
import java.io.IOException;
import java.io.File;
import java.io.FileReader;
import java.io.FileNotFoundException;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.Document; 
import org.w3c.dom.Node; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.DOMImplementation; 
import org.w3c.dom.DOMConfiguration; 
import org.w3c.dom.ls.DOMImplementationLS; 
import org.w3c.dom.ls.LSSerializer; 
import org.xml.sax.ErrorHandler;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import javax.xml.XMLConstants;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

/**
 * Die Klasse XPathGrep selektiert mit XPath Nodes aus XML-Dateien (arg[1..]).
 * Erster Parameter ist XPath expression.
 * JDK &gt;= 1.5
 */

public class XPathGrep {

    static void usage() {
        System.out.println("Usage: XPathGrep <xpath-expression> <xml-files ...>");
    }


    public static void main(String[] args) {
        if ( args.length < 2 ) {
           usage();
           return;
        }
        String xpath = args[0];
        System.out.println("expression = " + xpath);
        String[] files = new String[ args.length-1 ];
        System.arraycopy(args,1,files,0,files.length);
        select( xpath, files );
    }


    static void select(String xpath, String[] files) {
        DocumentBuilderFactory pfac = DocumentBuilderFactory.newInstance();
        DocumentBuilder parser = null;
        try {
            //pfac.setValidating(true);
            //pfac.setNamespaceAware(true); do not set for XPath
            //pfac.setXIncludeAware(true);
            //pfac.setExpandEntityReferences(false);
            parser = pfac.newDocumentBuilder();
            // parser.setErrorHandler( eh );
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
            return;
        }
        //Document result = parser.newDocument();

        DOMImplementation dimp = parser.getDOMImplementation();
        DOMImplementationLS dimpls = null;
        LSSerializer store = null;
        if ( dimp.hasFeature("LS","3.0") ) {
            dimpls = (DOMImplementationLS) dimp;
            store = dimpls.createLSSerializer();
            //System.out.println("store = " + store);
            DOMConfiguration conf = store.getDomConfig();
            conf.setParameter("xml-declaration",false);
            //Object y = conf.getParameter("xml-declaration");
            //System.out.println("y = " + y);
        }

        XPathFactory xfac = XPathFactory.newInstance();
        XPath xp = xfac.newXPath();
        XPathExpression expression = null;
        try {
            expression = xp.compile(xpath);
        } catch (XPathExpressionException e) {
            e.printStackTrace();
            return;
        }
        //System.out.println("expression = " + expression);

        boolean valid = true;
        File xmlFile;
        NodeList nl;
        StringBuffer res = new StringBuffer("\n");
        for ( int i = 0; i < files.length; i++ ) {
            xmlFile = new File( files[i] );
            res.append( select( expression, parser, xmlFile, store ) );
            /* does not work
            for ( int j = 0; j < nl.getLength(); j++ ) {
                Node n = nl.item(j);
                // result.adoptNode( n );
                System.out.println( n );
                Node x = result.importNode( n, true );
                System.out.println( x );
                System.out.println( result );
            }
            */
        }
        //System.out.println( store.writeToString(result) );
        System.out.println( res.toString() );
        return;

    }

    static String select(XPathExpression expression, 
                         DocumentBuilder parser, 
                         File file,
                         LSSerializer store) {
        Document document = null;
        System.out.println("file = " + file.getName());
        try {
            document = parser.parse( file );
        } catch (SAXException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

        //Node node = document.getDocumentElement();
        NodeList nl = null;
        try {
            nl = (NodeList)expression.evaluate(document,XPathConstants.NODESET);
            // nl = (NodeList)expression.evaluate(document,XPathConstants.STRING);
        } catch (XPathExpressionException e) {
            e.printStackTrace();
            return null;
        }
        //System.out.println("hits = " + nl.getLength() );
        StringBuffer nls = new StringBuffer();
        for ( int i = 0; i < nl.getLength(); i++ ) {
            Node n = nl.item(i);
            if ( n != null ) {
               //System.out.println(n.getTextContent());
               if ( store != null ) {
                  nls.append( store.writeToString(n) + "\n" );
               } else {
                  nls.append( n.getTextContent() + "\n" );
               }
            }
        }
        //System.out.println(nls.toString());
        return nls.toString();
    }

}