开发者

Removing duplicates in xsl

开发者 https://www.devze.com 2022-12-21 04:33 出处:网络
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 on

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号