如何在路径名中将 xsl:import 与变量一起使用?

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

提问人:Andrew G. Johnson 提问时间:4/15/2011 更新时间:11/20/2023 访问量:4469

问:

从本质上讲,我想在XSL中执行此操作:

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

但我似乎不能在包含中使用变量 ($domain)。关于解决方法的任何建议?

XSLT的

评论

0赞 Dimitre Novatchev 4/15/2011
好问题,+1。请参阅我对 XSLT 2.0 的回答 - 唯一可能(但有限)的解决方案和另一种替代的非 XSLT 解决方案。

答:

6赞 lavinio 4/15/2011 #1

xsl:import并在编译时解析,并且不支持运行时扩展。xsl:include

但是,如果您使用的是 XSLT 2.0,那么如果有一个可以在静态上下文中计算的表达式,则可以将条件包含与 一起使用。use-when

评论

1赞 4/15/2011
+1 正确答案。即使在 XSLT 2.0 中,样式表模块 URI 也不是“动态”的。当然,它可以是相对 URI......
2赞 Dimitre Novatchev 4/15/2011 #2

正如 @lavinio 所解释的,在 XSLT 2.0 中,use-when 属性可用于允许在一定程度上“编译时”包含 XSLT 指令,但这仅限于测试条件,这些条件可以从静态上下文中的值和这些动态上下文值(当前日期和时间以及隐式时区)中确定。

另一种方法是在运行时加载 XSLT 样式表(作为 XML 文档),然后再启动转换,以动态设置任何所需和/或指令的属性。href<xsl:include><xsl:import>

XPath 可视化工具使用此技术来动态更改 XSLT 样式表,然后计算用户指定的 XPath 表达式,并使用突出显示所有选定和可见节点来设置 XML 文档的格式。

3赞 Daniel Haley 3/30/2017 #3

通过添加静态参数,现在可以有条件地包含在 XSLT 3.0 中。静态参数可以在 的属性中使用。use-whenxsl:include

现在,我们可以声明默认值为 的参数,然后覆盖我们在运行时需要的参数......false()

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

这是使用 Saxon-HE v9.7 测试的完整工作示例(也使用 Saxon-PE 9.5 测试)。

XML 输入 (test.xml)

<doc>
    <foo/>
</doc>

主 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>

第一个可能包含的 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>

第二个可能的包括 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>

命令行(设置为 true)inc2

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

输出

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

这是另一个示例,使用上述文件(main.xsl 除外),这更像是原始问题,其中部分路径是变量。请注意 which 是 shadow 属性_href

主 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>
0赞 ruvim 2/18/2020 #4

另一种解决方案是加载一个 XML 文件,并通过一组规则对其进行转换(此文件甚至可以是一个简单的 XSLT 变体)。

<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>