如何在具有默认命名空间的 xml 文档上使用 XPath

2022-09-02 21:24:05

我想操作具有默认命名空间但没有前缀的xml doc。有没有办法在没有命名空间uri的情况下使用xpath,就像没有命名空间一样?
我相信如果我们将 namespaceAware property of documentBuilderFactory 设置为 false,这应该是可能的。但在我的情况下,它不起作用。
是我的理解不正确,还是我在代码中犯了一些错误?

这是我的代码:

    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();
    }

这是我的xml:

<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.mydomain.com/schema">
  <author>
    <book title="t1"/>
    <book title="t2"/>
  </author>
</root>

答案 1

对使用默认命名空间(无前缀)的文档的 XPath 处理与对使用前缀的文档的 XPath 处理相同:

对于命名空间限定文档,可以在执行 XPath 时使用命名空间上下文。您需要在 XPath 中的片段前面加上前缀,以匹配 NamespaceContext。您使用的前缀不需要与文档中使用的前缀匹配。

以下是代码的外观:

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;
        }

    }

}

注意:我还使用了Dennis建议的更正后的XPath。

以下内容似乎也有效,并且更接近您的原始问题:

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();
        }
    }

}

答案 2

Blaise Doughan是对的,附加的代码是正确的。
问题是在某个地方。我通过 Eclipse IDE 中的应用程序启动器运行所有测试,但没有任何工作。然后我发现Eclipse项目是所有悲伤的原因。我从命令提示符运行我的类,它的工作原理。创建了一个新的eclipse项目并在那里粘贴了相同的代码,它在那里也起作用。谢谢大家的时间和精力。


推荐