0

Note: Solution should be in XSLt 1.0

I'm a complete novice with XSLT so apologies if solutions to other questions relating to loops would work for my problem but I've had no luck so far.

I have an XML file with multiple nodes such as the following:

<Roles>
  <field name="linecode" instance="1" value="EY"/>
  <field name="number" instance="1" value="265"/>
  <field name="linecode" instance="2" value="PK"/>
  <field name="number" instance="2" value="123"/>
  <field name="abc" instance="1" value="123"/>
  <field name="xyz" instance="1" value="123"/>
</Role>

I need to loop through these nodes and print <field name="linecode"> along with its matching instance no <field name="number">. However, if I use a for-each loop it will iterate through the <field name="linecode">s fine but print the same <field name="number"> is not working.

Is there any way I can sync them up so that, for example the output will be

EY - 265
PK - 123

I have also tried to use the following-sibling but its not working for me.. Any help is highly appreciated. .

Here's my sample xslt.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Roles">
    <xsl:for-each select="field[@name='linecode']">
        <xsl:value-of select="@value"/>
        <xsl:text> - </xsl:text>
        <xsl:value-of select="field[@name='number' and instance='@instance']"/>
        <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
</xsl:template>

If anyone could think an alternative to loops which would work as well I would appreciate it.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
Irfan Ahmed
  • 3
  • 1
  • 3

3 Answers3

1

If by "matching instance" you mean the immediately following field element, then you can use

<xsl:value-of select="following-sibling::field[1]/@value"/>

But if "matching instance" means the number field with the same id, then use

<xsl:value-of select="../field[@name='number' and @instance=current()/@instance]/@value"/>
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
0

The expression you want is this..

<xsl:value-of select="../field[@name='number' and @instance=current()/@instance]/@value"/>

Note the use of ../ at the start. If you did just <xsl:value-of select="field.." /> you would be trying to select a child element called field when you are already positioned on a field element. Doing .. selects the parent node first, allowing you to select a sibling element.

Also note the use of current() which refers to the node you are currently positioned on (the one you select with xsl:for-each). Read up on "current node vs context node" here: Current node vs. Context node in XSLT/XPath?

Alternatively, you could learn about using keys here. You could define a key to look up field elements by their instance attribute

<xsl:key name="fields" match="field" use="@instance" />

So, to look up the element you do this..

<xsl:value-of select="key('fields', @instance)[@name = 'number']/@value"/>

Try this XSLT too

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="fields" match="field" use="@instance" />

<xsl:template match="Roles">
    <xsl:for-each select="field[@name='linecode']">
        <xsl:value-of select="@value"/>
        <xsl:text> - </xsl:text>
        <xsl:value-of select="key('fields', @instance)[@name = 'number']/@value"/>
        <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93
0
<xsl:template match="Roles">
        <xsl:for-each select="field">
            <xsl:if test="@name='linecode'">
            <xsl:value-of select="@value"/>
                <xsl:text> - </xsl:text>
            </xsl:if>

            <xsl:if test="@name='number'">
                <xsl:value-of select="@value"/>
                <xsl:text>&#xa;</xsl:text>
            </xsl:if>

        </xsl:for-each>
Also try it
imran
  • 461
  • 4
  • 8