Группировка элементов и удаление дублирующих узлов - XSLT 1.0 - PullRequest
2 голосов
/ 21 февраля 2011

Я посмотрел на Muenchian Grouping - группа внутри узла, а не внутри всего документа , но она не совсем работает для меня.Один только метод Мюнхена не делает этого и для меня.

Я также рассмотрел XSLT 1.0: группировка и удаление дубликатов , но не могу полностью им следовать.следующий 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>.

Я пытался часами, но либо номера магазинов всегда дублируются, либо они не агрегируются, даже если PriceValue одинаково.Я ценю любую помощь, я не знаю, что делать дальше.Спасибо за вашу помощь!

С уважением, Питер

Ответы [ 3 ]

1 голос
/ 21 февраля 2011

Это преобразование:

<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>
1 голос
/ 21 февраля 2011

Я также собираюсь опубликовать таблицу стилей, потому что все это делают:

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

Я думаю, что мы рассмотрим все варианты: значение ключа, двухтактныйусловие разделителя последовательностей.

1 голос
/ 21 февраля 2011

Я думаю, что следующее решает проблему, по крайней мере, для группировки:

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