How to find element that matches xslt attribute value for each loop

Suppose I have the following XML:

<data>
  <foos>
    <foo id="1" checked="yes" />
    <foo id="2" />
    <foo id="3" />
    <foo id="4" checked="yes" />
  </foos>
  <bars>
    <bar for="1" name="blub" />
    <bar for="2" name="bla" />
    <bar for="3" name="baz" />
    <bar for="4" name="plim" />
  </bars>
</data>

      

Now I want to print all the attributes of name

this element bar

that point to the element foo

that has the attribute checked

. So for the example above, my xslt outputs blub

and plim

.

Here's what I've tried so far to check if I can print the attribute of an id

element foo

that belongs to each bar

:

<xsl:template match="/">
  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="../../foos/foo[@id=./@for]/@id" />
  </xsl:for-each>
</xsl:template>

      

but to no avail. I think the problem is that the check foo[@id=./@for]

will select both from @id

and @for

from the element foo

. So how can I tell I want an attribute @for

from my current element in the for loop, but @id

from another current element?

+3


source to share


3 answers


how can I tell that I want an attribute @for

from my current element in the for loop, but @id

from another current element?

Use the functioncurrent()

:



<xsl:value-of select="../../foos/foo[@id=current()/@for]/@id" />

      

In square brackets .

, this is the node that the predicate is testing and current()

is the node that is the current target for-each

.

+5


source


Alternatively, which should also improve performance, you can define the key

<xsl:key name="foo-by-id" match="foos/foo" use="@id"/>

      

and then replace



  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="../../foos/foo[@id=./@for]/@id" />
  </xsl:for-each>

      

from

  <xsl:for-each select="//bars/bar">
    <xsl:value-of select="key('foo-by-id', @for)/@id" />
  </xsl:for-each>

      

+1


source


To use the idea xsl:key

from @ martin-honnen enter a key for the checked items:

<xsl:key name="checked" match="foos/foo[@checked = 'yes']" use="@id" />

      

Then your XSLT might become:

<xsl:template match="/">
  <xsl:apply-templates select="/data/bars/bar[key('checked', @for)]" />
</xsl:template>

<xsl:template match="bar">
  <xsl:value-of select="@name" />
</xsl:template>

      

Only foo

s checked="yes"

are included in the key checked

(although if you are working with HTML it is more likely that it is checked="checked"

). key('checked', @for)

for an element without a matching checked="yes"

will return an empty sequence of node-set / empty (depending on your version of XSLT), so for those elements the predicate will evaluate as false

, so xsl:apply-templates

only selects the elements you are interested in, so the template for bar

becomes very simple.

0


source







All Articles