【问题标题】:Dynamically decide which XSL stylesheet to use动态决定使用哪个 XSL 样式表
【发布时间】:2010-08-05 17:20:22
【问题描述】:

我正在尝试创建一个站点,该站点(除其他外)将显示包含在 xml 文件中的数据。我正在使用 xsl 样式表来格式化所有内容,但有些页面具有相似的内容。有没有办法告诉 xsl 数据显示在哪里,并让它决定使用哪个布局,而不是用重复的数据制作多个 xml 表。

例子:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">

<xsl:choose>
  <xsl:if test="something">
    <!-- Format data one way -->
  </xsl:if>
  <xsl:otherwise>
    <!-- Format data another way -->
  </xsl:otherwise>
</xsl:choose>

</xsl:template>
</xsl:stylesheet>

该站点托管在一个较大的站点上,该站点不允许其微型站点使用任何服务器端脚本,因此我的选择在这里受到严重限制。

【问题讨论】:

  • 好问题 (+1)。请参阅我的回答,解释“填空”XSLT 设计模式。

标签: html xml xslt


【解决方案1】:

在这种情况下,我使用布局,每个布局都包含在一个单独的 XML 文档中。

要使用的(文件名)布局可以作为参数传递给转换,也可以在转换中动态确定。

从现在开始,可以使用 XSLT document() 函数访问 Layout XML 文档:

<xsl:variable name="vDocLayout" select="document($pLayout)"/>

然后你可以发出:

<xsl:apply-templates select="$vDocLayout"/>

这是“fill in the blanks”XSLT 设计模式

【讨论】:

  • @Dimitre:是的。我使用这种模式,这就是为什么我将链接发布到我的商业网站作为活生生的例子。但是,由于目前浏览器不支持 XPath 2.0,因此您不能使用fn:document-uri() 作为在线传递参数的方式。因此,您必须继续发送具有不同样式表的 PI,至少要声明您的 pLayout 参数,或者将其带有元数据的 uri 添加到您的 XML 文档中(与添加 PI 的任务基本相同)。在数据和布局 URI 之间进行某种内联映射是可能的,但会使网站的动态性降低......
  • @Dimitre:另外,我将这种转换(单独的布局文档和数据文档)称为“人口”,因为它更像是 .Net 中代码隐藏的良好代码实践
  • @Alejandro:仅在客户端处理中使用此设计模式没有任何限制。在服务器端,所有可能的平台都支持将参数传递给转换。
  • @Dimitre:是的,服务器端这是一个选项,但不是 OP:“不允许其微型站点使用任何服务器端脚本”
  • @Alejandro:他知道完整的 URL,并且可以按照惯例将其放在 XSLT 样式表中的特殊元素/属性中。
【解决方案2】:

您可以使用客户端 XSLT。在您的 XML 文档中提供 PI,并在特定样式表中包含主布局样式表。

请随意查看和使用http://www.aranedabienesraices.com.ar作为示例。

EDIT 3:几乎完整的递归示例。

XML 文档“layoutA.xml”:

<html xmlns:inc="include">
    <body>
        <h1>Birthday</h1>
        <dl inc:in-iter="person">
            <dt inc:path="name"></dt>
            <dd inc:path="date"></dd>
        </dl>
    </body>
</html>

输入 XML 文档:

<data>
    <person>
        <name>Bob</name>
        <date>2010-02-23</date>
        <link>http://example.org/bob</link>
    </person>
    <person>
        <name>Alex</name>
        <date>2010-02-23</date>
        <link>http://example.org/alex</link>
    </person>
</data>

样式表:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:inc="include">
    <xsl:param name="pLayout" select="'layoutA.xml'"/>
    <xsl:template match="/">
        <xsl:apply-templates select="document($pLayout)/*">
            <xsl:with-param name="context" select="*"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:param name="context"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:with-param name="context" select="$context"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[@inc:path]">
        <xsl:param name="context"/>
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:with-param name="context" select="$context"/>
            </xsl:apply-templates>
            <xsl:value-of select="$context/*[name()=current()/@inc:path]"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[@inc:in-iter]" priority="1">
        <xsl:param name="context"/>
        <xsl:variable name="me" select="."/>
        <xsl:copy>
            <xsl:apply-templates select="@*">
                <xsl:with-param name="context" select="$context"/>
            </xsl:apply-templates>
            <xsl:for-each select="$context/*[name()=current()/@inc:in-iter]">
                <xsl:apply-templates select="$me/node()">
                    <xsl:with-param name="context" select="."/>
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[@inc:out-iter]" priority="1">
        <xsl:param name="context"/>
        <xsl:variable name="me" select="."/>
        <xsl:for-each select="$context/*[name()=current()/@inc:out-iter]">
            <xsl:element name="{name($me)}" namespace="{namespace-uri($me)}">
                <xsl:apply-templates select="$me/@*|$me/node()">
                    <xsl:with-param name="context" select="."/>
                </xsl:apply-templates>
            </xsl:element>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="@inc:path|@inc:in-iter|@inc:out-iter" priority="1"/>
    <xsl:template match="@inc:*">
        <xsl:param name="context"/>
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="$context/*[name()=current()]"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

输出:

<html xmlns:inc="include">
    <body>
        <h1>Birthday</h1>
        <dl>
            <dt>Bob</dt>
            <dd>2010-02-23</dd>
            <dt>Alex</dt>
            <dd>2010-02-23</dd>
        </dl>
    </body>
</html>

将参数pLayout 传递为'layoutB.xml',并且这个“layoutB.xml”:

<html xmlns:inc="include">
    <body>
        <h1>Friends</h1>
        <ul>
            <li inc:out-iter="person">
                <a inc:href="link" inc:path="name"></a>
            </li>
        </ul>
    </body>
</html>

输出:

<html xmlns:inc="include">
    <body>
        <h1>Friends</h1>
        <ul>
            <li>
                <a href="http://example.org/bob">Bob</a>
            </li>
            <li>
                <a href="http://example.org/alex">Alex</a>
            </li>
        </ul>
    </body>
</html>

注意:您的要求的主要问题是相同的文档限制(因此,相同的文档 URI,没有不同的 PI,没有不同的布局 URI 元数据),这让您只需要 javascript 来传递布局URI 参数。直到浏览器支持 XPath 2.0 fn:document-uri() 才能解析 URL 查询。当然,您可以使用一些扩展(例如 MSXSL script),但很难跨浏览器运行。

【讨论】:

  • 这里的问题是每个 xml 文档仍然只能以一种方式设置样式。我试图没有主布局样式表。
  • @Skunkwaffle:每个 XML 输入文档都可以有自己的样式表,也可以保留一个主样式表(或相同的文档)。检查我的编辑和我的链接
  • 这仍然需要两个不同的 xml 文档。我想要的是拥有 A.xml,使用 master.xsl 或 b.xsl,具体取决于它的显示位置。
  • @Skunkwaffle:“取决于它的展示位置”是什么意思?某种媒体查询?
  • 对不起,我应该早点提到这一点。我在 iframe 中显示 xml 页面。
猜你喜欢
  • 1970-01-01
  • 2012-04-01
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 2012-11-07
  • 2021-12-13
相关资源
最近更新 更多