是否有一种技术可以将 XSL 转换管道合并为单个转换?

发布于 2024-10-03 18:32:16 字数 405 浏览 2 评论 0原文

我已经编写了一个使用 15 个 XSL 样式表管道的应用程序,并且我开始致力于调整其性能。它被设计为可移植的,因此可以在 Web 浏览器环境和桌面上运行。在桌面上,我认为将样式表作为多个转换的管道分开可能是有意义的,因为这允许每个单独的转换在自己的线程中运行,这在具有多核的 CPU 上非常高效。然而,不仅浏览器环境是单线程的,在大多数浏览器中,暴露给 JavaScript 的 XSL 处理 API 都需要将每个单独转换的结果解析回 DOM 对象,这似乎效率低下。因此,我认为,如果可能的话,在浏览器环境上下文中运行时将所有样式表组合成单个样式表将是有利的。我知道如何使用 exsl:node-set (大多数浏览器支持)来实现这一点,但我不清楚我想象的技术是否可以推广。是否有一种通用技术可以将 XSL 样式表管道转换为单个 XSL 样式表,从而保留完整管道的语义?自动化解决方案将是理想的。

I have written an application which uses a pipeline of 15 XSL stylesheets, and I'm beginning to work on tuning its performance. It's designed to be portable, so that it can be run in both the web browser environment, and on the desktop. On the desktop, I think it may make sense to keep the stylesheets separated out as a pipeline of multiple transformations, as this allows each individual transformation to be run in its own thread, which can be very efficient on CPUs with multiple cores. However, not only is the browser environment is single-threaded, in most browsers, the XSL processing API exposed to JavaScript requires parsing the result of each individual transformation back into a DOM object, which seems inefficient. I think it would therefore be advantageous to combine all of the stylesheets into a single stylesheet when running in the context of the browser environment, if that is possible. I have an idea of how this may be accomplished with exsl:node-set (which most browsers support), but it's not clear to me if the technique I'm imagining is generalizable. Is there a general technique for transforming a pipeline of XSL stylesheets into a single XSL stylesheet, such that the semantics of the complete pipeline are preserved? An automated solution would be ideal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

つ低調成傷 2024-10-10 18:32:16

有一种技术允许将独立的变换链接在一起,其中第 k 个变换的输出是第 (k+1) 个变换的输入。

这是一个简单的示例

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common"
    exclude-result-prefixes="ext xsl">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates select="node()"/>
  </xsl:variable>

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

 <xsl:template match="/*">
     <xsl:copy>
       <xsl:copy-of select="@*"/>
       <one/>
     <xsl:apply-templates/>
     </xsl:copy>
 </xsl:template>

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

 <xsl:template match="/*/one" mode="pass2" >
     <xsl:call-template name="identity"/>
      <two/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时:

<doc/>

