使用XSLT

时间:2017-07-12 21:42:00

标签: xslt xpath

我正在使用带有几个XML文件的XSLT来生成我的网页。我希望能够在我的XML中添加一个<widget name="example" />小部件标记,它将小部件插入到html中的相应位置。此小部件也由XML文件定义,该文件定义其html内容和其他信息。

这很顺利,但现在小部件需要一个或多个脚本,它定义为

<scripts>
    <script>jquery<script>
    <script>animation</script>
</scripts>

我想将此脚本添加到html的head标记中,而不是在整个地方散布脚本标记。我使用的当前方法如下:我构建我的页面并将其放入变量,如:

<xsl:template match="/">
    <xsl:variable name="document">
        <html>
            <head>
                <title><xsl:value-of select="page/title" /></title>
                <xsl:apply-templates select="/page/scripts" mode="content" />
                <xsl:apply-templates select="/page/sheets" mode="content" />
            </head>
            <body>
                <div class="header">
                    <h1><xsl:value-of select="page/title" /></h1>
                </div>
                <xsl:apply-templates select="$menu/menu" mode="menu" />
                <div class="content">
                    <xsl:apply-templates select="page/content/*" mode="content" />
                </div>
            </body>
        </html>
    </xsl:variable>
    <xsl:apply-templates select="exsl:node-set($document)" mode="collect-resources" />
</xsl:template>

这会将scripts标记留在原处。在此之后,我打电话给

<xsl:apply-templates select="exsl:node-set($document)" mode="collect-resources" />

导致以下模板:

<xsl:template match="head" mode="collect-resources">
    <xsl:for-each select="..//scripts">
        <xsl:apply-templates select="current()/*" mode="scripts" /> <!-- Convert the scripts defined in this scripts tag into proper HTML script tags. -->
    </xsl:for-each>
</xsl:template>

<xsl:template match="scripts" mode="collect-resources" /> <!-- Remove all scripts tags. -->

<xsl:template match="node()" mode="collect-resources">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="./node()" mode="collect-resources"/>
    </xsl:copy>
</xsl:template>

其中两次遍历整个文档:一次收集所有脚本标记以将脚本放入标题中,第二次删除所有scripts标记。

对于较大的文档,这变得非常慢,并且有点脏。有没有办法做到更整洁和/或更快?

附录I - widget.xml

<widget>
    <scripts>
        <script>/widgets/example/main</script>
    </scripts>
    <content>
        <div class="example-widget" />
    </content>
</widget>

附录II - template.xsl

<xsl:template match="widget" mode="content">
    <xsl:variable name="path">../widgets/<xsl:value-of select="@name" />/widget.xml</xsl:variable> <!-- The path to the widget xml -->
    <xsl:variable name="widget" select="document($path)"/>
    <xsl:element name="div">
        <xsl:attribute name="class">widget</xsl:attribute>
        <xsl:apply-templates select="$widget/widget/scripts" mode="content" /> <!-- Copy the widget script information. -->
        <xsl:apply-templates select="$widget/widget/content/*" mode="content" /> <!-- Copy the widget contents. -->
    </xsl:element>
</xsl:template>

<xsl:template match="node()" mode="content"> <!-- Copy anything that is not a widget. -->
    <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates select="./node()" mode="content" />
    </xsl:copy>
</xsl:template>

1 个答案:

答案 0 :(得分:1)

似乎在你的

里面
        <head>
            <title><xsl:value-of select="page/title" /></title>
            <xsl:apply-templates select="/page/scripts" mode="content" />
            <xsl:apply-templates select="/page/sheets" mode="content" />
        </head>

您希望确保直接处理任何widget及其链接脚本,例如

        <head>
            <title><xsl:value-of select="page/title" /></title>
            <xsl:apply-templates select="/page/scripts" mode="content" />
            <xsl:apply-templates select="//widget" mode="script"/>
            <xsl:apply-templates select="/page/sheets" mode="content" />
        </head>

<xsl:template match="widget" mode="script">
    <xsl:variable name="path">../widgets/<xsl:value-of select="@name" />/widget.xml</xsl:variable> <!-- The path to the widget xml -->
    <xsl:variable name="widget" select="document($path)"/>
    <xsl:apply-templates select="$widget/widget/scripts" mode="scripts" /> 
</xsl:template>

然后在另一个模板中,您将不输出脚本

<xsl:template match="widget" mode="content">
    <xsl:variable name="path">../widgets/<xsl:value-of select="@name" />/widget.xml</xsl:variable> <!-- The path to the widget xml -->
    <xsl:variable name="widget" select="document($path)"/>
    <xsl:element name="div">
        <xsl:attribute name="class">widget</xsl:attribute>
        <xsl:apply-templates select="$widget/widget/content/*" mode="content" /> <!-- Copy the widget contents. -->
    </xsl:element>
</xsl:template>

你必须衡量这是否表现更好。