import java.io.IOException;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

/**
 * This class provides static methods to analyse and display a DOM 
 * structure of an XML Document
 * @author Udo Altmann
 * @version 1.0
 * 
 */

public class analyse {

	/**
	 * @param args File to be analysed
	 * @throws IOException
	 * @throws SAXException
	 */
	public static void main(String args[]) throws IOException, SAXException {
		DOMParser dp = new DOMParser();
		//
		// Es gibt keine DOM-Methode zum Anlegen von Documenten
		// 
		dp.parse(args[0]);
		//
		// Die Verarbeitung startet mit dem Interface Document
		// 
		Document doc = dp.getDocument();
		//
		// Dokumente sind auch Knoten
		// 
		process(doc);
	}

	/**
	 * @param nd Node to be analysed. Child nodes are processed recursively
	 */
	public static void process(Node nd) {
		System.out.println(
			"Node type:\t"
				+ nd.getNodeType()
				+ " - "
				+ nodeTypeToString(nd.getNodeType()));
		System.out.println("\tname:\t" + nd.getNodeName());
		System.out.println("\tvalue:\t\"" + nd.getNodeValue() + "\"");
		if (nd.getParentNode() != null) {
			System.out.println(
				"\tparent:\t"
					+ nodeTypeToString(nd.getParentNode().getNodeType())
					+ "\t"
					+ nd.getParentNode().getNodeName());
		} else {
			System.out.println("\tno parent\t");
		}
		System.out.println("\tspecific details:\t");
		//nd.
		switch (nd.getNodeType()) {
			case Node.DOCUMENT_NODE :
				Document doc = (Document) nd;
				System.out.println(
					"\t\tDocumentElement: "
						+ doc.getDocumentElement().getNodeName());
				break;
			case Node.ELEMENT_NODE :
				Element el = (Element) nd;
				//
				// hasAttributes ist nicht in DOM-Level 1!
				//
				if (el.hasAttributes()) {
					System.out.println("\t\tgetTagName: " + el.getTagName());
					System.out.println("\t\tAttribute:");
					NamedNodeMap nnm = el.getAttributes();
					int i;
					for (i = 0; i < nnm.getLength(); i++) {
						process(nnm.item(i));
					}
				} else {
					System.out.println("\t\tno attributes!");
				}
				break;
			case Node.ATTRIBUTE_NODE :
				Attr at = (Attr) nd;
				System.out.println("\t\tgetName:" + at.getName());
				System.out.println("\t\tspecified: " + at.getSpecified());
				System.out.println("\t\tgetValue: " + at.getValue());
				break;
			case Node.COMMENT_NODE :
				Comment cm = (Comment) nd;
				System.out.println("\t\tgetData: " + cm.getData());
				System.out.println("\t\tgetLength: " + cm.getLength());
				break;
			case Node.TEXT_NODE :
				Text tn = (Text) nd;
				System.out.println("\t\tgetData: " + tn.getData());
				System.out.println("\t\tgetLength: " + tn.getLength());
				break;
			case Node.CDATA_SECTION_NODE :
				Text cs = (Text) nd;
				System.out.println("\t\tgetData: " + cs.getData());
				System.out.println("\t\tgetLength: " + cs.getLength());
				break;
			case Node.DOCUMENT_TYPE_NODE :
				int i;
				DocumentType dt = (DocumentType) nd;
				System.out.println("\t\tgetName: " + dt.getName());
				System.out.println("\t\tgetPublicId: " + dt.getPublicId());
				System.out.println("\t\tgetSytemId: " + dt.getSystemId());
				//
				// DOM 2 und parserabhängig
				//
				System.out.println(
					"\t\tgetInternalSubset: " + dt.getInternalSubset());
				NamedNodeMap nnm = dt.getEntities();
				if (nnm.getLength() <= 0) {
					System.out.println("\t\tno Entities");
				} else {
					for (i = 0; i < nnm.getLength(); i++) {
						process(nnm.item(i));
					}
				}
				nnm = dt.getNotations();
				if (nnm.getLength() <= 0) {
					System.out.println("\t\tno Notations");
				} else {
					for (i = 0; i < nnm.getLength(); i++) {
						process(nnm.item(i));
					}
				}
				break;
			case Node.NOTATION_NODE :
				Notation no = (Notation) nd;
				System.out.println("\t\tgetPublicId: " + no.getPublicId());
				System.out.println("\t\tgetSytemId: " + no.getSystemId());
				break;
			case Node.ENTITY_NODE :
				Entity en = (Entity) nd;
				System.out.println(
					"\t\tgetNotationName: " + en.getNotationName());
				System.out.println("\t\tgetPublicId: " + en.getPublicId());
				System.out.println("\t\tgetSytemId: " + en.getSystemId());
				break;
			case Node.PROCESSING_INSTRUCTION_NODE :
				ProcessingInstruction pe = (ProcessingInstruction) nd;
				System.out.println("\t\tgetTarget: " + pe.getTarget());
				System.out.println("\t\tgetData: " + pe.getData());
				break;
				// 
				// Für die folgenden Knotentyp gibt es keine speziellen Attribute/Methoden
				// 
			case Node.ENTITY_REFERENCE_NODE :
				//
				// EntityRefences werden evtl. nicht erkannt, wenn sie beim Parsen ersetzt werden
				// 
				// EntityReference er = (EntityReference) nd;
				// break;
			case Node.DOCUMENT_FRAGMENT_NODE :
				// DocumentFragment df = (DocumentFragment) nd; 
				// break;
			default :
				System.out.println("\t\tno details!");
		}
		if (nd.hasChildNodes()) {
			NodeList nl = nd.getChildNodes();
			int i;
			for (i = 0; i < nl.getLength(); i++) {
				process(nl.item(i));
			}
		}
	}

	/**
	 * Static method to convert Nodetypes to Strings
	 * @param s Type as short
	 * @return Type as String
	 */
	public static String nodeTypeToString(short s) {

		switch (s) {
			case Node.ATTRIBUTE_NODE :
				return "ATTRIBUTE_NODE";
			case Node.CDATA_SECTION_NODE :
				return "CDATA_SECTION_NODE";
			case Node.COMMENT_NODE :
				return "COMMENT_NODE";
			case Node.DOCUMENT_FRAGMENT_NODE :
				return "DOCUMENT_FRAGMENT_NODE";
			case Node.DOCUMENT_NODE :
				return "DOCUMENT_NODE";
			case Node.DOCUMENT_TYPE_NODE :
				return "DOCUMENT_TYPE_NODE";
			case Node.ELEMENT_NODE :
				return "ELEMENT_NODE";
			case Node.ENTITY_NODE :
				return "ENTITY_NODE";
			case Node.ENTITY_REFERENCE_NODE :
				return "ENTITY_REFERENCE_NODE";
			case Node.NOTATION_NODE :
				return "NOTATION_NODE";
			case Node.PROCESSING_INSTRUCTION_NODE :
				return "PROCESSING_INSTRUCTION_NODE";
			case Node.TEXT_NODE :
				return "TEXT_NODE";
			default :

				return null;
		}
	}


}