// Copyright (c) Keith D Gregory, all rights reserved
package com.kdgregory.example.xml.xpath;

import java.io.StringReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;

import org.xml.sax.InputSource;


/**
 *  An example XPath against a namespaced document, using an explicit (and complete)
 *  implementation of <code>javax.xml.namespace.NamespaceContext</code>.
 */
public class NamespacedXPathExample
{
    public static void main(String[] argv) throws Exception
    {
        String xml = "<foo xmlns='http://www.example.com/example'>"
                   + "    <bar name='argle'>"
                   +          "Argle"
                   + "    </bar>"
                   + "    <bar name='bargle'>"
                   +          "Bargle"
                   + "        <baz>Baz</baz>"
                   + "    </bar>"
                   + "</foo>";

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document dom = db.parse(new InputSource(new StringReader(xml)));

        XPath xpath = XPathFactory.newInstance().newXPath();
        xpath.setNamespaceContext(new NamespaceContext()
        {
            private String _prefix = "ns";
            private String _namespaceUri = "http://www.example.com/example";
            private List<String> _prefixes = Arrays.asList(_prefix);


            @Override
            @SuppressWarnings("rawtypes")
            public Iterator getPrefixes(String uri)
            {
                if (uri == null)
                    throw new IllegalArgumentException("nsURI may not be null");
                else if (_namespaceUri.equals(uri))
                    return _prefixes.iterator();
                else if (XMLConstants.XML_NS_URI.equals(uri))
                    return Arrays.asList(XMLConstants.XML_NS_PREFIX).iterator();
                else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri))
                    return Arrays.asList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
                else
                    return Collections.emptyList().iterator();
            }


            @Override
            public String getPrefix(String uri)
            {
                if (uri == null)
                    throw new IllegalArgumentException("nsURI may not be null");
                else if (_namespaceUri.equals(uri))
                    return _prefix;
                else if (XMLConstants.XML_NS_URI.equals(uri))
                    return XMLConstants.XML_NS_PREFIX;
                else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri))
                    return XMLConstants.XMLNS_ATTRIBUTE;
                else
                    return null;
            }


            @Override
            public String getNamespaceURI(String prefix)
            {
                if (prefix == null)
                    throw new IllegalArgumentException("prefix may not be null");
                else if (_prefix.equals(prefix))
                    return _namespaceUri;
                else if (XMLConstants.XML_NS_PREFIX.equals(prefix))
                    return XMLConstants.XML_NS_URI;
                else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
                    return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
                else
                    return null;
            }
        });

        String result = xpath.evaluate("/ns:foo/ns:bar/ns:baz", dom);
        System.out.println("selected content: \"" + result + "\"");
    }
}
