55
votes

Could you please help me to find all the elements b which have the child element c in the example below?

<a>
    <b name = "b1"></b>
    <b name = "b2"><c/></b>
    <b name = "b3"></b>
</a>

The xpath query must return the b2 element

The second question is I want to combine 2 conditions: I want to get the element which have name = "b2" and has the element c But this syntax seems not to work: //b[@name='b2' and c]

2
What exactly means "seems not to work"? Please, ask a new, separate question and provide complete (as small as possible) source XML document, the XPath expression used and the wanted result and the actual result you got. With the current XML document the XPath expression //b[@name='b2' and c] selects the second child of a -- exactly as it should.Dimitre Novatchev

2 Answers

66
votes

Whenever the structure of the XML document is known, it is better to avoid using the // XPath pseudo-operator, as its use can result in big inefficiency (traversal of the whole document tree).

Therefore, I recomment this XPath expression for the provided XML document:

/*/b[c]

This selects any b element that is a child of the top element of the XML document and that has a child-element named c.

UPDATE: The OP asked a second question just minutes ago:

The second question is I want to combine 2 conditions: I want to get the element which have name = "b2" and has the element c But this syntax seems not to work: //b[@name='b2' and c]

The provided XPath expression does select exactly the wanted element.

Here is XSLT - based verification:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:copy-of select="//b[@name='b2' and c]"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<a>
    <b name = "b1"></b>
    <b name = "b2"><c/></b>
    <b name = "b3"></b>
</a>

the XPath expression is evaluated and the correctly-selected element is copied to the output:

<b name="b2">
   <c/>
</b>
26
votes

It should be as simple as

//b[c]

i.e. find a b anywhere that has a c child.