/** {@inheritDoc} */
  @Override
  public void startDocument() throws SAXException {
    LOG.debug("Starting XML parsing");

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setType(XmlTokenTypes.DOCUMENT);
    token.setText(file.getName());

    // Node
    root = new DetailAST();
    root.initialize(token);

    currentNode = root;

    // Path = package
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setType(XmlTokenTypes.PATH);
    token.setText(file.getParent());
    DetailAST path = new DetailAST();
    path.initialize(token);
    root.addChild(path);
    DetailAST pathIdent = new DetailAST();
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setType(XmlTokenTypes.IDENT);
    token.setText(file.getParent());
    pathIdent.initialize(token);
    path.addChild(pathIdent);

    // Fake child to match Java grammar structure
    pathIdent = new DetailAST();
    pathIdent.initialize(token);
    path.addChild(pathIdent);

    // Name = Type
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setType(XmlTokenTypes.IDENT);
    token.setText(file.getName());
    DetailAST name = new DetailAST();
    name.initialize(token);
    root.addChild(name);
    DetailAST nameIdent = new DetailAST();
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setType(XmlTokenTypes.IDENT);
    token.setText(file.getName());
    nameIdent.initialize(token);
    name.addChild(nameIdent);
  }
  /** {@inheritDoc} */
  public void processingInstruction(String target, String data) throws SAXException {
    LOG.debug("Processing instruction : " + target);
    LOG.debug("  Args : " + data);

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(target);
    token.setType(XmlTokenTypes.PROCESSING_INSTRUCTION);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);
    child.setText(token.getText());

    // Target
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(target);
    token.setType(XmlTokenTypes.PROCESSING_TARGET);

    DetailAST targetAST = new DetailAST();
    targetAST.initialize(token);
    targetAST.setText(token.getText());
    child.addChild(targetAST);

    // Data
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(data);
    token.setType(XmlTokenTypes.PROCESSING_DATA);

    DetailAST dataAST = new DetailAST();
    dataAST.initialize(token);
    dataAST.setText(token.getText());
    child.addChild(dataAST);

    // Parent
    currentNode.addChild(child);
  }
  /** {@inheritDoc} */
  public void startPrefixMapping(String prefix, String URI) throws SAXException {
    LOG.debug("Prefix mapping : " + URI + ", chosen prefix : " + prefix);

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(prefix);
    token.setType(XmlTokenTypes.PREFIX_MAPPING);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);

    // Prefix
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(prefix);
    token.setType(XmlTokenTypes.IDENT);

    DetailAST prefixAST = new DetailAST();
    prefixAST.initialize(token);
    prefixAST.setText(token.getText());

    child.addChild(prefixAST);

    // URI
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(URI);
    token.setType(XmlTokenTypes.STRING_LITERAL);

    DetailAST uri = new DetailAST();
    uri.initialize(token);

    child.addChild(uri);

    // Parent
    currentNode.addChild(child);
  }
  /** {@inheritDoc} */
  public void skippedEntity(String text) throws SAXException {

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(text);
    token.setType(XmlTokenTypes.SKIPPED_ENTITY);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);
    child.setText(token.getText());

    // Parent
    currentNode.addChild(child);
  }
  /** {@inheritDoc} */
  public void ignorableWhitespace(char[] ch, int start, int end) throws SAXException {

    String value = new String(ch, start, end);

    LOG.debug("ignorable whitespace : ..." + value + "...");

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber() + start);
    token.setText(value);
    token.setType(XmlTokenTypes.WHITE_SPACE);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);
    child.setText(token.getText());

    // Parent
    currentNode.addChild(child);
  }
  /** {@inheritDoc} */
  public void characters(char[] ch, int start, int end) throws SAXException {

    String value = new String(ch, start, end);

    LOG.debug("#PCDATA : " + value);

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber() + start);
    token.setText(value);
    token.setType(XmlTokenTypes.PCDATA);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);
    child.setText(token.getText());

    // Parent
    currentNode.addChild(child);
  }
  /** {@inheritDoc} */
  public void startElement(
      String nameSpaceURI, String localName, String rawName, Attributes attributs)
      throws SAXException {
    LOG.debug("Opening element : " + localName);

    int col = locator.getColumnNumber();

    // XmlToken
    XmlToken token = new XmlToken();
    token.setLine(locator.getLineNumber());
    token.setColumn(locator.getColumnNumber());
    token.setText(rawName);
    token.setType(XmlTokenTypes.ELEMENT);

    // Node
    DetailAST child = new DetailAST();
    child.initialize(token);

    // Parent
    currentNode.addChild(child);

    // Ident
    DetailAST ident = new DetailAST();
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    col++;
    token.setColumn(col);
    token.setText(localName);
    token.setType(XmlTokenTypes.IDENT);
    ident.initialize(token);
    child.addChild(ident);

    // Attributes
    LOG.debug("  Attributes : ");
    DetailAST attrs = new DetailAST();
    token = new XmlToken();
    token.setLine(locator.getLineNumber());
    col += rawName.length() + 1;
    token.setColumn(col);
    token.setText(rawName);
    token.setType(XmlTokenTypes.ATTRIBUTES);
    attrs.initialize(token);
    child.addChild(attrs);

    for (int index = 0; index < attributs.getLength(); index++) {

      // Attribut
      DetailAST attr = new DetailAST();
      token = new XmlToken();
      token.setLine(locator.getLineNumber());
      token.setColumn(index);
      token.setText(rawName);
      token.setType(XmlTokenTypes.ATTRIBUTE);
      attr.initialize(token);
      attrs.addChild(attr);
      LOG.debug("     - " + attributs.getLocalName(index) + " = " + attributs.getValue(index));

      // Ident
      ident = new DetailAST();
      token = new XmlToken();
      token.setLine(locator.getLineNumber());
      token.setColumn(index);
      token.setText(attributs.getLocalName(index));
      token.setType(XmlTokenTypes.IDENT);
      ident.initialize(token);
      attr.addChild(ident);

      // Value
      DetailAST value = new DetailAST();
      token = new XmlToken();
      token.setLine(locator.getLineNumber());
      token.setColumn(index + attributs.getLocalName(index).length() + 1);
      token.setText(attributs.getValue(index));
      token.setType(XmlTokenTypes.STRING_LITERAL);
      value.initialize(token);
      attr.addChild(value);

      // Go forward
      col += attributs.getLocalName(index).length() + attributs.getValue(index).length() + 2;
    }

    // This node is now he current node
    currentNode = child;
  }