在XSLT中嵌套for-each

时间:2013-09-21 07:53:59

标签: xslt

我对XSLT没有多少经验。我需要你的帮助来为下面的xml准备正确的XSL转换。我有像

这样的XML
<message>
<requisition>
    <data-values>
        <data-value multi-valued="false">
            <name>Test_Grid-1.Name</name>
            <value>1</value>
        </data-value>
        <data-value multi-valued="false">
            <name>Test_Grid-1.SupportType</name> 
            <value>Monthly,Quarterly</value>
        </data-value>
        <data-value multi-valued="false">
            <name>Test_Grid-1.Status</name>
            <value>New</value>
        </data-value>
        <data-value multi-valued="false">
            <name>Test_Grid-2.Name</name>
            <value>2</value>
        </data-value>
        <data-value multi-valued="false">
            <name>Test_Grid-2.SupportType</name> 
            <value>Monthly</value>
        </data-value>
        <data-value multi-valued="false">
            <name>Test_Grid-2.Status</name>
            <value>Existing</value>
        </data-value>
    </data-values>
</requisition>
<agent-parameter multi-valued="false">
    <name>ActionType</name>
    <value>New</value>
</agent-parameter>
<agent-parameter multi-valued="false">
    <name>Dictionary</name>
    <value>Test_Grid</value>
</agent-parameter>
<agent-parameter multi-valued="false">
    <name>ActionName</name>
    <value>SupportData</value>
</agent-parameter>
</message>

我想像这样准备XML:

<ext:message>
<ext:record>
    <ext:name>SupportData</ext:name>
    <ext:rowData>
        <ext:rowAttribute name="Name">1</ext:rowAttribute>
        <ext:rowAttribute name="SupportType">Monthly,Quarterly</ext:rowAttribute>
        <ext:rowAttribute name="Status">New</ext:rowAttribute>
    </ext:rowData>
</ext:record>
<ext:record>
    <ext:name>SupportData</ext:name>
    <ext:rowData>
        <ext:rowAttribute name="Name">2</ext:rowAttribute>
        <ext:rowAttribute name="SupportType">Monthly</ext:rowAttribute>
        <ext:rowAttribute name="Status">Existing</ext:rowAttribute>
    </ext:rowData>
</ext:record>

请你帮我解决XSL转换问题。非常感谢您的支持。

2 个答案:

答案 0 :(得分:0)

这样的东西
<xsl:for-each select="data-value[position() mod 3 = 1]">
<ext:Record>
  <ext:name>...</ext:name>
  <ext:rowData>
    <ext:rowAttribute name="Name"><xsl:value-of select="substring(substring-after(name, 'Test-Grid_'), 1, 1)"/></ext:rowAttribute>
    <ext:rowAttribute name="SupportType"><xsl:value-of select="following-sibling[1]/value"/></ext:rowAttribute>
    <ext:rowAttribute name="Status"><xsl:value-of select="following-sibling[2]/value"/></ext:rowAttribute>
   </ext:rowData>
 </ext:Record>
</xsl:for-each>

答案 1 :(得分:0)

这可以被视为分组问题。你有顺序元素,但你希望通过 name 元素(或者更确切地说, name 元素的一部分)在完全停止之前对它们进行分组,我假设这是逻辑)。在XSLT 1.0中,您通常会使用一种名为Muenchian Grouping的技术来执行此操作。

首先,定义一个按相关名称“分组”数据值元素的键。

<xsl:key name="record" match="data-value" use="substring-before(name, '.')" />

因此,对于给定名称,例如“Test_Grid-2”,该键将包含记录中所需的所有元素。

要开始输出记录,您首先必须查看所有数据值元素,但只选择键中首先出现的给定“名称”元素。元素比较使用'generate-id()'方法完成,因此表达式如下所示:

<xsl:apply-templates 
     select="requisition/data-values/data-value
     [generate-id() = 
        generate-id(key('record', substring-before(name, '.'))[1])]" mode="record" />

(这里的模式是因为最终的XSLT将有两个匹配数据值的模板,所以这将区分它们。)

然后,在匹配不同数据值元素的模板中,您将获得记录的所有元素,如此

<xsl:apply-templates select="key('record', substring-before(name, '.'))" />

有一点需要注意,您的预期输出是使用命名空间前缀'ext',但您没有显示前缀的声明。 (可能是因为你只是简化了你的例子),但实际上我希望输出像这样开始:

<ext:message xmlns:ext="http://mylovelynamespace.com">

无论如何,试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="ext">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="record" match="data-value" use="substring-before(name, '.')" />

   <xsl:template match="message">
      <ext:message>
         <xsl:apply-templates select="requisition/data-values/data-value[generate-id() = generate-id(key('record', substring-before(name, '.'))[1])]" mode="record" />
      </ext:message>
   </xsl:template>

   <xsl:template match="data-value" mode="record">
      <ext:record>
         <ext:name>SupportData</ext:name>
         <xsl:apply-templates select="key('record', substring-before(name, '.'))" />
      </ext:record>
   </xsl:template>

   <xsl:template match="data-value">
      <ext:rowAttribute name="{substring-after(name, '.')}"><xsl:value-of select="value" /></ext:rowAttribute>
   </xsl:template>
</xsl:stylesheet>

在XSLT 2.0中,您可以使用 xsl:for-each-group 结构来简化分组。