2009-12-15 8 views
0

Я новичок в переполнении стека и XSLT. У меня возникла проблема с удалением повторяющихся записей из вывода на основе некоторых условий дочерних элементов.Удаление элементов на основе дочерних элементов 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?

ответ

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

Спасибо, Томалак. У меня есть вопросы 1. Что делать, если я хочу также фильтровать заказы с отклоненным статусом. 2. Если мне нужно настроить outpout .., то выходные элементы могут быть вместо и вместо . Пожалуйста помоги – angi

0

Соответствующий XSL: содержание шаблона будет:

<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 для этого под нагрузкой.

+0

Вы можете, конечно, использовать XSLT для этого. Вы просто не можете использовать *, что * XSLT. Методом Muenchian, который использует ответ Томалака, является O (N). –

+0

Ты, наверное, прав. – alamar

Смежные вопросы