Xpath - Java - 从XML中提取多个名称空间

时间:2014-01-16 08:57:42

标签: java xml xpath namespaces

我正在研究用Java编写的解析器。我可以从各个位置接收带有各种内容的XML提要。我需要从feed中提取所有名称空间,根据feed调用this或that。我在使用Java获取此功能时遇到了一些麻烦,我不确定问题出在哪里。

让我们考虑一下这个XML:

<?xml version="1.0"?>
        <?xml-stylesheet type='text/xsl' href='new.xsl'?>
<test xmlns:mynsone="http://www.ns.com/test" xmlns:demons="http://www.demons.com/test">
    <p xmlns:domain="http://www.toto.com/test">
        this is a test.
    </p>
</test>

为了测试我的xPath表达式(我相当新),我写了一个应用于该XML的.xsl脚本:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output
            method="html"
            encoding="ISO-8859-1"
            doctype-public="-//W3C//DTD XHTML//EN"
            doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531"
            indent="yes" />
    <xsl:template match="/">
        <xsl:for-each select="//namespace::*">
            <xsl:value-of select="." />
            <xsl:text> </xsl:text><br />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

这正确地为我提供了迭代节点时遇到的命名空间列表:

http://www.w3.org/XML/1998/namespace 
http://www.demons.com/test 
http://www.ns.com/test 
http://www.w3.org/XML/1998/namespace 
http://www.demons.com/test 
http://www.ns.com/test 
http://www.toto.com/test 

现在我回到Java:这是我使用的代码。

    InputStream file = url.openStream();
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder =  builderFactory.newDocumentBuilder();
    org.w3c.dom.Document xmlDocument = builder.parse(file);

    XPath xPath = XPathFactory.newInstance().newXPath();
    String expression = "//namespace::*";
    System.out.println(expression);

    NodeList nodelist = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);

    for (int k = 0; k < nodelist.getLength(); k++)
    {
        Node mynode = nodelist.item(k);
        System.out.println(mynode.toString());
    }  

以下是我获得的结果:

xmlns:mynsone="http://www.ns.com/test"
org.apache.xml.dtm.ref.dom2dtm.DOM2DTMdefaultNamespaceDeclarationNode@7dbb8ca4
xmlns:domain="http://www.toto.com/test"

因此,不会返回“demons”命名空间。问题是,如果我在一个节点上放置几个名称空间,则只返回1个Java,而在XSL脚本上则显示所有名称空间。

我希望自己能够清醒自己;我花了几天的时间在网页上浏览一些例子,我不知道我是否真的很接近但只是遗漏了一些东西,或者我的表情根本就不合适......

提前致谢。

好的,所以我最终使用xPath 2.0来完成它,使用saxon-HE 9.4:

public static boolean detectGeoRssNamespace(InputStream sourceFeed) {
    try {
        if (sourceFeed.markSupported()) {
            sourceFeed.reset();
        }

        String objectModel = NamespaceConstant.OBJECT_MODEL_SAXON;
        System.setProperty("javax.xml.xpath.XPathFactory:"+NamespaceConstant.OBJECT_MODEL_SAXON, "net.sf.saxon.xpath.XPathFactoryImpl");
        XPathFactory xpathFactory = XPathFactory.newInstance(objectModel);
        XPath xpath = xpathFactory.newXPath();

        InputSource is = new InputSource(sourceFeed);
        SAXSource ss = new SAXSource(is);
        NodeInfo doc = ((XPathEvaluator)xpath).setSource(ss);       

        String xpathExpressionStr = "distinct-values(//*[name()!=local-name()]/ concat('prefix=', substring-before(name(), ':'), '&uri=', namespace-uri()))";
        XPathExpression xpathExpression = xpath.compile(xpathExpressionStr);

        List nodelist = (List)xpathExpression.evaluate(doc, XPathConstants.NODESET);

         System.out.println("<output>");
         Iterator iter = nodelist.iterator();
         while ( iter.hasNext() ) {
             Object line = (Object)iter.next();
             System.out.println(line.toString());
         }
         System.out.println("</output>");

    } catch (XPathFactoryConfigurationException e) {
        e.printStackTrace();
    } catch (XPathException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();                

    }  

2 个答案:

答案 0 :(得分:0)

如果将此命名空间提取到不同的xml元素,该怎么办?

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output
            method="html"
            encoding="ISO-8859-1"
            doctype-public="-//W3C//DTD XHTML//EN"
            doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531"
            indent="yes" />
    <xsl:template match="/">
        <xsl:for-each select="//namespace::*">
          <namespace>
            <xsl:value-of select="." />
          </namespace>
            <xsl:text> </xsl:text><br />
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:0)

问题是使用xPath 2.0(包含在问题中的代码)解决的