Удаление элементов на основе дочерних элементов XSLT - PullRequest
0 голосов
/ 15 декабря 2009

Я новичок в переполнении стека и XSLT. У меня проблема с удалением повторяющихся записей из выходных данных на основе некоторых условий дочернего элемента.

Вот пример XML, который у меня есть:

<partyorders>    
    <order>  
        <day>12</day>
        <month>05</month>  
        <year>2000</year>  
        <amount>5000.00</amount>  
        <decision>pending</decision>  
    </order>  
    <order>  
        <day>19</day>  
        <month>04</month>  
        <year>2000</year>  
        <amount>2000.00</amount>  
        <decision>pending</decision>  
    </order>  
    <order>  
        <day>19</day>  
        <month>04</month>  
        <year>2000</year>  
        <amount>2000.00</amount>  
        <decision>reserved</decision>  
    </order> 
     <order>  
        <day>05</day>  
        <month>04</month>  
        <year>2000</year>  
        <amount>1000.00</amount>  
        <decision>pending</decision>  
    </order>  
    <order>  
        <day>05</day>  
        <month>04</month>  
        <year>2000</year>  
        <amount>1000.00</amount>  
        <decision>reserved</decision>  
    </order> 
    <order>
        ....
    </order>
</partyorders>  

.... представляет больше заказов, чем указано выше

Мне нужно получить вывод как:

  1. только один заказ с ожидающим / утвержденным статусом.
  2. если есть два ордера с разным статусом, я хочу отображать зарезервированный ордер только после подтверждения путем сравнения элементов <day>, <month>, <year>, <amount>

Я хочу следующий вывод на основе тегов <day>, <month>, <year>, <amount> и <decision>:

<restrntpartyorders>    
    <restrntorder>  
        <partyday>12</partyday>
        <partymonth>05</partymonth>  
        <partyyear>2000</partyyear>  
        <partyamount>5000.00</partyamount>  
        <partydecision>pending</partydecision>  
    </restrntorder>  
    <restrntorder>  
        <partyday>19</partyday>  
        <partymonth>04</partymonth>  
        <partyyear>2000</partyyear>  
        <partyamount>2000.00</partyamount>  
        <partydecision>reserved</partydecision>  
    </restrntorder>  
    <restrntorder>  
        <partyday>05</partyday>  
        <partymonth>04</partymonth>  
        <partyyear>2000</partyyear>  
        <partyamount>1000.00</partyamount>  
        <partydecision>reserved</partydecision>  
    </restrntorder> 
    <restrntorder>
        ....
    </restrntorder>
</restrntpartyorders>  

Может кто-нибудь помочь мне с решением XSLT 1.0?

Ответы [ 2 ]

1 голос
/ 16 декабря 2009
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output indent="yes" encoding="utf-8" />

  <!-- index order elements by year, month, day, amount -->
  <xsl:key 
    name="kOrdersByDate" 
    match="order" 
    use="concat(year, '-', month, '-', day, '$', amount)"
  />

  <xsl:template match="order">
    <!-- select all orders of same date and amount -->
    <xsl:variable name="same" select="
      key('kOrdersByDate', concat(year, '-', month, '-', day, '$', amount))
    " />
    <!-- of those, select the first 'reserved' order -->
    <xsl:variable name="same-reserved" select="
      $same[decision = 'reserved']
    " />

    <!-- check that either: 
      1. no other equal order, e.g. count($same) = 1, or
      2. reseverd order exists, take it
      3. no reseverd order exists, take the first "same" order
    -->
    <xsl:if test="
      count($same) = 1 
      or 
      ($same-reserved and generate-id() = generate-id($same-reserved[1]))
      or
      (not($same-reserved) and generate-id() = generate-id($same[1]))
    ">
      <!-- rename order -> restrntorder -->
      <restrntorder>
        <xsl:apply-templates select="*" />
      </restrntorder>
    </xsl:if>
  </xsl:template>

  <!-- rename partyorders -> restrntpartyorders -->
  <xsl:template match="partyorders">
    <restrntpartyorders>
      <xsl:apply-templates select="order" />
    </restrntpartyorders>
  </xsl:template>

  <!-- rename day etc. -> partyday etc. -->
  <xsl:template match="order/*">
    <xsl:element name="party{local-name()}">
      <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Выход:

<?xml version="1.0" encoding="utf-8"?>
<restrntpartyorders>
    <restrntorder>
        <partyday>12</partyday>
        <partymonth>05</partymonth>
        <partyyear>2000</partyyear>
        <partyamount>5000.00</partyamount>
        <partydecision>pending</partydecision>
    </restrntorder>

    <restrntorder>
        <partyday>19</partyday>
        <partymonth>04</partymonth>
        <partyyear>2000</partyyear>
        <partyamount>2000.00</partyamount>
        <partydecision>reserved</partydecision>
    </restrntorder>

    <restrntorder>
        <partyday>05</partyday>
        <partymonth>04</partymonth>
        <partyyear>2000</partyyear>
        <partyamount>1000.00</partyamount>
        <partydecision>reserved</partydecision>
    </restrntorder>
    <restrntorder>
        ....
    </restrntorder>
</restrntpartyorders>
0 голосов
/ 15 декабря 2009

Соответствующее содержимое xsl: template будет:

<partyorders>
  <xsl:for-each select="/partyorders/order">
    <xsl:if test="count(following-sibling::order[day = current()/day and month = current()/month etc etc]) = 0">
      <xsl:copy-of select="." />
    </xsl:if>
  </xsl:for-each>
</partyorders>

Это O (N ^ 2), но я не буду рекомендовать использовать XSLT для этого под нагрузкой.

...