对同一个 XSL 样式表使用不同的 HTML 模板

Posted

技术标签:

【中文标题】对同一个 XSL 样式表使用不同的 HTML 模板【英文标题】:Using a different HTML template for the same XSL stylesheet 【发布时间】:2012-11-02 21:31:37 【问题描述】:

是否可以为同一个 XSLT 样式表使用不同的 html 布局?

我一直在阅读 XSLT,我看到的大多数示例都表明 HTML 代码实际上嵌入在样式表中。

是否可以为多个 HTML 布局使用相同的样式表? (我的想法类似于 Velocity 的工作方式 - 即可以使用相同的 Velocity 标签处理多个 HTML 文件)。

我正在使用 Java Xalan 处理器来处理 XSLT。

编辑

我尝试了下面的@Dimitre Novatchev 方法,效果很好。 唯一的问题是我将如何处理循环元素?比如xml文档修改为:

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>
 <age>33</age>
 <age>55</age>
</person>

如何遍历每个年龄元素?

这是我在 HTML 模板上尝试过的,但我没有发现任何区别:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.  

  <gen:for-each select="/person/age">
    <gen:age/>,
  </gen:for-each>

 </body>
</html>

预期输出

我希望上面的输出是

Hi JohnSmith!
You are 25 years old. 

25, 33, 55

【问题讨论】:

ziggy,我的回答对你有用还是你还有什么问题? @DimitreNovaatchev - 这非常有用,我只需要弄清楚如何循环遍历多个元素(请参阅我的更新)。 这可以通过添加额外的“gen:”指令来完成。请提供一个完整的例子——我错过了想要的结果。由于我现在要去上班,请期待最早 10 小时后的答复。 @DimitreNovaatchev 基本上我想遍历多个元素。请参阅我期望的示例输出的更新。谢谢 【参考方案1】:

是的,这是一种非常强大的技术,我称之为“填空”。

这是一个非常简短的例子:

骨架 1:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/>!</h1>
 </body>
</html>

骷髅 2:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.
 </body>
</html>

XSLT 转换作为外部参数传递“要使用的骨架”的 Uri,它会“按原样”复制所有节点,但特殊命名的元素除外(其名称位于特殊命名空间“my :转换生成的“)。这些被 XSLT 转换中与它们匹配的模板的结果替换。

以下是此类转换的示例

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:gen="my:tranform-generated" exclude-result-prefixes="gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSkeleton" select="'file:///c:/temp/delete/Skeleton1.xml'"/>

 <xsl:variable name="vData" select="/"/>

 <xsl:template match="/">
  <xsl:apply-templates select="document($pSkeleton)/*"/>
 </xsl:template>

 <xsl:template match="*">
     <xsl:element name="name()">
       <xsl:copy-of select="namespace::*[not(. = 'my:tranform-generated')]"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="name()"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

 <xsl:template match="*[namespace-uri()='my:tranform-generated']">
  <xsl:value-of select="$vData/*/*[name() = local-name(current())]"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于此 XML 文档时

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>
</person>

产生了想要的正确结果(使用 Skeleton1.xml):

<html>
   <body>
      <h1>Hi John!</h1>
   </body>
</html>

当对同一个 XML 文档应用相同的转换,但传递给它的外部参数 $pSkeleton 的值为 "file:///c:/temp/delete/Skeleton2.xml" 时,我们再次得到想要的结果(格式化的 Skeleton2):

<html>
   <body>
      <h1>Hi JohnSmith!</h1>

      You are 25 years old.

   </body>
</html>

更新

这是一个如何处理迭代的示例——按照 OP 的要求:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:gen="my:tranform-generated" exclude-result-prefixes="gen">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSkeleton" select="'file:///c:/temp/delete/Skeleton3.xml'"/>

 <xsl:variable name="vData" select="/"/>

 <xsl:template match="/">
  <xsl:apply-templates select="document($pSkeleton)/*"/>
 </xsl:template>

 <xsl:template match="*">
     <xsl:element name="name()">
       <xsl:copy-of select="namespace::*[not(. = 'my:tranform-generated')]"/>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="name()"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

 <xsl:template match="*[namespace-uri()='my:tranform-generated']">
  <xsl:value-of select="$vData/*/*[name() = local-name(current())]"/>
 </xsl:template>

 <xsl:template match="gen:context" priority="2">
     <xsl:apply-templates>
       <xsl:with-param name="pContext"
         select="$vData/*/*[name()=current()/@select][1]"/>
     </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="gen:iterate" priority="2">
  <xsl:param name="pContext"/>

  <xsl:variable name="vDelim" select="string(@delimiter)"/>

  <xsl:for-each select="$pContext/*[name()= current()/@select]">
   <xsl:if test="not(position()=1)"><xsl:copy-of select="$vDelim"/></xsl:if>
   <xsl:copy-of select="node()"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

Skeleton3.xml:

<html xmlns:gen="my:tranform-generated">
 <body>
  <h1>Hi <gen:fname/> <gen:lname/>!</h1>

  You are <gen:age/> years old.

  Education:
  <gen:context select="education">
    <gen:iterate select="degree" delimiter=", "/>
  </gen:context>
 </body>
</html>

当上述转换应用于此 XML 文档时:

<person>
 <fname>John</fname>
 <lname>Smith</lname>
 <age>25</age>

 <education>
  <degree>MSc. Biology</degree>
  <degree>MBa.</degree>
  <degree>PhD. Computer Science</degree>
 </education>
</person>

产生想要的正确结果

<html>
   <body>
      <h1>Hi JohnSmith!</h1>

      You are 25 years old.

        Education:
        MSc. Biology, MBa., PhD. Computer Science
   </body>
</html>

【讨论】:

谢谢 - 这看起来像我需要的,但我不明白它是如何工作的。这种技术叫什么,因为我需要谷歌它并尝试了解它是如何工作的。谢谢你,因为你给了我一个很好的起点。 我正在尝试一个简单的例子,看看我是否可以让上面的工作。对 file:///c:/temp/delete/Skeleton1.xml 的引用是否正确还是应该引用 Skeleton1.html @ziggy,你是决定放置每个骨架文件的人 - 在我的情况下,我将所有对我的工作文件不重要的文件放在 c:\temp\delete 中。至于技术,是我自己发现的,之前没见过用过——当然这不代表其他人不知道。 我已经测试了上述内容并且它有效。请查看原始帖子的更新,因为我无法让循​​环工作。 @ziggy,这可以通过添加额外的“gen:”指令来完成。请提供一个完整的例子——我错过了想要的结果。由于我现在要去上班,请期待最早在 10 小时后得到答复。【参考方案2】:

是的,这是可能的。您可以在 xsl:if 标签中包围 html 块

例如:

<xsl:if test="value &gt; 75000"><p>Print out this html</p></xsl:if>

【讨论】:

以上是关于对同一个 XSL 样式表使用不同的 HTML 模板的主要内容,如果未能解决你的问题,请参考以下文章

使用参数作为 XSL 选择语句的参数

如何使用 XSL 生成 HTML 文件?

为啥 XSL 样式表显示没有 XML(信息/值)的 html 表

使用 XSL 样式表 Java Transformer Factory 对 XMLTag 进行排序

预处理 XSL 样式表 - 包括外部文档

ui-template