2011-07-03 42 views
4

我想处理有哪几种不同的状态组像XSLT和临时文件

<root> 
<childgroup>16</childgroup> 
<setstate>init</setstate> 
<child1>...</child1> 
<child2>...</child2> 
<setstate>process<setstate> 
<child2>...</child2> 
<child3>...</child3> 
..... 
<childgroup>17</childgroup> 
... 

一个XML文件我需要的其实是得到类似

<childgroup no="16"> 
    <state statename="init"> 
    <child1>...</child1> 
    <child2>...</child2> 
    </state> 
    <state statename="process"> 
    <child2>...</child2> 
    <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="17"> 
... 

我已经做了简单的一部分并将“chgrpno”属性和stateid属性添加到所有子项(它使所有元素的副本,但是子组和副本的状态,将属性添加到这两个元素中)

<xsl:template match="/"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:template> 

这样做的结果是,所有的孩子都有属性,所以我可以在下一关重新组合它们,并且州有数字,所以我以后可以做同样的事情。但是,试图跟随M.Kay的例子有“临时文件”当我尝试做

<xsl:variable name="nmb"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

<xsl:template match="/"> 
    <xsl:copy-of select="$nmb"/> 
</xsl:template> 

那么它只是返回原来的我,我在第一遍的所有变化都没有了。那么我在这里做错了什么?

我明确地使用了XSLT 1.0,而不是XSLT 2.0。

(编辑:当然我命名变量,忘记复制它在这里)。

+0

问得好,+1。查看我的答案,了解XSLT 1.0中必需的RTF转换为临时树的解释。此外,还提供了两遍XSLT 1.0处理的完整代码示例。 –

回答

3

以下是一个示例,说明如何在一步中使用XSLT 1.0进行分组;样式表

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:output indent="yes"/> 

    <xsl:key name="k1" match="root/*[not(self::childgroup)]" 
    use="generate-id(preceding-sibling::childgroup[1])"/> 

    <xsl:key name="k2" match="root/*[not(self::childgroup) and not(self::setstate)]" 
    use="concat(generate-id(preceding-sibling::childgroup[1]), '|', generate-id(preceding-sibling::setstate[1]))"/> 

    <xsl:template match="root"> 
    <xsl:copy> 
     <xsl:apply-templates select="childgroup"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="childgroup"> 
    <childgroup no="{.}"> 
     <xsl:apply-templates select="key('k1', generate-id())[self::setstate]"/> 
    </childgroup> 
    </xsl:template> 

    <xsl:template match="setstate"> 
    <state statename="{.}"> 
     <xsl:copy-of select="key('k2', concat(generate-id(preceding-sibling::childgroup[1]), '|', generate-id()))"/> 
    </state> 
    </xsl:template> 

</xsl:stylesheet> 

将输入样本

<root> 
    <childgroup>16</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>17</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
</root> 

<root> 
    <childgroup no="16"> 
     <state statename="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
     </state> 
     <state statename="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
     </state> 
    </childgroup> 
    <childgroup no="17"> 
     <state statename="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
     </state> 
     <state statename="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
     </state> 
    </childgroup> 
</root> 
+0

+1一个很好的答案。 –

0

你应该命名你的变量,然后你可以复制它

<xsl:variable name="rtf1"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

<xsl:template match="/"> 
    <xsl:copy-of select="$rtf1"/> 
</xsl:template> 

使用XSLT 1.0,如果你不想给变量的内容,而不是与复制和拷贝要处理它与应用的模板,那么你需要的扩展功能就像exsl:node-set例如

<xsl:variable name="rtf1"> 
    <xsl:apply-templates mode="numb"/> 
</xsl:variable> 

<xsl:template match="/"> 
    <xsl:apply-templates select="exsl:node-set($rtf1)/node()"/> 
</xsl:template> 
+0

这正是我的问题:就像你给的代码是在书凯的临时结果,它不工作 - 我要是<应用模板>里面的我获得理想的结果,但我这样做的变量中时,像你这样的建议,我在“麻木”模式所做的修改都将丢失。 – Konstantin

+0

考虑后最小但完整和真实样本使我们能够重现问题。 –

2

在多遍处理的关键一点与XSLT 1.0是包含第一个的结果的变量pass并不包含一个XML文档(树)。

该变量包含RTF(结果树片段)。 RTF仅在XSLT 1.0中定义。只能使用RTF完成的操作是<xsl:copy-of><xsl:value-of>或将它作为参数传递 - 任何将RTF视为字符串的东西。

根据定义,任何尝试使用带有位置测试的XPath表达式的RTF内部 - 都必须失败。

解决方法是使用扩展函数,通常命名为xxx:node-set()(但Xalan使用名称“nodeset”no dash),其中"xxx:"前缀绑定到特定的实现定义XSLT处理器。正如Martin Honnen所建议的,为了达到某种程度的可移植性,每当由特定的XSLT处理器实现时,都应该尝试使用EXSLT common:nodeset()扩展。

这里是XSLT 1.0两遍的处理的例子:

<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: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[not(. mod 2)]"/> 

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

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

<xsl:template match="num" mode="pass2"> 
<x> 
    <xsl:apply-templates/> 
</x> 
</xsl:template> 
</xsl:stylesheet> 

当该XML文档上施加:

<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> 

这种转变在第一遍产生过滤树,其中只有num元件具有奇数值都存在。然后第二次通过重命名每num元件x。最终的结果是:

<nums> 
    <x>01</x> 
    <x>03</x> 
    <x>05</x> 
    <x>07</x> 
    <x>09</x> 
</nums> 
1

另一个(单通)可能的方法(不是说简单的一个)是:

  • 复制节点集作为变量
  • 使用变量引用的基础上同一组递归
的相邻兄弟姐妹交叉节点集的谓词
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output indent="yes"/> 
    <xsl:template match="text()"/> 

    <xsl:template match="*" mode="childx"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="childgroup"> 
     <xsl:variable name="fw" select="following-sibling::*"/> 
     <childgroup no="{.}"> 
      <xsl:variable name="fwrw" 
       select="$fw[self::childgroup][1] 
       /preceding-sibling::*"/> 
      <xsl:apply-templates select="following-sibling::*[ 
       count(. | $fwrw) = count($fwrw) 
       or count($fwrw)=0] 
       [self::setstate] " mode="setstate"/> 
     </childgroup> 
    </xsl:template> 

    <xsl:template match="setstate" mode="setstate"> 
     <xsl:variable name="fw" select="following-sibling::*"/> 
     <state name="{.}"> 
      <xsl:variable name="fwrw" 
       select="$fw[ self::setstate or self::childgroup ][1]/ 
       preceding-sibling::*"/> 
      <xsl:apply-templates select="following-sibling::*[ 
       count(. | $fwrw) = count($fwrw) 
       or count($fwrw) = 0]" mode="childx"/> 
     </state> 
    </xsl:template> 
</xsl:stylesheet> 

当下面的XML应用:

<root> 
    <childgroup>16</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>17</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>18</childgroup> 
    <childgroup>19</childgroup> 
    <setstate>init</setstate> 
    <child1>...</child1> 
    <child2>...</child2> 
    <setstate>process</setstate> 
    <child2>...</child2> 
    <child3>...</child3> 
    <childgroup>20</childgroup> 
</root> 

产地:

<childgroup no="16"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="17"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="18"/> 
<childgroup no="19"> 
    <state name="init"> 
     <child1>...</child1> 
     <child2>...</child2> 
    </state> 
    <state name="process"> 
     <child2>...</child2> 
     <child3>...</child3> 
    </state> 
</childgroup> 
<childgroup no="20"/>