XSLT根据元素和属性对重复项进行排序和删除

时间:2014-07-11 15:44:08

标签: xslt

请你帮我解决我被击中的XSLT,

要求:在我的XML记录中,任何offer / sku都是相同的,并且offer / customer-attributes / custom-attribute / Feed_SKU更重要,那么我必须保留该记录(这意味着这是最新的记录并忽略另一个)。

我的案例Feed_SKU = 09/07/2014 23:21:20是最新记录。

我尝试过使用xsl:key compare并且很难解析属性值(Feed_SKU)。你能帮帮我吗?

输入XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<enfinity xmlns="http://www.intershop.com/xml/ns/enfinity/6.5/xcs/impex" xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/6.5/xcs/impex catalog.xsd  http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt dt.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" family="enfinity" major="6" minor="1">
<offer import-mode="UPDATE" sku="36-5149574">
<sku>36-5149574</sku>
<custom-attributes>
<custom-attribute name="OriginalFileName" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">Message_20140709_2321130190_BP71794596.dat_SKU</custom-attribute>
<custom-attribute name="FacilityId" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">385</custom-attribute>
<custom-attribute name="GII" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">6661116</custom-attribute>
<custom-attribute name="CountryOrigin" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">US</custom-attribute>
<custom-attribute name="UOMSystem" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">I</custom-attribute>
<custom-attribute name="CartonType" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">AF</custom-attribute>
<custom-attribute name="Catalog" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">36</custom-attribute>
<custom-attribute name="Height" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">3 in</custom-attribute>
<custom-attribute name="Length" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">14 in</custom-attribute>
<custom-attribute name="Width" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">10.5 in</custom-attribute>
<custom-attribute name="Weight" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">9.7 lb</custom-attribute>
<custom-attribute name="Feed_SKU" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">09/07/2014 23:21:14</custom-attribute>
</custom-attributes>
</offer>
<offer import-mode="UPDATE" sku="36-5149574">
<sku>36-5149574</sku>
<custom-attributes>
<custom-attribute name="OriginalFileName" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">Message_20140709_2321130190_BP71794596.dat_SKU</custom-attribute>
<custom-attribute name="FacilityId" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">385</custom-attribute>
<custom-attribute name="GII" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">6661116</custom-attribute>
<custom-attribute name="CountryOrigin" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">US</custom-attribute>
<custom-attribute name="UOMSystem" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">I</custom-attribute>
<custom-attribute name="CartonType" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">AF</custom-attribute>
<custom-attribute name="Catalog" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">36</custom-attribute>
<custom-attribute name="Height" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">3 in</custom-attribute>
<custom-attribute name="Length" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">14 in</custom-attribute>
<custom-attribute name="Width" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">10.5 in</custom-attribute>
<custom-attribute name="Weight" dt:dt="quantity" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">9.7 lb</custom-attribute>
<custom-attribute name="Feed_SKU" dt:dt="string" xmlns:dt="http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt">09/07/2014 23:23:23</custom-attribute>
</custom-attributes>
</offer>
</enfinity> 

XLST我正在努力:(不工作)

  <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                         version="1.0" 
                         xmlns:impex="http://www.intershop.com/xml/ns/enfinity/6.5/xcs/impex" 
                         xsi:schemaLocation="http://www.intershop.com/xml/ns/enfinity/6.5/xcs/impex catalog.xsd  http://www.intershop.com/xml/ns/enfinity/6.5/core/impex-dt dt.xsd" 
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output omit-xml-declaration="no" indent="yes" method="xml"/>
    <!-- key for grouping -->
    <xsl:key name="offerBySku" match="impex:offer" use="impex:sku"/>
    <xsl:template match="/*">
        <xsl:copy>
            <!-- transfer attributes of the document element -->
            <xsl:copy-of select="@*"/>
            <!-- Muenchian method to get one iteration per sku -->
            <xsl:for-each select="impex:offer[generate-id() = generate-id(key('offerBySku', impex:sku)[1])]">
                <!-- sort the group by descending timestamp -->
                <xsl:for-each select="key('offerBySku', impex:sku)">
                    <!-- rearrange the timestamp to year, month, day, time -->
                    <xsl:sort order="descending" select="concat(
                          substring(impex:custom-attributes/impex:custom-attribute[@name='Feed_SKU'], 7, 4),
                          substring(impex:custom-attributes/impex:custom-attribute[@name='Feed_SKU'], 4, 2),
                          substring(impex:custom-attributes/impex:custom-attribute[@name='Feed_SKU'], 1, 2),
                          substring(impex:custom-attributes/impex:custom-attribute[@name='Feed_SKU'], 11))"/>
                    <!-- copy just the first element in sorted order, i.e. the one with the latest date-->
                    <xsl:copy-of select="."/>
                    <xsl:if test="position() = 1">
                        <xsl:copy-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

此问题分为两部分,首先将共享相同sku的商品组合在一起,然后在每个组中查找最新日期。对于第一部分,您可以使用Muenchian分组,对于第二部分,您需要通过字符串操作获得创造性 - XSLT 1.0对日期和时间没有任何特殊支持,因此您需要将时间戳值按摩到按时间顺序匹配的形式词典排序。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
        xmlns:impex="http://www.intershop.com/xml/ns/enfinity/6.5/xcs/impex">

  <!-- key for grouping -->
  <xsl:key name="offerBySku" match="impex:offer" use="impex:sku" />

  <xsl:template match="/*">
    <xsl:copy>
      <!-- transfer attributes of the document element -->
      <xsl:copy-of select="@*"/>
      <!-- Muenchian method to get one iteration per sku -->
      <xsl:for-each select="impex:offer[
           generate-id() = generate-id(key('offerBySku', impex:sku)[1])]">
        <!-- sort the group by descending timestamp -->
        <xsl:for-each select="key('offerBySku', impex:sku)">
          <!-- rearrange the timestamp to year, month, day, time -->
          <xsl:sort order="descending" select="concat(
              substring(impex:custom-attributes/impex:custom-attribute[
                          @name='Feed_SKU'], 7, 4),
              substring(impex:custom-attributes/impex:custom-attribute[
                          @name='Feed_SKU'], 4, 2),
              substring(impex:custom-attributes/impex:custom-attribute[
                          @name='Feed_SKU'], 1, 2),
              substring(impex:custom-attributes/impex:custom-attribute[
                          @name='Feed_SKU'], 11))" />
          <!-- copy just the first element in sorted order, i.e. the one with
               the latest date -->
          <xsl:if test="position() = 1">
            <xsl:copy-of select="." />
          </xsl:if>
        </xsl:for-each>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

我假设时间戳是dd / mm / yyyy,因为2014年9月7日将在问这个问题的日期之后,但如果它们实际上是mm / dd / yyyy那么你将不得不交换第二次和第三次substring调用以获得正确的排序。