tags:

views:

91

answers:

3

I am trying to manipulate xsd schema as an xml document that should not be a problem, I believe. But facing troubles with XPath. Whatever XPath I try, it returns nothing. Tried it with or without namespaces but no success. Please help me understand what am I doing wrong?

My xml is:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.mydomain.com" xmlns="http://www.mydomain.com" elementFormDefault="qualified">

  <xs:complexType name="Label">
    <xs:choice maxOccurs="unbounded" minOccurs="0">
      <xs:element name="Listener"/>
    </xs:choice>
  </xs:complexType>

</xs:schema>

and application code is:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setValidating(false);
domFactory.setNamespaceAware(true);
domFactory.setIgnoringComments(true);
domFactory.setIgnoringElementContentWhitespace(true);

try {
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document dDoc = builder.parse("C:/Temp/test.xsd");

    // This part works
    Node rootNode = dDoc.getElementsByTagName("xs:schema").item(0);
    System.out.println(rootNode.getNodeName());

    // This part doesn't work
    XPath xPath1 = XPathFactory.newInstance().newXPath();
    NodeList nList1 = (NodeList) xPath1.evaluate("//xs:schema", dDoc, XPathConstants.NODESET);  
    System.out.println(nList1.item(0).getNodeName());

    // This part doesn't work
    XPath xPath2 = XPathFactory.newInstance().newXPath();
    NodeList nList2 = (NodeList) xPath2.evaluate("//xs:element", rootNode, XPathConstants.NODESET); 
    System.out.println(nList2.item(0).getNodeName());

}catch (Exception e){
    e.printStackTrace();
}
+4  A: 

Set a namespace context using XPath.setNamespaceContext(). This binds the xs prefix to the http://www.w3.org/2001/XMLSchema namespace.

Sjoerd
and then xPath1.evaluate("//schema",...) should do the trick?
willcodejavaforfood
@willcodejavaforfood: No. `//schema` means any `schema` element in the tree under no namespace. Should be `/xs:schema`
Alejandro
@Alejandro - OK that makes sense, thanks
willcodejavaforfood
+2  A: 

The reason is that you haven't specified what xs means. An xml parser must know the namespace url, xs is just an identifier.

You can demonstrate this yourself by using the following code:

XPath xPath = XPathFactory.newInstance().newXPath();

SimpleNamespaceContext nsContext = new SimpleNamespaceContext();
nsContext.addNamespace("t", "http://www.w3.org/2001/XMLSchema");
xPath.setNamespaceContext(nsContext);

xPath.evaluate("//t:schema", dDoc, XPathConstants.NODESET);

You can see that I now use the identifier t instead of xs but that doesn't matter as long as you use the same namespace url.

Ronald Wildenberg
You should `import org.custommonkey.xmlunit.SimpleNamespaceContext` first or something similar, because the JDK doesn't contain an implementation of `javax.xml.namespace.Namespace`.
Adam Schmideg
+1  A: 

Made changes to your code. It works:

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

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

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XPathtest {
    public static void main(String[] args) {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory
                .newInstance();
        domFactory.setValidating(false);
        domFactory.setNamespaceAware(true);
        domFactory.setIgnoringComments(true);
        domFactory.setIgnoringElementContentWhitespace(true);

        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("C:/Temp/test.xsd");

            // This part works
            Node rootNode = dDoc.getElementsByTagName("xs:schema").item(0);
            System.out.println(rootNode.getNodeName());

            // This part doesn't work
            XPath xPath1 = XPathFactory.newInstance().newXPath();

            NamespaceContext nsContext = new NamespaceContext() {

                @Override
                public String getNamespaceURI(String prefix) {
                    return "http://www.w3.org/2001/XMLSchema";
                }

                @Override
                public String getPrefix(String namespaceURI) {
                    return "xs";
                }

                @Override
                public Iterator getPrefixes(String namespaceURI) {
                    Set s = new HashSet();
                    s.add("xs");
                    return s.iterator();
                }

            };

            xPath1.setNamespaceContext((NamespaceContext) nsContext);

            NodeList nList1 = (NodeList) xPath1.evaluate("//xs:schema", dDoc,
                    XPathConstants.NODESET);
            System.out.println(nList1.item(0).getNodeName());

            // This part doesn't work
            // XPath xPath2 = XPathFactory.newInstance().newXPath();
            NodeList nList2 = (NodeList) xPath1.evaluate("//xs:element",
                    rootNode, XPathConstants.NODESET);
            System.out.println(nList2.item(0).getNodeName());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
YoK