命令空间声明的XPath解析

时间:2011-08-11 03:51:57

标签: java xpath

我正在使用XPath来提取URL128 XML元素的值。即使我在下面的示例中只有一个,也可以有很多这些。当我在SearchResponse元素上包含xmlns ='http://c1.net.corbis.com/'时,我得到一个空的NodeList,但当我删除该命名空间元素时,它工作正常。是否有我缺少的配置?

String xmlData = "<SearchResponse xmlns='http://c1.net.corbis.com/'><searchResultDataXML><SearchResultData><SearchRequestUID Scope='Public' Type='Guid' Value='{cded773c-c4b7-4dd8-aaee-8e5b8b7a2475}'/><StartPosition Scope='Public' Type='Long' Value='1'/><EndPosition Scope='Public' Type='Long' Value='50'/><TotalHits Scope='Public' Type='Long' Value='323636'/></SearchResultData></searchResultDataXML><imagesXML><Images><Image><ImageUID Scope='Public' Type='Guid' Value='{a6f6d3e2-2c3f-4502-9741-eae2e1bb573a}'/><CorbisID Scope='Public' Type='String' Value='42-25763849'/><Title Scope='Public' Type='String' Value='Animals figurines'/><CreditLine Scope='Public' Type='String' Value='© Ocean/Corbis'/><IsRoyaltyFree Scope='Public' Type='Boolean' Value='True'/><AspectRatio Scope='Public' Type='String' Value='0.666667'/><URL128 Scope='Public' Type='String' Value='http://cachens.corbis.com/CorbisImage/thumb/25/76/38/25763849/42-25763849.jpg'/></Image></Images></imagesXML></SearchResponse>";
            InputSource source = new InputSource(new StringReader(xmlData));

            XPath xPath = XPathFactory.newInstance().newXPath();
            NodeList list = null;
            try {
                list = (NodeList) xPath.evaluate("//URL128/@Value", source, XPathConstants.NODESET);
            } catch (Exception ex) {
                System.out.println(ex.getMessage());
            }
            for (int i = 0; i < list.getLength(); i++) {
                System.out.println(list.item(i).getTextContent());
            }

3 个答案:

答案 0 :(得分:2)

嗯,长话短说,您需要为XPath提供NamespaceContext

final XPath xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
    @Override
    public Iterator<String> getPrefixes(final String namespaceURI) {
        return null;
    }
    @Override
    public String getPrefix(final String namespaceURI) {
        return null;
    }
    @Override
    public String getNamespaceURI(final String prefix) {
        return "http://c1.net.corbis.com/";
    }
});
final NodeList list = (NodeList) xPath.evaluate("//c:URL128/@Value", source, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); i++) {
    System.out.println(list.item(i).getTextContent());
}

似乎XPath要求我们在这种情况下实现的唯一方法是getNamespaceURI(String prefix)

请注意,“c:URL128”中的实际前缀在这种情况下并不重要 - 您可以轻松使用“:URL128”。当在XML中有多个名称空间时,区分它们变得很重要(如果元素相对较少,则使用Map或一系列if-then-else

如果您不能或不想对前缀进行硬编码,您可以自己从XML文档中提取它们,但这需要更多的代码......

有关详细信息,另请参阅this blog post

答案 1 :(得分:1)

对此有一个稍微简单的解决方案,它不涉及在代码中放置硬编码的URI引用...只需解析文档,并将namespace aware属性设置为false ...

String xmlData = "<SearchResponse xmlns='http://c1.net.corbis.com/'><searchResultDataXML><SearchResultData><SearchRequestUID Scope='Public' Type='Guid' Value='{cded773c-c4b7-4dd8-aaee-8e5b8b7a2475}'/><StartPosition Scope='Public' Type='Long' Value='1'/><EndPosition Scope='Public' Type='Long' Value='50'/><TotalHits Scope='Public' Type='Long' Value='323636'/></SearchResultData></searchResultDataXML><imagesXML><Images><Image><ImageUID Scope='Public' Type='Guid' Value='{a6f6d3e2-2c3f-4502-9741-eae2e1bb573a}'/><CorbisID Scope='Public' Type='String' Value='42-25763849'/><Title Scope='Public' Type='String' Value='Animals figurines'/><CreditLine Scope='Public' Type='String' Value='© Ocean/Corbis'/><IsRoyaltyFree Scope='Public' Type='Boolean' Value='True'/><AspectRatio Scope='Public' Type='String' Value='0.666667'/><URL128 Scope='Public' Type='String' Value='http://cachens.corbis.com/CorbisImage/thumb/25/76/38/25763849/42-25763849.jpg'/></Image></Images></imagesXML></SearchResponse>";
InputSource source = new InputSource(new StringReader(xmlData));

// create doc instance instead of passing source straight to XPath...
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false); // must be false
DocumentBuilder builder = factory.newDocumentBuilder();
final Document doc = builder.parse(source);

XPath xPath = XPathFactory.newInstance().newXPath();

// use doc instead
NodeList list = (NodeList) xPath.evaluate("//URL128/@Value", doc, 
        XPathConstants.NODESET);

for (int i = 0; i < list.getLength(); i++) {
    System.out.println(list.item(i).getTextContent());
}

答案 2 :(得分:0)

下面是两种实现AlistairIsreal概述的方法:

如果使用spring,则可以依赖org.springframework.util.xml.SimpleNamespaceContext接口。

InputSource source = new InputSource(new StringReader(unescaped));

            XPath xPath = XPathFactory.newInstance().newXPath();
            NodeList list = null;
            try
            {
                SimpleNamespaceContext nsCtx = new SimpleNamespaceContext();
                nsCtx.bindNamespaceUri("ns", "http://c1.net.corbis.com/");
                xPath.setNamespaceContext(nsCtx);
                list = (NodeList) xPath.evaluate("//ns:URL128/@Value", source, XPathConstants.NODESET);
            } catch (Exception ex)
            {
                System.out.println(ex.getMessage());
            }
            for (int i = 0; i < list.getLength(); i++)
            {
                System.out.println(list.item(i).getTextContent());
            }