Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT: Match first descendant element

Tags:

xslt

xpath

I'm trying to match the first bar element that occurs as a descendant of a foo element in an xsl match pattern and struggling. Initial attempt:

<xsl:template match="//foo//bar[1]">
...
</xsl:template>

fails because there are several bar elements that match. So:

<xsl:template match="(//foo//bar)[1]">
...
</xsl:template>

but that fails to compile.

like image 967
Bobby Jack Avatar asked Jun 17 '14 17:06

Bobby Jack


1 Answers

Tricky. I don't know how efficient or otherwise this would be, but you could turn the pattern on its head and move the logic into a predicate (which is allowed to use axes other than child, attribute and //):

<xsl:template match="foo//bar[not(preceding::bar/ancestor::foo)]">

(any bar inside a foo provided there isn't another bar-inside-a-foo before it). Alternatively you could try a key trick similar to the way Muenchian grouping works, which may be more efficient

<!-- trick key - all matching nodes will end up with the same key value - all
     we care about is finding whether a particular node is the first such node
     in the document or not. -->
<xsl:key name="fooBar" match="foo//bar" use="1" />

<xsl:template match="foo//bar[generate-id() = generate-id(key('fooBar', 1)[1])]">
like image 93
Ian Roberts Avatar answered Oct 03 '22 00:10

Ian Roberts