2010-05-04 51 views
1

XSL中有更新全局变量的方法吗?在XSL中更新变量

我想检查我已经转换的元素并采取相应的行动。这需要我以某种方式将元素的名称添加到某种列表中,并在每次转换新元素时更新它。

但是由于xsl:variable在人们所期望的意义上不是“可变的”,所以一旦它被定义,我就无法向它添加任何东西。

我有多个包含的数据文件,所以使用只知道当前节点集的xsl函数将无济于事。

==编辑==

这就是我的转换现在看起来像。但它会包含每次在不同子文件中重复引用的文件。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output method="xml" /> 

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

    <!-- include the contents of referenced files --> 
    <xsl:template match="reference"> 
     <xsl:apply-templates select="document(@url)/data/node()" /> 
    </xsl:template> 

</xsl:transform> 

而数据文件将是这个样子:

<data> 
    <reference url="another_data_file.xml"/> 
    ... other stuff ... 
</data> 
+2

如果不知道更多关于您要做什么的细节,很难给出建议。可能你并没有试图通过“XSLT方式”解决问题。也许你可以发布一个最小的输入和输出文档? – 2010-05-04 10:17:30

+0

嘿,你绝对没有在这里定义一个问题。请指出你的问题!这是一个定义不明的问题的例子。 – 2010-05-04 13:15:32

+0

第一句话中的问题如何? – Stroboskop 2010-05-04 13:27:32

回答

7

XSLT是一种功能语言,不允许更新变量。如果您需要通过几个步骤来汇总结果,通常的方法是使用递归模板。例如:

<xsl:template name="transform-elements"> 
    <xsl:param name="elements-to-process" select="/.."/> 
    <xsl:param name="processed-elements" select="/.."/> 
    <xsl:if test="$elements-to-process"> 
     <xsl:variable name="element" select="$elements-to-process[1]"/> 

     <!-- ... Do stuff with $element ...--> 

     <!-- Recursively invoke template for remaining elements --> 
     <xsl:call-template name="transform-elements"> 
      <xsl:with-param name="elements-to-process" 
          select="$elements-to-process[position() != 1]"/> 
      <xsl:with-param name="processed-elements" 
          select="$processed-elements|$element"/> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
+0

我现在很忙,但我会尝试。 – Stroboskop 2010-05-06 09:38:40

1

可悲的是,没有一个直接的方式,XSL的变量赋值只有一次,但可以有条件地分配。

但是,块中定义的变量只能访问该块及其子元素,可能会颠倒您的逻辑并反复进行迭代工作。

这样,您就无法处理已经转换的东西,因为它已经完成。

查看xsl:Key和xsl:for-each的用法,这可以让您订购变换的节点。

从W3Schools的引用,使用此XML:

<persons> 
    <person name="Tarzan" id="050676"/> 
    <person name="Donald" id="070754"/> 
    <person name="Dolly" id="231256"/> 
</persons> 

这XSL:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:key name="preg" match="person" use="@id"/> 

<xsl:template match="/"> 
    <html> 
    <body> 
    <xsl:for-each select="key('preg','050676')"> 
    <p> 
    Id: <xsl:value-of select="@id"/><br /> 
    Name: <xsl:value-of select="@name"/> 
    </p> 
    </xsl:for-each> 
    </body> 
    </html> 
</xsl:template> 

</xsl:stylesheet> 

会发现人与 '050676' 的ID。 也许用更多定义的键使用这种方法会给你你需要的结构?

+0

这将工作,如果我只有一个文件。 我的主要问题似乎是,我试图解决递归包含的数据只有一次,即没有一组节点,我可以查询获取我需要的列表。 – Stroboskop 2010-05-04 10:36:09

+0

啊,你了;这些XML文件中的一些是否也包含重复节点? 想到编写一个外部脚本/程序来编程转换Xml(在C#/ IronPython中使用XslCompiledTransform类f.ex)并使用XSL:参数? 这样,您可以加载每个XML文件,使用XPath来获取每个逻辑块进行转换,并递归组合结果。 这有点混乱,但它可能只是工作。 – 2010-05-04 10:48:05

+0

文件本身没有重复的节点,但可以从几个不同的文件中引用包含的文件,这些文件都被另一个文件引用。因此,在收集所有参考文献的过程中,我可能会多次使用同一个对象。 我可以尝试预解析引用结构,并创建我在XSL之外需要的列表。但是,我可以在XSL之外进行整体聚合... – Stroboskop 2010-05-04 11:02:41

1

如果您的输入数据分布在多个文档中,将转换过程分成几个步骤可能是一个好主意。

添加一个预处理转换,将输入文档中的相关部分拖入单个中间文档。然后可以使用简单的XSLT来转换此文档,并且您可能不会遇到当前面临的问题。

+0

听起来好像它可以工作。我可以使用文件而不是变量。 – Stroboskop 2010-05-04 13:29:10

0

我不确定要解析的文档大小,但作为相对较小XML文档的解决方案,您可以将结果输出到变量并应用扩展功能node-set(from exslt或msxsl等)将变换应用于变量的内容,不包括重复节点,就像处理单个XML文档一样。