Removing duplicates in xsl
I have the following XML and I want to process it so that I do not get duplicates in the result set. I have simplified the problem to make it easier to understand. Also how can I use the results of one template as part of the input for another?
This:
<LINES xmlns:set="http://exslt.org/sets">
<STDINSTRSEQ>0</STDINSTRSEQ>
<STDINSTRSEQ>1</STDINSTRSEQ>
<STDINSTRSEQ>2</STDINSTRSEQ>
</LINES>
is the desired result. <STDINSTRSEQ>
is the name of the field that should be treated as the key. I have provided the sample data here.
<PURCHASEORDER>
<POHEADER>
<REQUISITIONNO>1103025T12 000 000</REQUISITIONNO>
<REQLDATE>2004-10-26</REQLDATE>
<MTLREQDT></MTLREQDT>
<开发者_JAVA技巧CREATEDT>2005-03-16</CREATEDT>
<VNDRLONGNM>DORI FOODS, INC.</VNDRLONGNM>
</POHEADER>
<LINES>
<LINE>
<POLINENBR>12</POLINENBR>
<STDINSTRDESC>NOTE: THIS PURCHASE ORDER SERVES AS CONFIRMATION</STDINSTRDESC>
<STDINSTRSEQ>0</STDINSTRSEQ>
</LINE>
<LINE>
<POLINENBR>11</POLINENBR>
<STDINSTRDESC>NOTE: THIS PURCHASE ORDER SERVES AS CONFIRMATION</STDINSTRDESC>
<STDINSTRSEQ>0</STDINSTRSEQ>
</LINE>
<LINE>
<POLINENBR>11</POLINENBR>
<STDINSTRDESC>THAT WE ACCEPT THE TERMS AND CONDITIONS OUTLINED IN</STDINSTRDESC>
<STDINSTRSEQ>1</STDINSTRSEQ>
</LINE>
<LINE>
<POLINENBR>12</POLINENBR>
<STDINSTRDESC>THAT WE ACCEPT THE TERMS AND CONDITIONS OUTLINED IN</STDINSTRDESC>
<STDINSTRSEQ>1</STDINSTRSEQ>
</LINE>
<LINE>
<POLINENBR>23</POLINENBR>
<STDINSTRDESC>YOUR CONTRACT DATED 02/16/2007 FOR THE FOLLOWING</STDINSTRDESC>
<STDINSTRSEQ>2</STDINSTRSEQ>
</LINE>
<LINE>
<POLINENBR>22</POLINENBR>
<STDINSTRDESC>YOUR CONTRACT DATED 02/16/2007 FOR THE FOLLOWING</STDINSTRDESC>
<STDINSTRSEQ>2</STDINSTRSEQ>
</LINE>
</LINES>
</PURCHASEORDER>
If I understand correctly what you are asking for, then given your sample XML this would work
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="/PURCHASEORDER/LINES" />
</xsl:template>
<xsl:template match="LINES">
<LINES xmlns:set="http://exslt.org/sets">
<xsl:apply-templates select="LINE/STDINSTRSEQ[not(. = preceding::STDINSTRSEQ)]"/>
</LINES>
</xsl:template>
<xsl:template match="STDINSTRSEQ">
<xsl:copy> <xsl:apply-templates/> </xsl:copy>
</xsl:template>
</xsl:stylesheet>
An optimized version that uses <xsl:key>
to filter and provide unique results:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="STDIN" match="STDINSTRSEQ" use="./text()" />
<xsl:template match="/">
<xsl:apply-templates select="/PURCHASEORDER/LINES" />
</xsl:template>
<xsl:template match="LINES">
<LINES xmlns:set="http://exslt.org/sets">
<xsl:apply-templates select="LINE/STDINSTRSEQ[generate-id(.) = generate-id(key('STDIN', .))]"/>
</LINES>
</xsl:template>
<xsl:template match="STDINSTRSEQ">
<xsl:copy> <xsl:apply-templates/> </xsl:copy>
</xsl:template>
</xsl:stylesheet>
I'm not sure about the apply-templates. I don't understand how they work. So for a XML that was like that:
<xml>
<line>209</line>
<line>209</line>
<line>209</line>
<line>100</line>
<line>101</line>
<line>101</line>
<line>100</line>
<line>102</line>
<line>209</line>
<line>101</line>
<line>101</line>
<line>101</line>
<line>101</line>
<line>209</line>
<line>100</line>
</xml>
to remove the repetitions, leaving only unique values:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="no" />
<xsl:template match="/">
<Output>
<xsl:for-each select="//line">
<xsl:if test="not(. = preceding::line)">
<line>
<xsl:value-of select="string(.)" disable-output-escaping="no" />
</line>
</xsl:if>
</xsl:for-each>
</Output>
</xsl:template>
</xsl:stylesheet>
And the result was:
<Output>
<line>100</line>
<line>101</line>
<line>102</line>
<line>209</line>
</Output>
And it was much quicker than the solution provided by Mads Hansen.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:key name="kSTDINSTRSEQ" match="STDINSTRSEQ" use="." />
<xsl:template match="PURCHASEORDER">
<xsl:apply-templates select="LINES" />
</xsl:template>
<xsl:template match="LINES">
<LINES xmlns:set="http://exslt.org/sets">
<xsl:copy-of select="
LINE/STDINSTRSEQ[
generate-id() = generate-id(key('kSTDINSTRSEQ', .)[1])
]
" />
</LINES>
</xsl:template>
</xsl:stylesheet>
produces
<LINES xmlns:set="http://exslt.org/sets">
<STDINSTRSEQ>0</STDINSTRSEQ>
<STDINSTRSEQ>1</STDINSTRSEQ>
<STDINSTRSEQ>2</STDINSTRSEQ>
</LINES>
To access this from another XSL template, write it to a temporary file and use the document()
function. Alternatively, just do the grouping in the other XSLT file.
精彩评论