Nested for-each loops, accessing outer element with variable from the inner loop

25,333

Your stylesheet looks almost fine. Just the expression $rec/$field doesn't make sense because you can't combine two node sets/sequences this way. Instead, you should compare the names of the elements using the name() function. If I understood your problem correctly, something like this should work:

<xsl:variable name="config" select="document('./configuration.xml')"/>
<xsl:for-each select="data/dataset/record">
    <xsl:variable name="rec" select="."/>
    <xsl:for-each select="$config/configuration/outputField">
        <xsl:variable name="field" select="fieldName"/>
        ...
        <xsl:variable name="value" select="$rec/*[name(.)=$field]"/>
        ...    
    </xsl:for-each>
    <xsl:value-of select="$newline"/>
</xsl:for-each>

Variable field is not required in this example. You can also use function current() to access the current context node of the inner loop:

<xsl:variable name="value" select="$rec/*[name(.)=current()/fieldName]"/>
Share:
25,333
Xavi López
Author by

Xavi López

Updated on May 04, 2020

Comments

  • Xavi López
    Xavi López almost 4 years

    I'm trying to write an XSL that will output a certain subset of fields from the source XML. This subset will be determined at transformation time, by using an external XML configuration document containing the field names, and other specific information (such as the padding length).

    So, this is two for-each loops:

    • The outer one iterates over the records to access their fields record by record.
    • The inner one iterates over the configuration XML document to grab the configured fields from the current record.

    I've seen in In XSLT how do I access elements from the outer loop from within nested loops? that the current element in the outside loop can be stored in an xsl:variable. But then I've got to define a new variable inside the inner loop to get the field name. Which yields to the question: Is it possible to access a path in which there are two variables ?

    For instance, the source XML document looks like:

    <data>
        <dataset>
            <record>
                <field1>value1</field1>
                ...
                <fieldN>valueN</fieldN>
            </record>
        </dataset>
        <dataset>
            <record>
                <field1>value1</field1>
                ...
                <fieldN>valueN</fieldN>
            </record>
        </dataset>
    </data>
    

    I'd like to have an external XML file looking like:

    <configuration>
        <outputField order="1">
            <fieldName>field1</fieldName>
            <fieldPadding>25</fieldPadding>
        </outputField>
        ...
        <outputField order="N">
            <fieldName>fieldN</fieldName>
            <fieldPadding>10</fieldPadding>
        </outputField>
    </configuration>
    

    The XSL I've got so far:

    <xsl:variable name="config" select="document('./configuration.xml')"/>
    <xsl:for-each select="data/dataset/record">
        <!-- Store the current record in a variable -->
        <xsl:variable name="rec" select="."/>
        <xsl:for-each select="$config/configuration/outputField">
            <xsl:variable name="field" select="fieldName"/>
            <xsl:variable name="padding" select="fieldPadding"/>
    
            <!-- Here's trouble -->
            <xsl:variable name="value" select="$rec/$field"/>
    
            <xsl:call-template name="append-pad">
                <xsl:with-param name="padChar" select="$padChar"/>
                <xsl:with-param name="padVar" select="$value"/>
                <xsl:with-param name="length" select="$padding"/>
            </xsl:call-template>
    
        </xsl:for-each>
        <xsl:value-of select="$newline"/>
    </xsl:for-each>
    

    I'm quite new to XSL, so this might well be a ridiculous question, and the approach can also be plain wrong (i.e. repeatig inner loop for a task that could be done once at the beggining). I'd appreciate any tips on how to select the field value from the outer loop element and, of course, open to better ways to approach this task.