【问题标题】:Make an XSLT result document be processed by a “parent” XSLT document, recursively使 XSLT 结果文档由“父”XSLT 文档递归处理
【发布时间】:2012-08-14 16:15:22
【问题描述】:

我有一个文件grandchild.xml,它用granchild.xsl处理后的结果必须转发到child.xsl,然后必须由parent.xsl最终处理并输出。

我已尝试将xml-stylesheet 元素添加到结果文档中,希望它被引用的 XSL 样式表处理,但没有任何反应。

完成这项任务的正确声明是什么?我在网上搜索了很多,没有结果。

【问题讨论】:

  • 如果我理解正确(您希望浏览器能够使用 XSLT 递归处理生成的 XML),那么我认为您不走运。套用我在 SO 上看到的一句话,浏览器没有看过《盗梦空间》,也不知道如何“更深入”
  • 你理解得很好,我什至搜索了“XSL Inception”,哈哈。然后,如果不可能的话,我真的看不出 XSLT 与将 HTML 内容作为字符串插入服务器端相比有什么真正有用或有效的使用。或者也许我并没有真正理解 XSLT 的意义?
  • XML 的 XSLT 转换有很多用途,我们在生成特定的 HTML 位时到处使用它……它是一种非常强大的语言
  • 始终可以在浏览器中执行单次、多遍转换。您有兴趣查看代码示例吗?
  • @DimitreNovaatchev 是否​​解决了我最初的请求?我不确定。

标签: xml xslt


【解决方案1】:

以下是浏览器中的多通道转换示例

让我们拥有这个 XML 源文档

<?xml-stylesheet title="XSL_formatting"
  type="text/xsl" href="MultiPassBrowser.xsl"?>
<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

让我们进行这两个 XSLT 转换

MultiPassBrowser1.xsl

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

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num/text()">
  <xsl:value-of select=". *2"/>
 </xsl:template>
</xsl:stylesheet>

MultiPassBrowser2.xsl

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

 <xsl:template match="node()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num" mode="pass2">
  <p><xsl:value-of select=". +1"/></p>
 </xsl:template>
</xsl:stylesheet>

第一个转换“按原样”复制 XML 文档,但每个 num 元素的字符串值乘以 2。

第二个转换“按原样”复制 XML 文档,但每个 num 元素的字符串值递增。

如果将第二个转换应用于第一个转换的结果,则从初始 num 元素获得的最终值必须是 3、5、7、...、21。

以下是将这两者粘合在一起的转换

MultiPassBrowser.xsl

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
 exclude-result-prefixes="ext msxsl">
 <xsl:import href="file:///C:/Temp/delete/MultiPassBrowser1.xsl"/>
 <xsl:import href="file:///C:/Temp/delete/MultiPassBrowser2.xsl"/>
 <xsl:output method="html"/>
 <xsl:strip-space elements="*"/>

 <msxsl:script language="JScript" implements-prefix="ext">
     this['node-set'] =  function (x) {
      return x;
      }
 </msxsl:script>

 <xsl:template match="/">
  <html>
      <xsl:variable name="vrtfPass1">
        <xsl:apply-templates select="/*"/>
      </xsl:variable>

      <xsl:apply-templates select="ext:node-set($vrtfPass1)/*/*"
                           mode="pass2"/>
  </html>
 </xsl:template>
</xsl:stylesheet>

当使用 IE、Firefox、Safari 和 Opera 打开 XML 文件时,结果是正确的,预期的结果

<html>
   <p>3</p>
   <p>5</p>
   <p>7</p>
   <p>9</p>
   <p>11</p>
   <p>13</p>
   <p>15</p>
   <p>17</p>
   <p>19</p>
   <p>21</p>
</html>

解释

  1. 主要样式表模块(XML 文档 PI 中引用的那个)导入包含单独转换的两个样式表模块。

  2. 第一次转换的结果被捕获在变量$vrtfPass1中。

  3. 在 XSLT 1.0 中,此类变量属于臭名昭著的“RTF”(结果树片段)类型,不能直接操作(只能在 RTF 上使用复制和 string() 函数)。这里我们使用xxx:node-set() 扩展函数的一个可移植变体,它在IE 和其他四种主要浏览器中都可以使用。 这个可移植的扩展最初是由@DavidCarlisle 提出的,原文可以在his blog中找到。

  4. 模式“pass2”中的模板然后应用于节点集,我们在上面的步骤中将 RTF 变量转换为该节点集。第二个导入的样式表模块中的所有模板都处于“pass2”模式,因此它们被选中执行。

  5. 产生最终结果。

【讨论】:

  • 我喜欢它,并且几乎完全理解它;-) 它仍然不是 OP 所要求的(我仍然认为这是不可能的),但它是一个很好的选择。 +1
  • @freefaller,如果有数十或数百个转换要链接,这非常方便,使用 FXSL 模板compose-flist。你可以在这里看到它:fxsl.cvs.sourceforge.net/viewvc/fxsl/fxsl-xslt2/Tests/…
【解决方案2】:

除非有人知道得更清楚,否则我相信在浏览器上递归处理 XSLT 输出的能力是不可能的。

为了证明这一点,我刚刚在 IE8、FF14 和 Chrome 中尝试了以下...

level1.xml

<?xml version="1.0" encoding="utf-8" ?> 
<?xml-stylesheet title="XSL_formatting" type="text/xsl" href="level1.xsl"?>
<data>
  <id>Level 1 data</id>
</data>

level1.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
     <?xml-stylesheet title="XSL_formatting" type="text/xsl" href="level2.xsl"?>
     <data2>
       <id2>Level 2: <xsl:value-of select="/data/id"/></id2>
     </data2>
   </xsl:template>   
</xsl:stylesheet>

level2.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:template match="/">
     <html>
       <body>
         <b>Level 3:</b> <xsl:value-of select="/data2/id2"/>
       </body>
     </html>
   </xsl:template>   
</xsl:stylesheet>

所有 3 个浏览器的结果都只是显示Level 2: Level 1 Data

【讨论】:

  • 这种行为是否特定于 Web 浏览器,或者我可以期待服务器端 XSLT 实现的相同行为吗?
  • @user,我非常希望服务器端也能做到这一点......虽然很明显,在服务器端,您可以检查转换的结果输出,如有必要,再针对另一个运行它XSLT
  • 正是我所期待的,你刚刚证实了我的想法,我现在想我会做什么。感谢您的宝贵时间。
  • 不客气@user,祝你项目的其余部分好运:-)
  • @freefaller,但总是可以在浏览器中执行单次、多遍转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 2011-02-18
相关资源
最近更新 更多