package com.alethis.xml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.*;

public class ParseUsingDOM {

    private final static String INPUT_FILE = "c:\\project\\xml\\in.xml";
    
    public static void main(String[] args) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = factory.newDocumentBuilder();
            Node document = parser.parse(INPUT_FILE);
            
            DocumentDisplayer displayer = new DocumentDisplayer();
            displayer.display(document);
            System.out.println("DONE");
        }
        catch (SAXException se) {
            System.out.println("SAX exception: " + se.getMessage());
        }
        catch (IOException ioe) {
            System.out.println("IO exception: " + ioe.getMessage());
        }
        catch (FactoryConfigurationError fce) {
            System.out.println("Factory configuration error: " + fce.getMessage());
        }
        catch (ParserConfigurationException pce) {
            System.out.println("Parser configuration exception: " + pce.getMessage());
        }
        /*
         * Alternatives: instantiate one of the following, and then call parse()
         *  org.apache.xerces.parsers.DOMParser
         *  org.apache.crimson.jaxp.DocumentBuilderImpl
         *  oracle.xml.parser.v2.DOMParser
         *  gnu.xml.xml.dom.JAXPFactory$JAXPBuilder
         *
         * Or do System.setProperty("javax.xml.parser.DocumentBuilderFactory", <factory>);
         * where the factory is:
         *  org.apache.xerces.jaxp.DocumentBuilderFactory
         *  (not clear what to use for the other products)
         */
    }
}

class DocumentDisplayer {
    
    public void display(Node node) {
        displayNode(node);
        if (node.hasChildNodes()) {
            NodeList children = node.getChildNodes();
            for (int i = 0; i < children.getLength(); i++) {
                display(children.item(i));
            }
        }
    }
    
    private void displayNode(Node node) { 
        String name      = node.getNodeName();        // never null
        String type      = getType(node);             // never null
        String localName = node.getLocalName();
        String uri       = node.getNamespaceURI();
        String prefix    = node.getPrefix();
        String value     = node.getNodeValue();
        
        System.out.println("Node:         " + name);
        System.out.println("  Type:       " + type);
        if (localName != null) {
            System.out.println("  Local name: " + localName);
        }
        if (uri != null) {
            System.out.println("  URI:        " + uri);
        }
        if (prefix != null) {
            System.out.println("  Prefix:     " + prefix);
        }
        if (value != null) {
            System.out.println("  Value:      " + value);
        }
        System.out.println("");
    }
    
    private String getType(Node node) {
        switch (node.getNodeType()) {
            case Node.DOCUMENT_NODE:                return "Document";
            case Node.DOCUMENT_TYPE_NODE:           return "Document Type";
            case Node.DOCUMENT_FRAGMENT_NODE:       return "Document Fragment";
            case Node.ELEMENT_NODE:                 return "Element";
            case Node.ATTRIBUTE_NODE:               return "Attribute";
            case Node.TEXT_NODE:                    return "Text";
            case Node.CDATA_SECTION_NODE:           return "CDATA Section";
            case Node.ENTITY_NODE:                  return "Entity";
            case Node.ENTITY_REFERENCE_NODE:        return "Entity Reference";
            case Node.COMMENT_NODE:                 return "Comment";
            case Node.PROCESSING_INSTRUCTION_NODE:  return "Processing Instruction";
            case Node.NOTATION_NODE:                return "Notation";
            default:                                return "Unknown";
        }
    }
}