How can I use xsl:import with a variable in the path name?
Asked Answered
M

4

5

Essentially I want do this in XSL:

<xsl:include href="_domains/{$domain}/templates/header.xsl" />

But I can't seem to use a variable ($domain) in the include. Any suggestions on a work around?

Metalworking answered 14/4, 2011 at 20:47 Comment(1)
Good question, +1. See my answer for an XSLT 2.0 - only possible (but limited) solution and another alternative, non-XSLT solution.Ridenhour
R
6

xsl:import and xsl:include are resolved at compile time, and do not support runtime expansion.

Except, if you are using XSLT 2.0, you can use conditional inclusion with use-when, if you have an expression that can be evaluated in a static context.

Refutation answered 14/4, 2011 at 20:51 Comment(1)
+1 Correct answer. Even in XSLT 2.0 the stylesheet module URI is not "dynamic". It can be a relative URI, of course...Adorable
T
3

With the addition of static parameters, it is now possible to conditionally include in XSLT 3.0. Static parameters can be used in the use-when attribute of the xsl:include.

Now we can declare parameters with default values of false() and then override the ones we need at run time...

<xsl:param name="someparam" as="xs:boolean" select="false()" 
  static="yes" required="no"/>  
<xsl:include href="include_me.xsl" use-when="$someparam"/>

Here is a full working example tested with Saxon-HE v9.7 (also tested with Saxon-PE 9.5).

XML Input (test.xml)

<doc>
    <foo/>
</doc>

Main XSLT 3.0 (test_main.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:param name="inc1" as="xs:boolean" select="false()" 
    static="yes" required="no"/>
  <xsl:param name="inc2" as="xs:boolean" select="false()" 
    static="yes" required="no"/>
  
  <xsl:include href="test_inc1.xsl" use-when="$inc1"/>
  <xsl:include href="test_inc2.xsl" use-when="$inc2"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

First possible included XSLT 3.0 (test_inc1.xsl)

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

  <xsl:template match="foo">
    <xsl:copy>INCLUDE FILE 1!!!</xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

Second possible included XSLT 3.0 (test_inc2.xsl)

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

  <xsl:template match="foo">
    <xsl:copy>INCLUDE FILE 2!!!</xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

Command line (setting inc2 to true)

java -cp "saxon9he.jar" net.sf.saxon.Transform -s:"test.xml" -xsl:"test_main.xsl" inc2="true"

Output

<doc>
   <foo>INCLUDE FILE 2!!!</foo>
</doc>

Here's another example, using the above files (except main.xsl), that is more like the original question where part of the path is a variable. Note the _href which is a shadow attribute.

Main XSLT 3.0

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="inc_number" as="xs:string" select="'1'" static="yes" required="no"/>

    <xsl:include _href="test_inc{$inc_number}.xsl"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>
Tsushima answered 29/3, 2017 at 20:12 Comment(0)
R
2

As explained by @lavinio, in XSLT 2.0 the use-when attribute may be used to allow a certain degree of "compile-time" inclusion of an xslt instruction, however this is only limited to testing conditions that can can be determined from values in the static context and from these dynamic context values: current date and time, and implicit time zone.

Another approach is to load the XSLT stylesheet (as an XML document) at runtime and before initiating the transformation to dynamically set the href attribute of any desired <xsl:include> and/or <xsl:import> instructions.

This technique is used by the XPath Visualizer to dynamically change the XSLT stylesheet that then evaluates the user-specified XPath expression and formats the XML document with all selected and visible nodes -- highlighted.

Ridenhour answered 15/4, 2011 at 2:8 Comment(0)
W
0

Another solution is to load an XML file and transform it by a set of rules (this file could even be a simple XSLT variant).

<xsl:param name="domain">_default</xsl:param>

<xsl:variable name="header-template"
   select="document( concat('_domains/', $domain, '/templates/header.xml' ) )" />

<xsl:template name="header">
  <xsl:apply-templates mode="transform" select="$header-template"/>
</xsl:template>
Weighin answered 18/2, 2020 at 7:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.