Match conditionally upon current node value

25,211

Solution 1

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>

Solution 2

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>

Solution 3

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.)

Share:
25,211
Pierre Spring
Author by

Pierre Spring

Updated on December 17, 2020

Comments

  • Pierre Spring
    Pierre Spring over 3 years

    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>
    
  • Pierre Spring
    Pierre Spring almost 16 years
    thx for the current tip ... even if i really dislike the usage of for-each in xslt ...
  • Matt Large
    Matt Large almost 16 years
    Okay, ignore my answer further down, this one is great. Clean and made up of nice reusable parts.
  • Pierre Spring
    Pierre Spring over 15 years
    thanks for the tip ... works great ... i don't know why, i just dislike using variables in xslt ...