【问题标题】:How to search for an XPath node within a Node object如何在 Node 对象中搜索 XPath 节点
【发布时间】:2018-01-12 15:07:07
【问题描述】:

我有以下程序:

    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 表达式不正确 ("//*[local-name()='ProductID']");它显然搜索主文档,而不是调用 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

请注意,“id”的所有值都来自第一个节点,而不是调用 selectSingleNode() 的节点的 ProductID 值。

我尝试了各种“.”、“/”、没有“/”、“::”等的组合,但我似乎找不到将返回 ProductID 节点的 XPath 表达式列表中的单个产品节点。我该怎么做?

【问题讨论】:

  • 也有可能是程序无权访问命名空间,所以我也一直在玩local-name。

标签: java xpath dom4j


【解决方案1】:

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

您真正想要做的是 selectNodes() 在“ProductID”路径上并对其进行迭代。您甚至可以通过一些相对调用(见下文)获得与“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();
    }
}

【讨论】:

  • 这是我运行此解决方案时的输出: products node list size=3 101236004 Widget1 101236005 Widget2 101236006 Widget3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-20
相关资源
最近更新 更多