How to use XPath on xml docs having default namespace

30,503

Solution 1

The XPath processing for a document that uses the default namespace (no prefix) is the same as the XPath processing for a document that uses prefixes:

For namespace qualified documents you can use a NamespaceContext when you execute the XPath. You will need to prefix the fragments in the XPath to match the NamespaceContext. The prefixes you use do not need to match the prefixes used in the document.

Here is how it looks with your code:

import java.util.Iterator;
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.NodeList;

public class Demo {

    public static void main(String[] args) {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true);
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("E:/test.xml");

            XPath xPath = XPathFactory.newInstance().newXPath();
            xPath.setNamespaceContext(new MyNamespaceContext());
            NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET);
            System.out.println(nl.getLength());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static class MyNamespaceContext implements NamespaceContext {

        public String getNamespaceURI(String prefix) {
            if("ns".equals(prefix)) {
                return "http://www.mydomain.com/schema";
            }
            return null;
        }

        public String getPrefix(String namespaceURI) {
            return null;
        }

        public Iterator getPrefixes(String namespaceURI) {
            return null;
        }

    }

}

Note: I also used the corrected XPath suggested by Dennis.

The following also appears to work, and is closer to your original question:

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.NodeList;

public class Demo {

    public static void main(String[] args) {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("E:/test.xml");

            XPath xPath = XPathFactory.newInstance().newXPath();
            NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET);
            System.out.println(nl.getLength());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Solution 2

Blaise Doughan is right, attached code is correct.
Problem was somewhere elese. I was running all my tests through Application launcher in Eclipse IDE and nothing was working. Then I discovered Eclipse project was cause of all grief. I ran my class from command prompt, it worked. Created a new eclipse project and pasted same code there, it worked there too. Thank you all guys for your time and efforts.

Share:
30,503
WSK
Author by

WSK

Updated on September 29, 2020

Comments

  • WSK
    WSK almost 4 years

    I want to manipulate xml doc having default namespace but no prefix. Is there a way to use xpath without namespace uri just as if there is no namespace?
    I believe it should be possible if we set namespaceAware property of documentBuilderFactory to false. But in my case it is not working.
    Is my understanding is incorrect or I am doing some mistake in code?

    Here is my code:

        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(false);
        try {
            DocumentBuilder builder = domFactory.newDocumentBuilder();
            Document dDoc = builder.parse("E:/test.xml");
    
            XPath xPath = XPathFactory.newInstance().newXPath();
            NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET);
            System.out.println(nl.getLength());
        } catch (Exception e) {
            e.printStackTrace();
        }
    

    Here is my xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <root xmlns="http://www.mydomain.com/schema">
      <author>
        <book title="t1"/>
        <book title="t2"/>
      </author>
    </root>
    
  • WSK
    WSK over 13 years
    So I will have to move to namespaced scenario. Well, a good idea but I will be in the hell in doing so. I have tons of code that is currently handling xml without namespace, through using xpath. I had to add default namespace for validation (by IDE and programmatically) purpose. Is there any way to kill two birds with one stone? I mean I may not have to edit all of the xpath expressions, and at the same time could get the document validated both in IDE and programmatically?
  • WSK
    WSK over 13 years
    I thought to remove namespace. In that case I will not face xpath issue and for programmatical validation I may add namespace at runtime. Perhaps, I will only have to parse my documents before validation. It could be acceptable but after doing so, I don’t see any way to validate my xml docs by the IDE. Any other idea?
  • bdoughan
    bdoughan over 13 years
    Changing your XPath to what Dennis suggested will get your original code to work. Without using the namespace approach.
  • WSK
    WSK over 13 years
    Oh really? then there must be some other error too as this code is not working on my machine. Can you please help me find that?
  • bdoughan
    bdoughan over 13 years
    I have added the version that works for me that uses a non-namespace-aware DocumentBuilderFactory.