Use XSL to generate dynamic XSL that is executed within the same script?

10,025

Solution 1

What you want is not possible at present in pure XSLT (1.0 or 2.0).

If you are useing the Saxon 9.x XSLT processor, there is a couple of extension functions that implement this: saxon:compile-stylesheet() and saxon:transform().

It is very rare that a solution to a problem really requires such functionality and it is quite possible that if you describe the problem people will find the best way to solve it without having to produce and execute an XSLT stylesheet dynamically.

Solution 2

XSLT has a special built-in feature that supports generating output, which is XSLT itself.

This is the <xsl:namespace-alias> XSLT directive.

As explaiened by the XSLT 1.0 Spec.:

"

<!-- Category: top-level-element -->
<xsl:namespace-alias
  stylesheet-prefix = prefix | "#default"
  result-prefix = prefix | "#default" />

A stylesheet can use the xsl:namespace-alias element to declare that one namespace URI is an alias for another namespace URI. When a literal namespace URI has been declared to be an alias for another namespace URI, then the namespace URI in the result tree will be the namespace URI that the literal namespace URI is an alias for, instead of the literal namespace URI itself. The xsl:namespace-alias element declares that the namespace URI bound to the prefix specified by the stylesheet-prefix attribute is an alias for the namespace URI bound to the prefix specified by the result-prefix attribute. Thus, the stylesheet-prefix attribute specifies the namespace URI that will appear in the stylesheet, and the result-prefix attribute specifies the corresponding namespace URI that will appear in the result tree. "

Here is a small example of a transformation that generates an xsl:stylesheet containing an xsl:variable, which is constructed in the wanted way:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xxx="my:dummyNS" exclude-result-prefixes="xxx"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:namespace-alias result-prefix="xsl" stylesheet-prefix="xxx"/>

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

  <xxx:variable name="{@name}">
    <xsl:value-of select="."/>
  </xxx:variable>
 </xxx:stylesheet>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

    <v name="myVarName">myValue</v>

the wanted result is produced:

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

Then the next step will be to launch in your "script" this dynamically generated XSLT transformation.

Share:
10,025
Frank Rosario
Author by

Frank Rosario

By day, I'm a mild mannered IT Professional. But at night; I adorn a cape and mask and fight crime.

Updated on June 07, 2022

Comments

  • Frank Rosario
    Frank Rosario about 2 years

    I want to dynamically create variables with dynamic names for later use in my transform, but to do this I'd need to dynamically generate XSL and then run it in the same script.

    This is just a rough pseudo code example of what I'm looking for.

          <xsl:for-each select="//constants/constant" >
            <xsl:variable >
                <xsl:attribute name="name">
                  <xsl:value-of select="@name"/>
                </xsl:attribute>
              <xsl:attribute name="select">
                <xsl:value-of select="@value"/>
              </xsl:attribute>
            </xsl:variable>
          </xsl:for-each>
    

    Can I use XSL to dynamically build XSL to be run later in the same script?

    Note: our XML is transformed via a batch process running a CL XSL transform engine; so just referencing an XSL stylesheet in the XSL document isn't an option.

  • blast_hardcheese
    blast_hardcheese almost 8 years
    Just running your example produces different result to your answer. What actually comes out is: <xxx:stylesheet xmlns:xxx="http://www.w3.org/1999/XSL/Transform" version="1.0"><xxx:variable name="myVarName">myValue</xxx:variable></xxx:stylesheet>
  • Dimitre Novatchev
    Dimitre Novatchev almost 8 years
    @blast_hardcheese, The namespace prefix is not guaranteed to be the same as the one specified in the result-prefix attribute of the xsl:namespace-alias declaration -- it is only used to specify the namespace that the literal-result elements should be put in in the output. Thus, which prefix to actually use is XSLT-processor dependent. Saxon uses the same prefix as the one specified in the result-prefix attribute. However, other XSLT processors are at freedom to use whatever their developers decided was appropriate.
  • Dimitre Novatchev
    Dimitre Novatchev almost 8 years
    @blast_hardcheese, You probably know that if in two XML files only some prefixes (not the namespace URIs they are bound to) are different, then these two XML files are equivalent.