import org.apache.xerces.parsers.*;
import org.w3c.dom.*;

public class BasicDOMExample1 {

  public static void main(String[] args) {
    
    if (args.length > 0) {
      String filename = args[0];
      BasicDOMExample1 exampleDOM = new BasicDOMExample1(filename);
    }  
  }

  public BasicDOMExample1(String filename) {
    try {
      // Parse in XML file, and construct a document
      DOMParser parser = new DOMParser();

      parser.parse(filename);
      Document document = parser.getDocument();

      DOMImplementation domImpl = document.getImplementation();
      boolean levelCoreSupport = domImpl.hasFeature("CORE", "1.0");
      if (levelCoreSupport)
        System.out.println("DOM implementation supports DOM Level 1.0 Core");
      else
        System.out.println("DOM implementation doesn't support DOM Level 1.0 Core");

      Element documentElement = document.getDocumentElement();
      System.out.println("Document node name: " + documentElement.getTagName());

      attributeInformation(documentElement);

      documentElement.setAttribute("TESTATTRIBUTE", "TESTING");

      if (documentElement.hasAttribute("TESTATTRIBUTE"))
        System.out.println("Attribute has been successfully added");

      Attr testAttribute = documentElement.getAttributeNode("TESTATTRIBUTE");
      System.out.println("Element: " + testAttribute.getOwnerElement() + 
                         " has attribute " + testAttribute.getName() + 
                         " with the value " + testAttribute.getValue());

      System.out.println("New attribute, TESTATTRIBUTE has value: " + 
                          documentElement.getAttribute("TESTATTRIBUTE"));

      Element testElement = document.createElement("TESTELEMENT");
      testElement.setAttribute("TESTATTRIBUTE", "In TESTELEMENT");

      documentElement.appendChild(testElement);

      Text testTextNode = document.createTextNode("Test Text");
      testElement.appendChild(testTextNode);

      NodeList testTags = document.getElementsByTagName("TESTELEMENT"); 
      System.out.println("TESTELEMENT tags found: " + testTags.getLength());

      nodeInformation(document);

    } catch (Exception e) {
      e.printStackTrace(System.err);
    }
  }

  public void attributeInformation(Element element) {
    NamedNodeMap attributes = element.getAttributes();

    for (int i = 0; i < attributes.getLength(); i++) {
      Attr attribute = (Attr)attributes.item(i);
      System.out.println("Element: " + attribute.getOwnerElement() + 
                         " has attribute " + attribute.getName() + 
                         " with the value " + attribute.getValue());
    }
  }

  public void nodeInformation(Node node) {
    // Is there anything to do?
    if (node == null) {
      return;
    }

    // Output the NodeType and values
    int type = node.getNodeType();
    switch (type) {
      case Node.ATTRIBUTE_NODE: {
        System.out.println("Attribute node: " + ((Attr)node).getName() + 
                           " has value: " + ((Attr)node).getValue());
        break;
      }
      case Node.CDATA_SECTION_NODE: {
        System.out.println("CDATA node: " + node.getNodeName() + 
                           " has value: " + node.getNodeValue());
        break;
      }
      case Node.COMMENT_NODE: {
        System.out.println("Comment node: " + node.getNodeName() + 
                           " has value: " + node.getNodeValue());
        break;
      }
      case Node.DOCUMENT_FRAGMENT_NODE: {
        System.out.println("Document fragment node: " + node.getNodeName());
        outputChildNodes(node);
        break;
      }
      case Node.DOCUMENT_NODE: {
        System.out.println("Document node: " + node.getNodeName());
        outputChildNodes(node);
        break;
      }
      case Node.DOCUMENT_TYPE_NODE: {
        System.out.println("Document type node: " + node.getNodeName());
        break;
      }
      case Node.ELEMENT_NODE: {
        System.out.println("");
        System.out.println("Element node: " + ((Element)node).getTagName());
        outputAttributes(node);
        outputChildNodes(node);
        break;
      }
      case Node.ENTITY_NODE: {
        System.out.println("Entity node: " + node.getNodeName());
        break;
      }
      case Node.ENTITY_REFERENCE_NODE: {
        System.out.println("Entity reference node: " + node.getNodeName());
        break;
      }
      case Node.NOTATION_NODE: {
        System.out.println("Notation node: " + node.getNodeName());
        break;
      }
      case Node.PROCESSING_INSTRUCTION_NODE: {
        System.out.println("Processing instruction node: " + node.getNodeName() + 
                           " has value: " + node.getNodeValue());
        break;
      }
      case Node.TEXT_NODE: {
        System.out.println("Text node: " + node.getNodeName() + 
                           " has value: " + node.getNodeValue());
        break;
      }
    }
  }

  public void outputChildNodes(Node node) {
    // Output all the child nodes from this node recursively, using a NodeList
    NodeList children = node.getChildNodes();

    for (int i = 0; i < children.getLength(); i++) {
      Node child = children.item(i);
      nodeInformation(child);
    }
  }

  public void outputAttributes(Node node) {
    // Output all the attributes from this node recursively, using a NamedNodeMap
    NamedNodeMap attributes = node.getAttributes();

    for (int i = 0; i < attributes.getLength(); i++) {
      Attr attribute = (Attr)attributes.item(i);
      nodeInformation(attribute);
    }
  }
}
