package javacodebook.xml.processing.dom.search;

import org.w3c.dom.*;

/**
 * Diese Klasse bietet Unterstützung bei der Suche innerhalb eines
 * XML-Dokuments.  Sie bietet die Möglichkeit ein Dokument zu parsen
 * und anschließend Knoten anhand des XPath-Syntaxes zu extrahieren.
 *
 * @author Christoph Leinemann.
 */
public class DOMSearcher {

  private Document document = null;

  // dieses Objekt der Xalan-API implementiert die XPath Syntax
  private org.apache.xpath.XPathAPI xPathAPI = new org.apache.xpath.XPathAPI();

  private static final String USAGE =
      "\nBenutzerhinweis: javacodebook.xml.processing.dom.search.DOMSearcher " +
      "<uri> <xPath> \n\nwobei \n\n<uri>\n" +
      "die URI ist, von der das zu durchsuchende XML-Dokumente geholt werden soll und\n\n<xPath> \n" +
      "der XPath ausdruck ist, der adressiert werden soll";

  public DOMSearcher(){}

  /**
   * Dieser Konstruktor versucht sofort ein XML-Dokument von dem
   * über den Parameter übergebenen Ort zu parsen.
   *
   * @param docLocation
   * @throws Exception
   */
  public DOMSearcher(String docLocation) throws Exception {
    this.document = parse(docLocation);
  }
  /**
   * In der Main-Methode wird die Verwendung der DOMSender-Klasse demonstriert.
   * Als ersten Parameter muss der Ort eines XML-Dokuments übergeben werden. Als
   * zweiten Parameter muss ein XPath-Ausdruck übergeben werden.  Es werden dann
   * alle Knoten in dem XML-Dokument gesucht, die durch den XPath-Ausdruck adressiert
   * sind, und deren Knotenname und Knotenwert in die Standardausgabe geschrieben.
   *
   * @param args
   */
  public static void main(String[] args) {
    if (args.length != 2) {
      System.out.println(getUsage());
      System.exit(1);
    }

    try {
      // ein neues DOMSearcher-Objekt wird instanziiert.  Der Ort des Dokuments
      // das durchsucht werden soll wird an den Konstruktor übergeben.
      DOMSearcher dOMSearcher = new DOMSearcher(args[0]);

      // die Suche wird ausgeführt.
      NodeList nl = dOMSearcher.selectNodeList(args[1]);

      // mit der Ergebnismenge findet eine Dummyverarbeitung statt.
      System.out.println("Es wurde(n) " + nl.getLength() + " Knoten gefunden:");
      for (int i = 0; i < nl.getLength(); i++) {
        System.out.println("NodeName:  " + nl.item(i).getNodeName() +
                           "\tNodeValue:  " + nl.item(i).getNodeValue());
      }
    }
    catch (Exception e) {
      System.out.println("Suche fehlgeschlagen: " + e);
    }

  }

  /**
   * Diese Methode parst ein XML-Dokument mit Hilfe des
   * Xerces Parsers.
   *
   * @param documentLocation
   * @return org.w3c.dom.Document
   * @throws Exception
   */
  public Document parse(String documentLocation) throws Exception {

    // Ein DOMParser-Objekt wird instanziiert.
    org.apache.xerces.parsers.DOMParser parser =
        new org.apache.xerces.parsers.DOMParser();

    // Das Dokument, dass als Parameter übergeben
    // wurde, wird geparst.
    parser.parse(documentLocation);
    return parser.getDocument();
  }

  /**
   * Diese Methode liefert den ersten Knoten zurück, der den XPath
   * Ausdruck erfüllt.
   *
   * @param xPath
   * @return org.w3c.dom.Node
   * @throws Exception
   */
  public Node selectSingleNode(String xPath) throws Exception {
    if(document==null)throw new Exception("Bitte zunächst über die parse-Methode ein Dokument parsen");
    // das Xalan-XPathAPI-Objekt kapselt die XPath-Implementierung.
    // Als erster Parameter wird der Such-Kontext übergeben. In unserem Fall ist das
    // das komplette Dokument, also das Root-Element. Der 2. Parameter ist
    // der XPath-Ausdruck als String.
    return xPathAPI.selectSingleNode(document.getDocumentElement(), xPath);
  }

  /**
   * Diese Methode liefert eine Liste von Knoten, die den XPath-Ausdruck erfüllen,
   * zurück.
   *
   * @param xPath
   * @return org.w3c.dom.NodeList
   * @throws Exception
   */
  public NodeList selectNodeList(String xPath) throws Exception {
    if(document==null)throw new Exception("Bitte zunächst über die parse-Methode ein Dokument parsen");
    // siehe selectSingleNode-Methode.
    return xPathAPI.selectNodeList(document.getDocumentElement(), xPath);
  }

  public static String getUsage() {
    return USAGE;
  }
}