Thijs Wouters
Thijs Wouters

Reputation: 850

How to select all nodes with the same name for different parent nodes?

Let's say I have the following xml:

<root>
  <person>
    <name>John</name>
  </person>
  <children>
    <person>
      <name>Jack</name>
    </person>
  </children>
</root>

Is it possible to select both persons at once? Assuming that I don't know that the other person is in the children tag, they could easily be in the spouse tag or something completely different and possibly in an other child. I do know all persons I need are in the root tag (not necessarily the document root).

Upvotes: 5

Views: 17243

Answers (5)

StuartLC
StuartLC

Reputation: 107267

You can use

//person

or

//*[local-name()='person']

to find any person elements in the document, but be careful - certain xsl processors (like Microsoft's), the performance of double slash can be poor on large xml documents because all nodes in the document need to be evaluated.

Edit :
If you know there are only 2 paths to 'person' then you can avoid the // altogether:

<xsl:for-each select="/root/person | /root/children/person">
    <outputPerson>
        <xsl:value-of select="name/text()" />
    </outputPerson>
</xsl:for-each>

OR namespace agnostic:

<xsl:for-each select="/*[local-name()='root']/*[local-name()='person'] 
  | /*[local-name()='root']/*[local-name()='children']/*[local-name()='person']">

Upvotes: 11

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243449

In Petar Ivanov's answer the definition of // is wrong.

Here is the correct definition from the XPath 1.0 W3C Specification:

// is short for /descendant-or-self::node()/

Upvotes: 3

Spredzy
Spredzy

Reputation: 5164

As nonnb stated double slash's performance are poor on large xml documents.

So //name would do the trick but might bring up much more elements that you expect. Plus imagine within your root element you have some elements that are not persons that might have descendants element with the name name, according to your question you don't want to bring them up, //name will bring them up.

You should affine your context-node at max so performance wise your XPath will be optimal.

For this precise document I would use

/root/descendant::person/name

Hope it helps,

Upvotes: 1

Gapipro
Gapipro

Reputation: 1973

Or you can use:

root//person

So you search for persion only in root element

Upvotes: 1

Petar Ivanov
Petar Ivanov

Reputation: 93030

//name

will match both, no matter where they are in the xml tree.

// Selects nodes in the document from the current node that match the selection no matter where they are (link)

Upvotes: 1

Related Questions