tags:

views:

112

answers:

2
+1  Q: 

XPath selection

I'm having trouble writing an XPath expression to select nodes that contain certain elements, while excluding siblings of this element that I'm not interested in. I suspect this can't be done with XPath alone and that I will need to use XSLT.

Using this source document

<items>
    <item id="foo1">
     <attr1>val1</attr1>
     <attr2>val2</attr2>
     <attr3>val3</attr3>
     <interestingAttribute>val4</interestingAttribute>
    </item>
    <item id="foo2">
     <attr1>val5</attr1>
     <attr2>val6</attr2>
     <attr3>val7</attr3>
    </item>
    <item id="foo3">
     <attr1>val8</attr1>
     <attr2>val9</attr2>
     <attr3>val10</attr3>
     <interestingAttribute>val11</interestingAttribute>
    </item>
</items>

I would like to generate this result

<items>
    <item id="foo1">
     <interestingAttribute>val4</interestingAttribute>
    </item>
    <item id="foo3">
     <interestingAttribute>val11</interestingAttribute>
    </item>
</items>

Can this be done with XPath? If not, what XSLT transformation should I use?

+2  A: 

This will select only <item>s that have <interestingAttribute> children:

/items/item[interestingAttribute]

Or you can select the <interestingAttribute> elements themselves like so:

/items/item/interestingAttribute

These two expressions will give you back a node-set, a list of XML nodes. If you're really trying to transform one document to another you'll probably want to use XSLT, but remember that XPath is a core component of XSLT so you'll certainly be using XPath expressions like the ones above to control the transformation.

John Kugelman
+4  A: 

XPath is used to select specific nodes, and it won't give you a tree structure like you want. At most, you can get a node list out of it, and from the node list, you could derive the tree structure. If all you really want here is to select the interesting attributes, you can try this XPath:

/items/item/interestingAttribute

If you want to generate the tree, you will need XSLT. This template should do it:

<xsl:template match="/items">
 <xsl:copy>
  <xsl:for-each select="item[interestingAttribute]">
   <xsl:copy>
    <xsl:copy-of select="@* | interestingAttribute"/>
   </xsl:copy>
  </xsl:for-each>
 </xsl:copy>
</xsl:template>
Chris Nielsen
Fixed typos, thanks for pointing them out
Chris Stevens