【问题标题】:How to use default namespace in dom4j selectNotes xpath expressions?如何在 dom4j selectNotes xpath 表达式中使用默认命名空间?
【发布时间】:2018-02-09 21:14:13
【问题描述】:

我正在使用 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 xml-namespaces dom4j


【解决方案1】:

像这样:

    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 配置它,而不是全局的。

【讨论】:

  • 将 xpaths 与命名空间一起使用是正确的答案,但它迫使我更改所有 xpath 表达式和所有 api 调用。直接在 Document 对象中进行选择时,似乎无法选择命名空间。
【解决方案2】:

我的 hacky 解决方案只是在创建 Dom 对象之前删除 pom 文件的命名空间。不是很漂亮,但它工作正常,生活还在继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    相关资源
    最近更新 更多