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

Java 如何在具有默认命名空间的xml文档上使用XPath,java,xml,xpath,Java,Xml,Xpath,我想操作具有默认名称空间但没有前缀的xml文档。有没有一种方法可以像没有命名空间一样使用没有命名空间uri的xpath? 我相信,如果我们将documentBuilderFactory的namespaceAware属性设置为false,这应该是可能的。但就我而言,它不起作用。 是我的理解不正确还是我在代码中犯了错误 这是我的密码: DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); d

我想操作具有默认名称空间但没有前缀的xml文档。有没有一种方法可以像没有命名空间一样使用没有命名空间uri的xpath?
我相信,如果我们将documentBuilderFactory的namespaceAware属性设置为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>

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

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

下面是代码的外观:

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

    }

}
注: 我还使用了建议的正确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();
        }
    }

}
正确,所附代码正确。
问题出在埃利斯的某个地方。我在EclipseIDE中通过ApplicationLauncher运行所有测试,但什么都不起作用。然后我发现Eclipse项目是所有悲伤的原因。我从命令提示符运行我的类,它工作了。创建了一个新的eclipse项目并在那里粘贴了相同的代码,它也在那里工作。
感谢大家的时间和努力。

我已经编写了一个简单的
namespacecoxt
实现(),这可能会有所帮助。它将
映射
作为输入,其中
是前缀,
是名称空间

它遵循规范化,您可以看到它在中是如何工作的

Map mappings=newhashmap();
mappings.put(“foo”http://foo");
mappings.put(“foo2”http://foo");
mappings.put(“bar”http://bar");
上下文=新的SimpleNamespaceContext(映射);
context.getNamespaceURI(“foo”);//"http://foo"
context.getPrefix(“http://foo");   // “foo”或“foo2”
context.getPrefixes(“http://foo"); // [“foo”,“foo2”]

请注意,它依赖于

,因此我将不得不转到名称空间场景。好主意,但如果我这么做的话,我会下地狱的。我有大量的代码目前正在使用xpath处理没有名称空间的xml。为了验证(通过IDE和编程)目的,我不得不添加默认名称空间。有什么办法一箭双雕吗?我的意思是,我可能不必编辑所有的xpath表达式,同时可以在IDE中以编程方式验证文档?我想删除名称空间。在这种情况下,我将不会面临xpath问题,对于程序验证,我可以在运行时添加名称空间。也许,我只需要在验证之前解析文档。这是可以接受的,但在这样做之后,我看不到任何方法可以通过IDE验证我的xml文档。还有其他想法吗?将XPath更改为Dennis建议的值将使原始代码正常工作。不使用名称空间方法。哦,真的吗?那么肯定还有其他错误,因为这段代码在我的机器上不起作用。你能帮我找到吗?我添加了一个对我有效的版本,它使用了一个不支持名称空间的DocumentBuilderFactory。这看起来和XML名称空间、JDOM和XPath的问题一样
Map<String, String> mappings = new HashMap<>();
mappings.put("foo", "http://foo");
mappings.put("foo2", "http://foo");
mappings.put("bar", "http://bar");

context = new SimpleNamespaceContext(mappings);

context.getNamespaceURI("foo");    // "http://foo"
context.getPrefix("http://foo");   // "foo" or "foo2"
context.getPrefixes("http://foo"); // ["foo", "foo2"]