使用嵌套的XPath谓词......精炼

时间:2009-06-08 04:48:42

标签: xpath

所有好的答案!但问题值得改进......

我有以下示例XML ...

<objects>
    <object objectId="1123" ... />
    <properties refObjectId="1123" ... />
    <properties refObjectId="1123" refPropertyId="2311" ... />
    <properties refObjectId="1123" refPropertyId="4611" ... />
    <object objectId="2123" ... />
    <properties refObjectId="2123" refPropertyId="4311" ... />
    <properties refObjectId="2123" refPropertyId="8611" ... />
    ....
</objects>

...以及以下XPath查询...

//object[//properties[@refObjectId=@objectId and not(@refPropertyId)]]

我认为此查询将返回所有object个节点,其中properties节点的refObjectId属性等于objectId object属性} node 并且没有'refPropertyId'属性...即仅对象1123,而不是对象2123 ...但它没有。似乎嵌套谓词中的@objectId未引用objectId节点的object属性。

有什么想法吗?我知道XML结构没有像你期望的那样嵌套,但是这种结构有原因。

4 个答案:

答案 0 :(得分:7)

通常,您应该尽可能避免使用//。我会考虑改写:

//object[../properties/@refObjectId=@objectId]

在提供的表达式中,嵌套谓词实际上是在检查

//properties/@refObjectId=//properties/@objectId 

其中没有。

我希望这有帮助!

编辑:由于问题已在此处更新,因此更新后的回复:  您添加了“似乎嵌套谓词中的@objectId不引用对象节点的objectId属性。”你是绝对正确的!所以让我们解决它!!

//object[../properties[not(@refPropertyId)]/@refObjectId=@objectId]

这应该更接近你所追求的目标!

答案 1 :(得分:0)

试试这个:

   //objects[object/@objectId = properties/@refObjectId]/object

答案 2 :(得分:0)

这应该有效:

//objects/object[@objectId = ../properties/@refObjectId]

我不确定你的xml是怎么回事。但是,如果它采用以下格式:

<objects>
    <object objectId="1111" />
    <properties refObjectId="1111" />
    <object objectId="2111" />
    <properties refObjectId="3111" />
    <object objectId="4111" />
    <properties refObjectId="5111" />
    <object objectId="6111" />
    <properties refObjectId="4111" />
    <object objectId="7111" />
    <properties refObjectId="7111" />
</objects>

然后你应该使用下面的xpath来获取对象1111和7111.结果不应该包括4111,因为refObjectId = 4111的属性不会紧跟在objectId = 4111的对象之后。

//objects/properties[@refObjectId = preceding::object[1]/@objectId]/preceding::object[1]

答案 3 :(得分:0)

假设属于给定<properties>的所有<object>个节点实际上跟随该对象(您的输入似乎暗示了这一点),您可以这样做:

/objects/properties[
  @refObjectId = preceding-sibling::object[1]/@objectId
  and 
  not(@refPropertyId)
]/preceding-sibling::object[1]

这应该表现得很好。

如果您碰巧在XSLT中,事情会变得更简单:

<xsl:key name="kPropertiesByObjectId" match="properties" use="@refObjectId" />

<xsl:template match="object">
  <!-- This tests for an empty node-set. Non-empty node sets can only happen
       for objects with at least one <properties> node without @refPropertyId -->
  <xsl:if test="key('kPropertiesByObjectId', @objectId)[not(@refPropertyId)]">
    <xsl:copy-of select="." />
  </xsl:if>
</xsl:template>

在XSLT情况下,对象和proerties节点的顺序变得无关紧要。