代码之家  ›  专栏  ›  技术社区  ›  jbeard4

有没有一种技术可以将XSL转换的管道组合成单个转换?

  •  4
  • jbeard4  · 技术社区  · 15 年前

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

    2 回复  |  直到 15 年前
        1
  •  2
  •   Dimitre Novatchev    15 年前

    有一种技巧 它允许独立的转换链接在一起,其中第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/>
    

    想要的结果 (第一个过程添加元素 <one/> 作为顶层元素的子元素,然后第二个过程添加另一个子元素, , immediately after the element `在第一个通道中创建的) 是生产的 :

    <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() 扩展是必要的,任何链式转换都可以包含在实函数中。

        2
  •  0
  •   Martin Honnen    15 年前

    一种方法是使用模式 http://www.w3.org/TR/xslt#modes 但您是对的,这需要将每个步骤转换为变量,并使用节点集扩展函数来将下一步应用于变量内容。