如何在Node对象中搜索XPath节点

时间:2018-01-12 15:07:08

标签: java xpath dom4j

我有以下程序:

    package xpath;

    import java.io.StringReader;
    import java.util.List;

    import org.dom4j.Document;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;

    public class TryXPath
    {
        public static void say(String message) { System.out.println(message); }

        public static String mainDocumentXML 
            = "<GetAvailableProductsResponse xmlns=\"http://api.onecommunications.com/pricing_availability/\">" + 
                "  <GetAvailableProductsResult>" + 
                "    <Products>" + 
                "      <Product>" + 
                "        <ProductID>101236004</ProductID>" + 
                "        <BaseProductName>Widget1</BaseProductName>" + 
                "      </Product>" + 
                "      <Product>" + 
                "        <ProductID>101236005</ProductID>" + 
                "        <BaseProductName>Widget2</BaseProductName>" + 
                "      </Product>" + 
                "      <Product>" + 
                "        <ProductID>101236006</ProductID>" + 
                "        <BaseProductName>Widget3</BaseProductName>" + 
                "      </Product>" + 
                "    </Products>" + 
                "  </GetAvailableProductsResult>" + 
                "</GetAvailableProductsResponse>";

        public static void main(String[] args)
        {
        String PRODUCTS_NODE_PATH = "/*[name()='GetAvailableProductsResponse']/*[name()='GetAvailableProductsResult']/*[name()='Products']";
        String PRODUCTS_PATH = "/*[name()='Product']";

            try
            {
                org.dom4j.io.SAXReader reader = new SAXReader();

                Document document = reader.read(new StringReader(mainDocumentXML));
                Node root = document.selectSingleNode(PRODUCTS_NODE_PATH);
                if (root == null)
                {
                    say("No root");
                }
                else
                {
                    List<Node> productsNodeList = root.selectNodes(PRODUCTS_NODE_PATH + PRODUCTS_PATH);
                    say("products node list size=" + productsNodeList.size());
                    for (Node node : productsNodeList)
                    {
                        say("node: " + node.asXML());
                        say("name: " + node.getName());
                        say("id:   " + node.selectSingleNode("//*[local-name()='ProductID']").getText());
                    }
                }
            } 
            catch (Exception e) { e.printStackTrace(); }
        }

    }

它解析给定的XML;一部分产生一个3个产品节点的列表,然后我想要做的是访问每个节点内的项目。但是,我使用的ProductID的XPath表达式不正确(&#34; // * [local-name()=&#39; ProductID&#39;]&#34;);它显然搜索主文档,而不是调用selectSingleNode()方法的节点。

该计划的输出:

products node list size=3
node: <Product xmlns="http://api.onecommunications.com/pricing_availability/">        <ProductID>101236004</ProductID>        <BaseProductName>Widget1</BaseProductName>      </Product>
name: Product
id:   101236004
node: <Product xmlns="http://api.onecommunications.com/pricing_availability/">        <ProductID>101236005</ProductID>        <BaseProductName>Widget2</BaseProductName>      </Product>
name: Product
id:   101236004
node: <Product xmlns="http://api.onecommunications.com/pricing_availability/">        <ProductID>101236006</ProductID>        <BaseProductName>Widget3</BaseProductName>      </Product>
name: Product
id:   101236004

请注意&#34; id&#34;的所有值来自第一个节点,而不是被调用selectSingleNode()的节点的ProductID值。

我已经尝试过各种各样的组合&#34;。&#34;,&#34; /&#34;,no&#34; /&#34;,&#34;: :&#34;等等,我似乎无法找到将在列表中的单个Product节点内返回ProductID节点的XPath表达式。我该怎么做?

1 个答案:

答案 0 :(得分:0)

基本问题是字符串“// * [local-name()='ProductID']”)中的'//'将找到所有ProductID,无论它们在文档中的位置。当与selectSingleNode()方法一起使用时,您将始终获得该集合中的第一个。

你真正想做的是在'ProductID'路径上的selectNodes()并迭代这些。您甚至可以通过执行一些相对调用来获取与“ProductID”关联的关联“BaseProductName”(参见下文)。

public static void main(String[] args){

    String PRODUCTS_NODE_PATH = "/*[name()='GetAvailableProductsResponse']/*[name()='GetAvailableProductsResult']/*[name()='Products']";

    try {
        org.dom4j.io.SAXReader reader = new SAXReader();

        Document document = reader.read(new StringReader(mainDocumentXML));
        Node root = document.selectSingleNode(PRODUCTS_NODE_PATH);
        if (root == null) {
            say("No root");
        } else {

            // [JIM]  Get all the ProductID nodes               
            List<Node> productsNodeList = root.selectNodes("./*[local-name()='Product']/*[local-name()='ProductID']");              

            // [JIM] Now iterate through and pull out the values
            say("products node list size=" + productsNodeList.size());
            for (Node node : productsNodeList) {
                say(node.getText());
                // [JIM] Get the associated BaseProductName relative to the current ProductID
                say(node.getParent().selectSingleNode("./*[local-name()='BaseProductName']").getText());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}