Removing elements based on child elements XSLT
I am new to Stack Overflow and to XSLT. I have a problem with removing duplicate entries from the output, based on some child element conditions.
Here is an example of XML that I have:
<partyorders>
<ord开发者_高级运维er>
<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>
....
represents more orders of same as above
I need to get the output as:
- only one order with pending/approved status.
- if there are two orders with only different in status, i want to display reserved order only after confirming by comparing elements
<day>
,<month>
,<year>
,<amount>
I want the following output based on <day>
, <month>
, <year>
, <amount>
and <decision>
tags:
<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>
Can someone help me out in getting the solution using XSLT 1.0?
<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>
Output:
<?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>
The relevant xsl:template contents would be:
<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>
It's O(N^2) tho, and I won't recommend using XSLT for that under load.
精彩评论