首页 > 解决方案 > Java XPath 处理器忽略命名空间上下文

问题描述

我正在尝试使用默认命名空间查询 XML 文档。我想在默认命名空间中获取节点的文本内容。

我相信我已经正确设置了。但是,我没有得到结果。我创建了一个 NamespaceContext 并将它传递给 XPath 处理器。从输出看,似乎没有引用上下文。因此,命名空间感知处理器不会在默认命名空间中找到节点。

当我尝试使用忽略命名空间的非常丑陋的 XPath 表达式进行查询时,我得到了预期的结果。

我已经包含了一个示例程序,正在查询的 XML 文件和输出。

谢谢。

该程序

import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.xml.sax.InputSource;

public class Example {

    public static void main(String[] args) throws IOException, XPathExpressionException {
        List<String> pomLines = Files.readAllLines(Paths.get("example.xml"));
        String document = String.join(System.lineSeparator(), pomLines);

        // XPathFactory xpathFactory = new net.sf.saxon.xpath.XPathFactoryImpl();
        XPathFactory xpathFactory = XPathFactory.newInstance();
        XPath xpathNS = xpathFactory.newXPath();
        xpathNS.setNamespaceContext(new NamespaceContext() {

            @Override
            public String getNamespaceURI(String prefix) {
                System.out.println("*** getNamespaceURI, prefix='" + prefix + "'");
                if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
                    System.out.println("*** returning a URL");
                    return "http://maven.apache.org/POM/4.0.0";
                }

                System.out.println("*** returning NULL_NS_URI");
                return XMLConstants.NULL_NS_URI;
            }

            @Override
            public String getPrefix(String namespaceURI) {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public Iterator<String> getPrefixes(String namespaceURI) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        });

        XPathExpression xpathExpressionNS = xpathNS.compile("/project/name/text()");
        String artifactIdNS = xpathExpressionNS
                .evaluate(new InputSource(new StringReader(document)));
        System.out.println("artifactIdNS='" + artifactIdNS + "'");
        XPath xpath = xpathFactory.newXPath();
        XPathExpression xpathExpression = xpath
                .compile("/*[local-name()='project']/*[local-name()='name']/text()");
        String artifactId = xpathExpression.evaluate(new InputSource(new StringReader(document)));
        System.out.println("artifactId='" + artifactId + "'");

    }
}

XML 文档

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>parent-test-repo</artifactId>
        <version>0.1.0</version>
    </parent>

    <artifactId>test-repo-1</artifactId>
    <name>test-repo-1</name>
    <version>1.1.0</version>
</project>

实际输出

~/temp% java Example
artifactIdNS=''
artifactId='test-repo-1'

我会期待一些带有***.

标签: javaxmlxpath

解决方案


如果 xpath 表达式不包含前缀,则 xpath 编译器不会调用名称空间解析器。此 xpath 将显示预期消息但不显示预期值

XPathExpression xpathExpressionNS = xpathNS.compile("/:project/name/text()");

结果:

*** getNamespaceURI, prefix=''
*** returning a URL
artifactIdNS=''

映射默认命名空间的虚拟前缀可用于查询 xml

            if ("mvn".equals(prefix)) {
                System.out.println("*** returning a URL");
                return "http://maven.apache.org/POM/4.0.0";
            }
// code

XPathExpression xpathExpressionNS = xpathNS.compile("/mvn:project/mvn:name/text()");

结果:

*** getNamespaceURI, prefix='mvn'
*** returning a URL
*** getNamespaceURI, prefix='mvn'
*** returning a URL
artifactIdNS='SO-68977962'
artifactId='SO-68977962'

推荐阅读