9

All great answers! But the question deserves refinement ...

I've got the following sample 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>

... and the following XPath query ...

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

I thought this query would return all object nodes where there is a properties node that has a refObjectId attribute that equals the objectId attribute of the object node and no 'refPropertyId' attribute ... namely object 1123 only, not object 2123 ... but it doesn't. It seems the @objectId in the nested predicate does not refer to the objectId attribute of the object node.

Any ideas? I know the XML structure isn't nested as you would expect, but there are reasons for this structure.

1
  • Do you have multiple object nodes within the objects node where the properties for a particular object occur just below tht object? Commented Jun 8, 2009 at 5:01

4 Answers 4

10

Generally you should avoid using // where you can. I'd consider rephrasing:

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

In the expression provided, your nested predicate is actually checking for

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

of which there are none.

I hope this helps!

EDIT: Since the question has been updated here is an updated response: You added "It seems the @objectId in the nested predicate does not refer to the objectId attribute of the object node." You're absolutely right! So let's fix it!!

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

This should be closer to what you're after!

Sign up to request clarification or add additional context in comments.

Comments

0

Try this:

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

Comments

0

This should work:

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

I am not sure how your xml is. However, if it is in the following format:

<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>

Then you should use the following xpath to get only objects 1111 and 7111. The result should not include 4111 because the properties where refObjectId = 4111 does not immediately follow the object whose objectId=4111.

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

Comments

0

Assuming that all <properties> nodes that belong to a given <object> actually follow that object (your input seems to imply that), you could do:

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

This should perform pretty well.

If you happen to be in XSLT, things get a lot simpler:

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

and

<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>

In the XSLT case, the order of object and proerties nodes becomes irrelevant.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.