如何在dom4j的selectNodes xpath表达式中使用默认命名空间?

3

我正在使用Dom4J解析一些Maven Pom文件。当我使用没有默认命名空间的Pom文件时,一切都正常工作。例如:

Document pom = DocumentHelper.parseText(
                 "<project>" +
                 "   <groupId>xx.gov.xxx.sistema.xxx</groupId>" + 
                 "   <artifactId>sis-teste</artifactId>" + 
                 "   <packaging>war</packaging>" + 
                 "</project>");
//below works fine
String groupId = pom.selectSingleNode("/project/groupId").getText()

但是如果我的Pom文件定义了一个默认命名空间,它就会停止工作:
Document pom = DocumentHelper.parseText(
                 "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">" +
                 "   <groupId>xx.gov.xxx.sistema.xxx</groupId>" + 
                 "   <artifactId>sis-teste</artifactId>" + 
                 "   <packaging>war</packaging>" + 
                 "</project>");
//NullPointerException!!!!!!!!!!!!!!!!!!!!
String groupId = pom.selectSingleNode("/project/groupId").getText()

奇怪的是pom.selectSingleNode("/project")可以正常工作。

我该如何使我的xpath查询与默认命名空间一起工作?我想仅查询"/project/groupId"并获取groupId节点。


如果您不希望更改查询,您将需要深入XPath中的命名空间兔子洞穴。我建议您阅读这个网址:http://www.edankert.com/defaultnamespaces.html - undefined
2个回答

4

就像这样:

    Document pom = DocumentHelper.parseText(
            "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">" +
            "   <groupId>xx.gov.xxx.sistema.xxx</groupId>" +
            "   <artifactId>sis-teste</artifactId>" +
            "   <packaging>war</packaging>" +
            "</project>");
    Map<String, String> nsContext = new HashMap<>();
    nsContext.put("p", "http://maven.apache.org/POM/4.0.0");
    XPath xp = pom.createXPath("/p:project/p:groupId");
    xp.setNamespaceURIs(nsContext);
    String groupId = xp.selectSingleNode(pom).getText();
    System.out.println(groupId);

更新

仔细查看DOM4J代码后,发现这是可能的,只要您能容忍设置全局命名空间URI映射:

    Map<String, String> nsContext = new HashMap<>();
    nsContext.put("p", "http://maven.apache.org/POM/4.0.0");
    DocumentFactory.getInstance().setXPathNamespaceURIs(nsContext);

    Document pom = DocumentHelper.parseText(
            "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">" +
            "   <groupId>xx.gov.xxx.sistema.xxx</groupId>" +
            "   <artifactId>sis-teste</artifactId>" +
            "   <packaging>war</packaging>" +
            "</project>");
    String groupId = pom.selectSingleNode("/p:project/p:groupId").getText();
    System.out.println(groupId);

一个更本地化的解决方案是使用SAXReader并将其配置为专用的DocumentFactory,而不是全局的。


使用带有命名空间的xpath是正确的答案,但它强制我更改所有的xpath表达式和api调用。在直接在文档对象中进行选择时似乎没有选择命名空间的方法。 - undefined

0
我的临时解决方案就是在创建Dom对象之前删除pom文件的命名空间。虽然不太美观,但它能正常工作,生活还得继续。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接