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.
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 thename()
function. If I understood your problem correctly, something like this should work:Variable field is not required in this example. You can also use function
current()
to access the current context node of the inner loop: