分组元素和删除重复节点 - XSLT 1.0

时间:2011-02-21 15:14:17

标签: xslt xslt-grouping

我看过Muenchian Grouping - group within a node, not within the entire document,但对我来说不太合适。 Muenchian方法本身并不适合我。

我也查看了XSLT 1.0: grouping and removing duplicate,但无法完全遵循它。

我有以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<MT_MATERIALDATA>
<items item="475053">
    <Recordset>
        <CodeBusinessUnit>99</CodeBusinessUnit>
        <PriceValue>250</PriceValue>
    </Recordset>
    <Recordset>
        <CodeBusinessUnit>1</CodeBusinessUnit>
        <PriceValue>250</PriceValue>
    </Recordset>
</items>
<items item="475054">
    <Recordset>
        <CodeBusinessUnit>1</CodeBusinessUnit>
        <PriceValue>255.34</PriceValue>
    </Recordset>
    <Recordset>
        <CodeBusinessUnit>10</CodeBusinessUnit>
        <PriceValue>299</PriceValue>
    </Recordset>
</items>
</MT_MATERIALDATA>

结果应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<MT_MATERIALDATA>
<Mi item="475053">
    <PriceList>
        <Prices>
            <Price Value="250"/>
            <PriceConfig>
                <Stores>99,1</Stores>
            </PriceConfig>
        </Prices>
    </PriceList>
</Mi>
<Mi item="475054">
    <PriceList>
        <Prices>
            <Price Value="255.34"/>
            <PriceConfig>
                <Stores>1</Stores>
            </PriceConfig>
        </Prices>
        <Prices>
            <Price Value="299"/>
            <PriceConfig>
                <Stores>10</Stores>
            </PriceConfig>
        </Prices>
    </PriceList>
</Mi>
</MT_MATERIALDATA>

因此匹配<PriceValue>元素 在<Recordset>中,所有相应的<CodeBusinessUnits>都需要列在<Stores>中。 如果没有,则需要创建额外的<Prices>节点。

我已经尝试了几个小时,但是Store-number总是重复,或者即使PriceValue相同也不会聚合。我感谢任何帮助,我不知道该怎么办。谢谢你的帮助!

祝你好运, 彼得

3 个答案:

答案 0 :(得分:1)

我认为以下问题解决了这个问题,至少对于分组来说是这样的:

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

  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="k1" match="items/Recordset" use="concat(generate-id(..), '|', PriceValue)"/>

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

  <xsl:template match="items">
    <Mi item="{@item}">
      <PriceList>
        <xsl:apply-templates select="Recordset[generate-id() = generate-id(key('k1', concat(generate-id(..), '|', PriceValue))[1])]"/>
      </PriceList>
    </Mi>
  </xsl:template>

  <xsl:template match="Recordset">
    <Prices>
      <Price Value="{PriceValue}"/>
      <PriceConfig>
        <Stores>
          <xsl:apply-templates select="key('k1', concat(generate-id(..), '|', PriceValue))/CodeBusinessUnit"/>
        </Stores>
      </PriceConfig>
    </Prices>
 </xsl:template>

 <xsl:template match="CodeBusinessUnit">
   <xsl:if test="position() &gt; 1">,</xsl:if>
   <xsl:value-of select="."/>
 </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

此转化:

<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="kPriceByValAndItem" match="PriceValue"
  use="concat(../../@item, '|', .)"/>

 <xsl:template match="/*">
  <MT_MATERIALDATA>
   <xsl:apply-templates/>
  </MT_MATERIALDATA>
 </xsl:template>

 <xsl:template match="items">
  <MI item="{@item}">
   <PriceList>
     <xsl:for-each select=
      "*/PriceValue
          [generate-id()
          =
           generate-id(key('kPriceByValAndItem',
                           concat(../../@item, '|', .)
                           )[1]
                       )
           ]
      ">
       <Prices>
        <Price Value="{.}"/>
        <PriceConfig>
          <Stores>
            <xsl:for-each select=
            "key('kPriceByValAndItem',
                           concat(../../@item, '|', .)
                           )">
             <xsl:value-of select="../CodeBusinessUnit"/>
             <xsl:if test="not(position()=last())">,</xsl:if>
            </xsl:for-each>
          </Stores>
        </PriceConfig>
       </Prices>
     </xsl:for-each>
   </PriceList>
  </MI>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<MT_MATERIALDATA>
    <items item="475053">
        <Recordset>
            <CodeBusinessUnit>99</CodeBusinessUnit>
            <PriceValue>250</PriceValue>
        </Recordset>
        <Recordset>
            <CodeBusinessUnit>1</CodeBusinessUnit>
            <PriceValue>250</PriceValue>
        </Recordset>
    </items>
    <items item="475054">
        <Recordset>
            <CodeBusinessUnit>1</CodeBusinessUnit>
            <PriceValue>255.34</PriceValue>
        </Recordset>
        <Recordset>
            <CodeBusinessUnit>10</CodeBusinessUnit>
            <PriceValue>299</PriceValue>
        </Recordset>
    </items>
</MT_MATERIALDATA>

会产生想要的正确结果:

<MT_MATERIALDATA>
    <MI item="475053">
        <PriceList>
            <Prices>
                <Price Value="250"/>
                <PriceConfig>
                    <Stores>99,1</Stores>
                </PriceConfig>
            </Prices>
        </PriceList>
    </MI>
    <MI item="475054">
        <PriceList>
            <Prices>
                <Price Value="255.34"/>
                <PriceConfig>
                    <Stores>1</Stores>
                </PriceConfig>
            </Prices>
            <Prices>
                <Price Value="299"/>
                <PriceConfig>
                    <Stores>10</Stores>
                </PriceConfig>
            </Prices>
        </PriceList>
    </MI>
</MT_MATERIALDATA>

答案 2 :(得分:1)

我还要发布一个样式表,因为每个人都这样做:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kBUnitByItem-Price"
             match="CodeBusinessUnit"
             use="concat(../../@item, '++', ../PriceValue)"/>
    <xsl:template match="/">
        <MT_MATERIALDATA>
            <xsl:apply-templates/>
        </MT_MATERIALDATA>
    </xsl:template>
    <xsl:template match="items">
        <MI item="{@item}">
            <PriceList>
                <xsl:apply-templates/>
            </PriceList>
        </MI>
    </xsl:template>
    <xsl:template match="CodeBusinessUnit[
                            count(.|key('kBUnitByItem-Price',
                                        concat(../../@item,'++',../PriceValue)
                                    )[1]
                            ) = 1
                         ]">
        <Prices>
            <Price Value="{../PriceValue}"/>
            <PriceConfig>
                <Stores>
                    <xsl:apply-templates
                         select="key('kBUnitByItem-Price',
                                     concat(../../@item,'++',../PriceValue))"
                         mode="sequence"/>
                </Stores>
            </PriceConfig>
        </Prices>
    </xsl:template>
    <xsl:template match="text()"/>
    <xsl:template match="node()" mode="sequence">
        <xsl:if test="position()!=1">,</xsl:if>
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

注意:按商品和价格对商店进行分组。比推送风格多一点拉(这是因为没有重复的@item。)

输出:

<MT_MATERIALDATA>
    <MI item="475053">
        <PriceList>
            <Prices>
                <Price Value="250" />
                <PriceConfig>
                    <Stores>99,1</Stores>
                </PriceConfig>
            </Prices>
        </PriceList>
    </MI>
    <MI item="475054">
        <PriceList>
            <Prices>
                <Price Value="255.34" />
                <PriceConfig>
                    <Stores>1</Stores>
                </PriceConfig>
            </Prices>
            <Prices>
                <Price Value="299" />
                <PriceConfig>
                    <Stores>10</Stores>
                </PriceConfig>
            </Prices>
        </PriceList>
    </MI>
</MT_MATERIALDATA>

我认为我们涵盖了所有变化:键值,推拉,序列分隔符条件。