具有导入功能的XSLT变量作用域

时间:2018-10-05 21:35:42

标签: xml xslt scope include global-variables

我正在构建一个雄心勃勃且几乎可以肯定注定要失败的客户端CMS(使用XSLT 1.0,大多数浏览器都支持)。作为其中的一部分,我希望将template.xsl用作样式表,并将业务逻辑包含在config.xsl中。

这是我拥有的那种XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/XRCS/xrcs/template.xsl" type="text/xsl"?>
<xrcs:page id="/"
           xmlns="http://www.w3.org/1999/xhtml"
           xmlns:xrcs="xrcs:xrcs">
    <xrcs:title>XRCS Home Page</xrcs:title>
    <xrcs:content>
        Hello I am some HTML!
        <p>
            Paragraphs!
        </p>
        <h2>Headings!</h2>
        <p>
            More paragraphs!
        </p>
    </xrcs:content>
</xrcs:page>

首先,我希望页面标题可以从config.xsl中进行自定义。我认为这将非常简单:

  • template.xsl-实际的样式表

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:xrcs="xrcs:xrcs"
                    xmlns="http://www.w3.org/1999/xhtml">
        <xsl:import href="config.xsl" />
    
        <!-- DOCTYPE from
             https://stackoverflow.com/a/22302701/522375 -->
        <xsl:output method="xml"
                    doctype-system="about:legacy-compat" />
        <xsl:template match="/">
            <html>
                <head>
                    <title><xsl:value-of select="$site-name" /></title>
                </head>
                <body>
                    <h1><xsl:value-of select="/xrcs:page/xrcs:title" /></h1>
                    <xsl:copy-of select="/xrcs:page/xrcs:content/*" />
                </body>
            </html>
        </xsl:template>
    </xsl:stylesheet>
    
  • config.xsl

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:xrcs="xrcs:xrcs"
                    xmlns="http://www.w3.org/1999/xhtml">
        <!-- Global variables -->
        <xsl:variable name="site-name" select="'XRCS'" />
        <xsl:variable name="xrcs-url" select="'/XRCS/xrcs'" />
    
        <!-- Extensions -->
        <xsl:import href="extensions/core.xsl" />
        <xsl:import href="extensions/include.xsl" />
        <xsl:import href="extensions/citations.xsl" />
    </xsl:stylesheet>
    
  • extensions/*都是空的<xsl:stylesheet>元素。

当然,我现在知道$xrcs-url几乎没有用,因为导入是在变量之前求值的。但是,Firefox在尝试使用此样式表时会抱怨一些未指定的错误。

另一方面,

此样式表(我已用变量定义替换了导入),效果很好:

  • template.xsl-实际的样式表

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:xrcs="xrcs:xrcs"
                    xmlns="http://www.w3.org/1999/xhtml">
        <xsl:variable name="site-name" select="'XRCS'" />
    
        <!-- DOCTYPE from
             https://stackoverflow.com/a/22302701/522375 -->
        <xsl:output method="xml"
                    doctype-system="about:legacy-compat" />
        <xsl:template match="/">
            <html>
                <head>
                    <title><xsl:value-of select="$site-name" /></title>
                </head>
                <body>
                    <h1><xsl:value-of select="/xrcs:page/xrcs:title" /></h1>
                    <xsl:copy-of select="/xrcs:page/xrcs:content/*" />
                </body>
            </html>
        </xsl:template>
    </xsl:stylesheet>
    

为什么?!

到目前为止,我唯一提出的解释是变量是特定于文件的。如果是这样,我会非常非常烦恼,但是我想我可以为配置定义另一个模式,然后使用该$xrcs-url变量...

我的假设正确吗?这些变量是否特定于文件?我没有找到有关它的文档,并且XSLT规范是W3规范(除非您已经非常了解它,否则很难阅读),所以那里没有任何帮助。

2 个答案:

答案 0 :(得分:1)

全局(顶级)变量以及其他命名声明(例如命名模板)的范围是整个样式表,即所有模块。当模块A导入模块B时,两个模块都可以声明变量V,并且A中的V声明在各处都使用,包括在B中使用(按照规范的语言,A具有更高的导入优先级)。

如果您试图在XSLT中编写一些雄心勃勃的东西,那么我建议您坚持不懈地理解规范。或者,您可能更喜欢Wrox / Wiley的《 XSLT程序员参考》( XSLT程序员参考)-但它涵盖的是XSLT 2.0,而不是1.0,除非可以找到较旧的版本。

我很难理解您的意思是“当然,现在我知道$ xrcs-url几乎是无用的,因为导入是在变量之前求值的。” 导入不被“评估”,它们是用于在编译时构造样式表的声明。我不知道您想使用$ xrcs-url做什么(您的代码似乎没有尝试使用它),原则上似乎完全可以使用,尽管也许不是您的意图(但我不知道)当然是您想要的)。

顺便说一句,这里有一个样式表,其中包含两个模块:有助于正确理解术语。

然后,您说:“但是,Firefox在尝试使用此样式表时抱怨某些未指定的错误。”好吧,可能是在抱怨xsl:import声明在错误的位置。但更重要的是,在浏览器中运行XSLT代码并不是开发和测试的好方法。诊断很糟糕。使用专用的IDE(例如oXygen)会更有效率(您说自己很雄心勃勃)。

答案 1 :(得分:0)

<xsl:import />必须出现在<xsl:stylesheet />的任何其他子元素之前。那是我得到错误的直接原因。

我接受迈克尔·凯(Michael Kay)的回答,因为它实际上是这样说的,即使我错过了它,花了几天的时间自己弄清楚!