【问题标题】:XPath Help Needed - select nodes based on numeric range需要 XPath 帮助 - 根据数值范围选择节点
【发布时间】:2014-04-22 21:06:56
【问题描述】:

我很难过 - 如果可能的话,我想使用 XPath 来解决这个问题,因为它会简化一些支持 Java 代码。我的文档结构如下:

<table>
   <row id="a">
      <data-point value="0">5</data-point>
      <data-point value="15">4</data-point>
      <data-point value="30">2</data-point>
      <data-point value="45">0</data-point>
   </row>
   <row id="b">
      <data-point value="0">8</data-point>
      <data-point value="10">6</data-point>
      <data-point value="20">4</data-point>
      <data-point value="30">0</data-point>
   </row>
</table>

选择基于输入值。例如,如果 inputValue = 17,我需要选择包含该值的数据点 - 在这种情况下,选择 value="15" 和 "30" 的数据点。同样,如果值为 32,则选择数据点“30”和“45”。

如果数字与其中一个数据点完全匹配,则可以只返回匹配的数据点,或者返回该数据点和下一个或前一个数据点(只要匹配的数据点并不重要)返回。因此,如果 inputValue 为 15,则可以选择值为“15”和“30”、“0”和“15”或仅“15”的数据点。

XPath 还必须考虑行元素的选择器

我已经尝试了很多使用 follow-sibbling、last() 等的组合,但我似乎无法找到合适的 XPath。有哪位大师能想出一个好的 XPath 吗?

以下解决方案接近但在某些情况下仍然失败。以下 XPath 假定输入选择是针对行 id="a" 和 inputValue 为 20:

/table/row[@id='a']/data-point[(20 >= number(@value) or 20 <= number(@value)) and following-sibling::*[1]/@value > 20]

【问题讨论】:

  • 我不太了解行的要求。你会得到一个输入值和一行?如果不是,如何选择行?对于输入 = 17,是否应同时返回 15-30(来自行 a)和 10-20(来自行 b)?
  • 是否可以输入值,例如 120?
  • 您的示例输入似乎是按值属性排序的。真实数据是这样吗?
  • Slanec - 不,我把额外的“行”放在那里,因为它会被另外选中。因此,XPath 必须以 /table/row[@id='a']/data-point[???] 开头。我确实提出了一个似乎可行的解决方案,但感觉有点“蛮力”,所以也许有人可以提出一个更简单的解决方案。
  • 请不要通过编辑您的问题来发布您的答案,这只会混淆问题和答案之间的差异。回答你自己的问题是完全可以的。但是,对于更一般的情况,您的查询是不正确的。尝试 2 或 40 或其他一些值,而不是 20。

标签: xml xpath


【解决方案1】:

您在评论中提到您拥有 XPath 2.0,因此您可以使用 min 和 max 函数。假设$row 是目标行ID,$val 是目标值:

/table/row[@id = $row]/data-point[@value = (
   min(../data-point/@value[. ge $val]), max(../data-point/@value[. le $val])
)]

这将找到@values 的最低上限和最大下限(如果恰好匹配,则可能是相同的)并提取它们对应的data-point 元素。

即使输入中的值不是按升序排列的,这也会起作用。

【讨论】:

    【解决方案2】:

    您没有指定 XPath 版本,所以我假设它是 1.0。使用纯 1.0 功能解决这个问题会很棘手,因为没有对节点集进行排序的概念(但肯定有 N XPath 大师可以改变语言来解决这个问题)。但是,我看到了两个选项:

    1) 用合适的语言编写自定义函数,例如Java,获取一个节点集并返回另一个包含输入值的节点集,或者为null。

    2) 如果您可以更改输入数据,请应用一个 XSLT,该 XSLT 插入一个带有目标值的虚假 &lt;data-point&gt; 条目,对 &lt;row&gt; 子项进行排序,然后选择前面和后面的兄弟姐妹。

    【讨论】:

      【解决方案3】:

      假设 $row 是您的行项目(ab 在这种情况下)和 $input 是您的输入值(17 在给定的示例中),以下 XPath 将获取所需的节点:

      (/table/row[@id = $row]/data-point[@value < $input])[last()] | (/table/row[@id = $row]/data-point[@value > $input])[1] | /table/row[@id = $row]/data-point[@value = $input]
      

      它将选择最后一个值低于您输入值的项目和第一个值高于您输入值的项目。此外,如果值相等,它将添加节点本身。

      【讨论】:

      • 谢谢。这似乎有效。我最初试图避免使用联合运算符,但这确实返回了正确的值。
      【解决方案4】:

      假设您的搜索值存储在 $para 中,则以下 XPath 表达式应该在 XPath 1.0 中工作:

      data-point[  ( (preceding-sibling::data-point[1]/@value &lt; $para 
                      or 
                      not(preceding-sibling::data-point[1])
                     ) 
                    and @value > $para
                   ) 
                 or 
                   ( (following-sibling::data-point[1]/@value > $para 
                      or 
                      not (following-sibling::data-point[1])
                     ) 
                     and @value &lt; $para
                   )
                ]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-15
        相关资源
        最近更新 更多