想要的结果(第一遍添加元素 作为顶部元素的子元素,然后第二遍添加另一个子元素 ,紧接着在第一遍中创建的元素`)生成

<doc>
   <one/>
   <two/>
</doc>

FXSL中有一个非常合适的模板/函数来执行此操作:这就是compose-flist 模板。它采用初始数据参数和 N 个函数(模板)作为参数,并生成这些函数/模板的链式组合。

这是 FXSL 库的测试示例

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:myFun1="f:myFun1"
xmlns:myFun2="f:myFun2" 
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="xsl f ext myFun1 myFun2"
>
  <xsl:import href="compose.xsl"/>
  <xsl:import href="compose-flist.xsl"/>

  <!-- to be applied on any xml source -->

  <xsl:output method="text"/>
  <myFun1:myFun1/>
  <myFun2:myFun2/>


  <xsl:template match="/">

    <xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/>
    <xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/>
    Compose:
    (*3).(*2) 3 = 
    <xsl:call-template name="compose">
      <xsl:with-param name="pFun1" select="$vFun1"/>
      <xsl:with-param name="pFun2" select="$vFun2"/>
      <xsl:with-param name="pArg1" select="3"/>
    </xsl:call-template>

    <xsl:variable name="vrtfParam">
      <xsl:copy-of select="$vFun1"/>
      <xsl:copy-of select="$vFun2"/>
      <xsl:copy-of select="$vFun1"/>
    </xsl:variable>

    Multi Compose:
    (*3).(*2).(*3) 2 = 
    <xsl:call-template name="compose-flist">
      <xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/>
      <xsl:with-param name="pArg1" select="2"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="myFun1:*" mode="f:FXSL">
    <xsl:param name="pArg1"/>

    <xsl:value-of select="3 * $pArg1"/>
  </xsl:template>

  <xsl:template match="myFun2:*" mode="f:FXSL">
    <xsl:param name="pArg1"/>

    <xsl:value-of select="2 * $pArg1"/>
  </xsl:template>
</xsl:stylesheet>

当此转换应用于任何 xml 文档(未使用)时,会生成所需的正确结果

Compose:
(*3).(*2) 3 = 
18

Multi Compose:
(*3).(*2).(*3) 2 = 
36

执行注意:在 XSLT 2.0 及更高版本中,不需要 xxx:node-set() 扩展,并且任何链式转换都可以包含在实际函数中。

There is a technique that allows independent transformations to be chained together where the output of the k-th transformation is the input of the (k+1)-th transformation.

Here is a simple example:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ext="http://exslt.org/common"
    exclude-result-prefixes="ext xsl">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates select="node()"/>
  </xsl:variable>

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

 <xsl:template match="/*">
     <xsl:copy>
       <xsl:copy-of select="@*"/>
       <one/>
     <xsl:apply-templates/>
     </xsl:copy>
 </xsl:template>

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

 <xsl:template match="/*/one" mode="pass2" >
     <xsl:call-template name="identity"/>
      <two/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document:

<doc/>

the wanted result (the first pass addds the element <one/> as a child of the top element, then the second pass adds another child, , immediately after the element` that was created in the first pass) is produced:

<doc>
   <one/>
   <two/>
</doc>

There is a very suitable template/function in FXSL to do this: this is the compose-flist template. It takes as parameters an initial data argument and N functions (templates) and produces the chained composition of these functions/templates.

Here is the test example from the FXSL library:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:myFun1="f:myFun1"
xmlns:myFun2="f:myFun2" 
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="xsl f ext myFun1 myFun2"
>
  <xsl:import href="compose.xsl"/>
  <xsl:import href="compose-flist.xsl"/>

  <!-- to be applied on any xml source -->

  <xsl:output method="text"/>
  <myFun1:myFun1/>
  <myFun2:myFun2/>


  <xsl:template match="/">

    <xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/>
    <xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/>
    Compose:
    (*3).(*2) 3 = 
    <xsl:call-template name="compose">
      <xsl:with-param name="pFun1" select="$vFun1"/>
      <xsl:with-param name="pFun2" select="$vFun2"/>
      <xsl:with-param name="pArg1" select="3"/>
    </xsl:call-template>

    <xsl:variable name="vrtfParam">
      <xsl:copy-of select="$vFun1"/>
      <xsl:copy-of select="$vFun2"/>
      <xsl:copy-of select="$vFun1"/>
    </xsl:variable>

    Multi Compose:
    (*3).(*2).(*3) 2 = 
    <xsl:call-template name="compose-flist">
      <xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/>
      <xsl:with-param name="pArg1" select="2"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template match="myFun1:*" mode="f:FXSL">
    <xsl:param name="pArg1"/>

    <xsl:value-of select="3 * $pArg1"/>
  </xsl:template>

  <xsl:template match="myFun2:*" mode="f:FXSL">
    <xsl:param name="pArg1"/>

    <xsl:value-of select="2 * $pArg1"/>
  </xsl:template>
</xsl:stylesheet>

when this transformation is applied on any xml document (not used), the wanted, correct result is produced:

Compose:
(*3).(*2) 3 = 
18

Multi Compose:
(*3).(*2).(*3) 2 = 
36

Do note: In XSLT 2.0 and later no xxx:node-set() extension is necessary, and any of the chained transformations can be contained in a real function.

一身骄傲 2024-10-10 18:32:16

One approach is to use modes http://www.w3.org/TR/xslt#modes but you are right that that requires transforming each step into a variable and to use a node-set extension function to be able to apply the next step to the variable contents.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文