Reputation: 7174
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 name
attributes of those element bar
which point to an element foo
that has the attribute checked
. So for the example above, my xslt would output blub
and plim
.
Here is what I have tried so far is to just check whether I can print the id
attribute of the foo
element that each bar
belongs to:
<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 @id
and @for
from the foo
element. So how can I say that I want the @for
attribute from my current element in the for loop but the @id
from the other current element?
Upvotes: 3
Views: 5856
Reputation: 8068
To build on the xsl:key
idea from @martin-honnen, make a key for the checked items:
<xsl:key name="checked" match="foos/foo[@checked = 'yes']" use="@id" />
Then your XSLT can 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 the foo
with checked="yes"
are included in the checked
key (though if you are working from HTML, it's more likely that it's checked="checked"
). key('checked', @for)
for an element without a corresponding checked="yes"
will return an empty node-set/empty sequence (depending on your XSLT version), so for those elements, the predicate will evaluate to false
, so the xsl:apply-templates
selects only the elements that you are interested in, so the template for bar
becomes very simple.
Upvotes: 0
Reputation: 167781
As an alternative that should also improve performance you can define a 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>
with
<xsl:for-each select="//bars/bar">
<xsl:value-of select="key('foo-by-id', @for)/@id" />
</xsl:for-each>
Upvotes: 1
Reputation: 122424
how can I say that I want the
@for
attribute from my current element in the for loop but the@id
from the other current element?
<xsl:value-of select="../../foos/foo[@id=current()/@for]/@id" />
Inside the square brackets, .
is the node that the predicate is testing, whereas current()
is the node that is the current target of the for-each
.
Upvotes: 6