【问题标题】:Retrieving attribute values depending on the value of another attribute using xpath使用 xpath 根据另一个属性的值检索属性值
【发布时间】:2013-11-24 21:54:03
【问题描述】:

我有以下 xml 文档:

<database>

<order>
    <data>
        <field name="time" value="10:10:10" />
    </data>
    <data>
        <field name="product" value="product_type_1">
            <field name="attributeA" value="Foo" />
            <field name="attributeB" value="Bar" />
        </field>
        <field name="attributeC" value="Jeam" />
        <field name="attributeD" value="Beam" />
        <field name="attributeE" value="Deam" />
    </data>
</order>

<order>
    <data>
        <field name="time" value="10:10:11" />
    </data>
    <data>
        <field name="product" value="product_type_2">
            <field name="attributeF" value="Bravo" />
            <field name="attributeG" value="Echo" />
        </field>
        <field name="attributeC" value="Jeam2" />
        <field name="attributeD" value="Beam2" />
        <field name="attributeJ" value="Charlie" />
        <field name="attributeK" value="Tango" />
        <field name="attributeL" value="Zulu" />
    </data>
</order>

它是一组“订单”元素,但“字段”(包括数量和类型)取决于名称为“产品”的元素的值。我有兴趣根据产品的价值提取信息。更具体地说,我最终会得到这样的表格:

Time      Product          AttributeA AttributeB AttributeC AttributeD
10:10:10  product_type_1   Foo        Bar        Jeam       Beam
10:10:11  product_type_2                         Jeam2      Beam2

换句话说,我试图根据“订单”的子元素的值“剪切”不必要的信息。我试图通过使用xpath(在java中)来实现这一点,但我被卡住了。我不可能模仿上面描述的“if”条件。

我正在考虑使用和 xpath 查询一次检索一个订单元素,然后查询产品类型,然后选择适当的 xpath 来检索对应的属性,但这听起来确实效率低下且速度慢。

是否可以更有效地做到这一点? xpath 不是这里的正确答案吗?

提前致谢。

P.S:您在上面看到的数据的对齐和组织并不重要,只要我检索到正确的数据,那么我确信我能够以某种方式打印它们。

【问题讨论】:

    标签: java xml xslt xpath xquery


    【解决方案1】:

    如果您想使用 XPath,则至少需要 XPath 3.0 或 XQuery(此代码在两者中都有效)。如果您想在 Java 中使用 XQuery 引擎,请查看 XQuery 引擎,例如 Saxon、BaseX、eXist DB...

    for $order in /database/order
    return string-join((
      $order//field[@name='time']/@value,
      $order//field[@name='product']/@value,
      ($order//field[@name='attributeA']/@value, '')[1],
      ($order//field[@name='attributeB']/@value, '')[1],
      ($order//field[@name='attributeC']/@value, '')[1],
      ($order//field[@name='attributeD']/@value, '')[1]),
      '&#9;')
    

    用于属性的模式确保空值不会破坏表格布局(因此对于第二种产品类型,属性 C 和 D 不会获得属性 A 和 B)。 &amp;#9; 是制表符。


    如果您想使用 Java 进一步处理输出,我会这样做:获取所有订单 (/database/order) 并遍历它们。然后,对于每个订单,使用 DOM(或再次使用 XPath)来获取您需要的节点。然而,您提出的问题似乎不是您的实际问题,可能是使用 XQuery 可能会导致更清洁的解决方案。

    【讨论】:

    • 由于我对 XPath 的了解有限,给我的印象是 XPath 可以作为解决我问题的魔杖。很快就很明显,单靠 XPath 不是答案。 XQuery 可能有一个学习曲线,所以我像 Jens Erat 建议的那样将 XPath 与 DOM 结合起来。我在处理内存方面的中型(~1gb)大小的 xml 文件时遇到了麻烦,但我正在调查并尝试在此处发布解决方案。
    • 你可能想看看像 BaseX、Sedna 和 eXist 这样的 XML 数据库——那时你应该不会遇到主存问题。如果您不习惯函数式编程,XQuery 肯定有一个陡峭的学习曲线,但值得努力。 BaseX 有一些很好的可视化工具,可以在学习 XQuery 的同时帮助您,而且设置起来相当容易。 (免责声明:我在某种程度上隶属于 BaseX 团队。)
    最近更新 更多