如何使用XSLT对按顺序排列的xml元素进行分组?

时间:2016-11-19 22:14:51

标签: xslt xslt-1.0

有些示例使用xsl:key对项目进行分组,但那些不适合我的方案。

每一组都有column1 =&#34; H&#34;应该命名为<transaction>,并且所有项目都为column1 =&#34; D&#34;遵循&#34; H&#34;应该在<transaction> <item>内,直到它到达下一个&#34; H&#34;。然后它以相同的规则重复。

问题:这些值用双引号括起来,但输出不应该有双引号。

<root>
    <row>
        <column1>"H"</column1>
        <column2>"2016-09-09"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Conference Services Meeting Package"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Audio Visual Meeting Package"</column2>
    </row>
    <row>
        <column1>"H"</column1>
        <column2>"2016-09-09"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Meeting Package Lunch"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Marinated Roasted Olives</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Mezza Plate Humus with Smoked Paprika Butter"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Pastry Bread Block Loaf Bread"</column2>
    </row>
</root>

输出:

<xml>
    <transaction>
        <item>Conference Services Meeting Package</item>
        <item>Audio Visual Meeting Package</item>
    </transaction>
    <transaction>
        <item>Meeting Package Lunch</item>
        <item>Marinated Roasted Olives</item>
        <item>Mezza Plate Humus with Smoked Paprika Butter</item>
        <item>Pastry Bread Block Loaf Bread</item>
    </transaction>
</xml>

2 个答案:

答案 0 :(得分:3)

此转化

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kFollowing" match='row[column1=&apos;"D"&apos;]' 
          use='generate-id(preceding-sibling::row[column1=&apos;"H"&apos;][1])'/>

  <xsl:template match="/*">
    <xml>
      <xsl:apply-templates select='row[column1=&apos;"H"&apos;]'/>
    </xml>
  </xsl:template>

  <xsl:template match="row">
    <transaction>
      <xsl:apply-templates select="key('kFollowing', generate-id())/column2"/>
    </transaction>
  </xsl:template>

  <xsl:template match="column2">
    <item><xsl:value-of select=
     'concat(translate(substring(.,1,1),&apos;"&apos;,""), 
             substring(.,2, string-length(.) -2),
             translate(substring(.,string-length()),&apos;"&apos;,""))'/></item>
  </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<root>
    <row>
        <column1>"H"</column1>
        <column2>"2016-09-09"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Conference Services Meeting Package"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Audio Visual Meeting Package"</column2>
    </row>
    <row>
        <column1>"H"</column1>
        <column2>"2016-09-09"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Meeting Package Lunch"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Marinated Roasted Olives</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Mezza Plate Humus with Smoked Paprika Butter"</column2>
    </row>
    <row>
        <column1>"D"</column1>
        <column2>"Pastry Bread Block Loaf Bread"</column2>
    </row>
</root>

产生完全正确的结果

<xml>
   <transaction>
      <item>Conference Services Meeting Package</item>
      <item>Audio Visual Meeting Package</item>
   </transaction>
   <transaction>
      <item>Meeting Package Lunch</item>
      <item>Marinated Roasted Olives</item>
      <item>Mezza Plate Humus with Smoked Paprika Butter</item>
      <item>Pastry Bread Block Loaf Bread</item>
   </transaction>
</xml>

<强>解释

  1. ,它定义所有对应的"D" <column2>元素,作为其对应的generate-id()(最近的前一个){{1}的函数} "H"元素。

  2. 将第一个和最后一个字符(仅当它们是引号)<column1>转换为空字符串。因此"被正确处理,即使它没有以引号结尾 - 这很可能是偶然错误。

  3. 没有"Marinated Roasted Olives(甚至嵌套!)指令。

答案 1 :(得分:2)

以这种方式尝试:

XSLT 1.0

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

<xsl:key name="tx" match="row[column1='&quot;D&quot;']" use="generate-id(preceding-sibling::row[column1='&quot;H&quot;'][1])" />

<xsl:template match="/root">
    <xml>
        <xsl:for-each select="row[column1='&quot;H&quot;']">
            <transaction>
                <xsl:for-each select="key('tx', generate-id())">
                    <item>
                        <xsl:value-of select="column2"/>
                    </item>
                </xsl:for-each>
            </transaction>
        </xsl:for-each>
    </xml>
</xsl:template>

</xsl:stylesheet>

这解决了对相邻项目进行分组的问题。删除双引号的问题相当简单,可以使用substring()函数轻松解决。如果您无法使其发挥作用,请发布单独的问题。