1

I am trying to transform an XML file into a CSV file. The resulting CSV file will contain 2 lines, the first being the column headers, the second being the data extracted from the XML file.

Following the answer to the question Reference an XSLT variable via a dynamic name, I created a similar structure. However, I wanted the elements to contain 2 attributes, the first being the name of the column to be used (for the first line), and the second being the XML path to the value (for the second line) which is to be evaluated to extract the value.

XML:

<?xml version="1.0" encoding="UTF-8"?>
<message>
    <address>
        <line-1>123 Random Street</line-1>
        <line-2>Random-City, Some-State</line-2>
    </address>
</message>

XSLT:

<!-- Global variables -->
    <xsl:variable name="newlineChar"><xsl:text>&#xa;</xsl:text></xsl:variable>
    <xsl:variable name="seperatorPipe"><xsl:text>&#x7C;</xsl:text></xsl:variable>

    <v:variables name="varsRaw">
        <v:variable name="ADDRESS_LINE_1" value="//message/address/line-1" />
        <v:variable name="ADDRESS_LINE_2" value="//message/address/line-2" />
    </v:variables>
    <xsl:variable name="vars" select="document('')//v:variables/v:variable" />

<!-- Start main template -->
    <xsl:template match="/|@*">

        <!-- CSV Column headers -->
        <xsl:for-each select="$vars">
            <xsl:value-of select="./@name" />
            <xsl:if test="position() != last()">
                <xsl:value-of select="$seperatorPipe" />
            </xsl:if>
        </xsl:for-each>

        <!-- CSV Column values -->
        <xsl:for-each select="$vars">
            <xsl:value-of select="./@value" />
            <xsl:if test="position() != last()">
                <xsl:value-of select="$seperatorPipe" />
            </xsl:if>
        </xsl:for-each>

    </xsl:template>
<!-- End main template -->

</xsl:stylesheet>

The first for-each works fine, displaying the headers as desired.

However, I am unable to get the XSLT to interpret the contents of the value attribute as an XPath, it instead is handled and displayed as a literal string. I tried enclosing it in curly brackets (<xsl:value-of select="{./@value}" />), but that didn't change anything (I'm speculating that this is because it isn't an XSLT variable).

Is it possible to have XSLT interpret the contents of an element or attribute as an XPath in order to fetch the data from the XML file?

If this is not possible, is there a viable alternative that could be used (I tried looking into having XSLT variables that could have the name of the XSV column, and looked into dynamically referring to the variable based on the name, kind of like a Perl reference or $$ in PHP, but didn't find anything I could implement)?

Similar questions which didn't quite answer my question: XSLT document with dynamic path ; dynamic xpath in xslt? ; Reference an XSLT variable via a dynamic name

Edit: I am unable to determine whether any extensions are available.

AntonH
  • 6,359
  • 2
  • 30
  • 40

2 Answers2

0

Is it possible to have XSLT interpret the contents of an element or attribute as an XPath in order to fetch the data from the XML file?

There is no dynamic XPath evaluation in vanilla XSLT / XPath 1.0 or 2.0.

You can use XSLT-processor-specific extensions to overcome this, for example http://exslt.org/dyn/functions/evaluate/.

Which kind of extensions - if any - your XSL processor supports, depends.

XSLT 3.0 has <xsl:evaluate> (spec).

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • `There is no dynamic XPath evaluation in vanilla XSLT / XPath 1.0 or 2.0.` This confirms what I thought :( Thanks. – AntonH Aug 01 '18 at 16:58
0

I can see two issues here.

First of all, you probably mean:

<v:variables name="varsRaw">
    <v:variable name="ADDRESS_LINE_1" value="{//message/address/line-1}" />
    <v:variable name="ADDRESS_LINE_2" value="{//message/address/line-2}" />
</v:variables>

This is the place where you want to interpret XPath.

Second, I would go with putting this in a variable, and converting it from result fragment to node set (an XSLT 1.0 quirk) with EXSLT. Instead of trying to grab it from current stylesheet. Then you can iterate over the contents of this variable.

alamar
  • 18,729
  • 4
  • 64
  • 97