如何在Java XPath查询中使用name()和/或node()?

时间:2014-08-29 14:53:12

标签: java xml xpath

我有一些大致如下的XML:

<project type="mankind">
    <suggestion>Build the enterprise</suggestion>
    <suggestion>Learn Esperanto</suggestion>
    <problem>Solve world hunger</suggestion>
    <discussion>Do Vulcans exist</discussion>
</project>

我想使用XPath来查找二级元素的名称(可能有我不知道的元素,并且使用Java)。这是我试过的代码:

public NodeList xpath2NodeList(Document doc, String xPathString) throws XPathExpressionException {
     XPath xpath = XPathFactory.newInstance().newXPath();
     MagicNamespaceContext nsc = new MagicNamespaceContext();
     xpath.setNamespaceContext(nsc);
     Object exprResult = xpath.evaluate(xPathString, doc, XPathConstants.NODESET);
     return (NodeList) exprResult;
}

我的XPath是/project/*/name()。我收到错误:

javax.xml.transform.TransformerException:未知节点类型:名称

/project/suggestion这样的查询按预期工作。我错过了什么?我想获得一个带有标签名称的列表。

2 个答案:

答案 0 :(得分:2)

  

Java6(不要问)。

我认为您的实现仅支持XPath 1.0。如果这是真的,只有以下方法可行:

"name(/project/*)"

原因是在XPath 1.0模型中,您不能使用函数(如name())作为路径表达式中的一个步骤。您的代码抛出异常,在这种情况下,处理器会错误您的函数name()以获取未知的节点测试(如comment())。但是使用路径表达式作为name()函数的参数没有任何问题。

不幸的是,如果一个只能处理单个节点作为参数的XPath 1.0函数被赋予一系列节点,则只使用第一个节点。因此,您可能只会获得第一个元素名称。

XPath 1.0的操作能力非常有限,通常解决此类问题的最简单方法是使用XPath作为查询语言的高级语言(在您的Java案例中)。或者换一种方式:编写一个XPath表达式来检索所有相关节点并迭代结果,返回元素名称,用Java表示。

使用XPath 2.0,您的初始查询会没问题。另请参阅this related question

答案 1 :(得分:1)

以下代码可能会回答您的原始问题。

    package com.example.xpath;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;

    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import javax.xml.xpath.XPath;
    import javax.xml.xpath.XPathConstants;
    import javax.xml.xpath.XPathExpression;
    import javax.xml.xpath.XPathExpressionException;
    import javax.xml.xpath.XPathFactory;

    import org.w3c.dom.Document;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.SAXException;

    public class XPathReader {

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

        public static void main(String[] args) {

            try {
                FileInputStream file = new FileInputStream(new File("c:/mankind.xml"));

                DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();

                DocumentBuilder builder =  builderFactory.newDocumentBuilder();

                Document xmlDocument = builder.parse(file);

                XPathExpression expr = xPath.compile("//project/*");
                NodeList list= (NodeList) expr.evaluate(xmlDocument, XPathConstants.NODESET);
                for (int i = 0; i < list.getLength(); i++) {
                    Node node = list.item(i);
                    System.out.println(node.getNodeName() + "=" + node.getTextContent());
                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (XPathExpressionException e) {
                e.printStackTrace();
            }        
        }
    }

假设输入已得到纠正(Solve world hunger),代码应该打印出来:

建议=建立企业 建议=学习世界语
问题=解决世界饥饿问题 讨论=存在Vulcans