Reputation: 10675
Given the following XML:
<current>
<login_name>jd</login_name>
</current>
<people>
<person>
<first>John</first>
<last>Doe</last>
<login_name>jd</login_name>
</preson>
<person>
<first>Pierre</first>
<last>Spring</last>
<login_name>ps</login_name>
</preson>
</people>
How can I get "John Doe" from within the current/login matcher?
I tried the following:
<xsl:template match="current/login_name">
<xsl:value-of select="../people/first[login_name = .]"/>
<xsl:text> </xsl:text>
<xsl:value-of select="../people/last[login_name = .]"/>
</xsl:template>
Upvotes: 8
Views: 25357
Reputation: 437
If you need to access multiple users, then JeniT's <xsl:key />
approach is ideal.
Here is my alternative take on it:
<xsl:template match="current/login_name">
<xsl:variable name="person" select="//people/person[login_name = .]" />
<xsl:value-of select="concat($person/first, ' ', $person/last)" />
</xsl:template>
We assign the selected <person>
node to a variable, then we use the concat()
function to output the first/last names.
There is also an error in your example XML. The <person>
node incorrectly ends with </preson>
(typo)
A better solution could be given if we knew the overall structure of the XML document (with root nodes, etc.)
Upvotes: 1
Reputation: 3690
I'd define a key to index the people:
<xsl:key name="people" match="person" use="login_name" />
Using a key here simply keeps the code clean, but you might also find it helpful for efficiency if you're often having to retrieve the <person>
elements based on their <login_name>
child.
I'd have a template that returned the formatted name of a given <person>
:
<xsl:template match="person" mode="name">
<xsl:value-of select="concat(first, ' ', last)" />
</xsl:template>
And then I'd do:
<xsl:template match="current/login_name">
<xsl:apply-templates select="key('people', .)" mode="name" />
</xsl:template>
Upvotes: 10
Reputation: 389
Just to add my thoughts to the stack
<xsl:template match="login_name[parent::current]">
<xsl:variable name="login" select="text()"/>
<xsl:value-of select='concat(ancestor::people/child::person[login_name=$login]/child::first/text()," ",ancestor::people/child::person[login_name=$login]/child::last/text())'/>
</xsl:template>
I always prefer to use the axes explicitly in my XPath, more verbose but clearer IMHO.
Depending on how the rest of the XML documents looks (assuming this is just a fragment) you might need to constrain the reference to "ancestor::people" for example using "ancestor::people[1]" to constrain to the first people ancestor.
Upvotes: 0
Reputation: 5892
You want current()
function
<xsl:template match="current/login_name">
<xsl:value-of select="../../people/person[login_name = current()]/first"/>
<xsl:text> </xsl:text>
<xsl:value-of select="../../people/person[login_name = current()]/last"/>
</xsl:template>
or a bit more cleaner:
<xsl:template match="current/login_name">
<xsl:for-each select="../../people/person[login_name = current()]">
<xsl:value-of select="first"/>
<xsl:text> </xsl:text>
<xsl:value-of select="last"/>
</xsl:for-each>
</xsl:template>
Upvotes: 4
Reputation: 75058
I think what he actually wanted was the replacement in the match for the "current" node, not a match in the person node:
<xsl:variable name="login" select="//current/login_name/text()"/>
<xsl:template match="current/login_name">
<xsl:value-of select='concat(../../people/person[login_name=$login]/first," ", ../../people/person[login_name=$login]/last)'/>
</xsl:template>
Upvotes: 0