Sunday 17 September 2017

Eliminate duplicate nodes/records from a list using xslt

Request Payload:

      <GetDocumentsResponse>
         <tns:DocumentDetails>
            <tns:DocumentId>217</tns:DocumentId>
            <tns:DocumentSource>WCC</tns:DocumentSource>
         </tns:DocumentDetails>
         <tns:DocumentDetails>
            <tns:DocumentId>12312173</tns:DocumentId>
            <tns:DocumentSource>WCC</tns:DocumentSource>
         </tns:DocumentDetails>
         <tns:DocumentDetails>
            <tns:DocumentId>218</tns:DocumentId>
            <tns:DocumentSource>W</tns:DocumentSource>
            <tns:DocumentName>Test document 10</tns:DocumentName>
         </tns:DocumentDetails>
         <tns:DocumentDetails>
            <tns:DocumentId>217</tns:DocumentId>
            <tns:DocumentSource>W</tns:DocumentSource>
            <tns:DocumentName>Test document 13</tns:DocumentName>
         </tns:DocumentDetails>
      </GetDocumentsResponse>

Expected Response:

Eliminated duplicate records using one of the child nodes (DocumentId here). Eliminate duplicated DocumentId="217" record from the response just like below.

      <GetDocumentsResponse>
         <tns:DocumentDetails>
            <tns:DocumentId>217</tns:DocumentId>
            <tns:DocumentSource>WCC</tns:DocumentSource>
         </tns:DocumentDetails>
         <tns:DocumentDetails>
            <tns:DocumentId>12312173</tns:DocumentId>
            <tns:DocumentSource>WCC</tns:DocumentSource>
         </tns:DocumentDetails>
         <tns:DocumentDetails>
            <tns:DocumentId>218</tns:DocumentId>
            <tns:DocumentSource>W</tns:DocumentSource>
            <tns:DocumentName>Test document 10</tns:DocumentName>
         </tns:DocumentDetails>
      </GetDocumentsResponse>



Solution:

XSLT 1.0:

Use the below xslt template with version 1.0.

<xsl:stylesheet version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>
  <xsl:key name="DocumentDetailsById" match="/ns0:GetDocumentsResponse/ns0:DocumentDetails" use="./ns0:DocumentId"/>
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="/ns0:GetDocumentsResponse/ns0:DocumentDetails[not(generate-id() = generate-id(key('DocumentDetailsById', ./ns0:DocumentId[1])))]"/>
</xsl:stylesheet>



XSLT 2.0:


<xsl:stylesheet version="2.0">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">

     <XML>
       <xsl:for-each-group select="/ns0:GetDocumentsResponse/ns0:DocumentDetails" group-by="./ns0:DocumentId">
         <xsl:sequence select="."/>
       </xsl:for-each-group>
     </XML>
 </xsl:template>

</xsl:stylesheet>











Wednesday 30 August 2017

Filter List using multiple sub/child elements in XSLT

<xsl:for-each select="//DocumentList/DocumentDetails[./DocumentSource=$DocumentSource or $DocumentSource= ''][./Category = $Category or $Category = '']">


I have Request something like below:

<DocumentList>
  <DocumentDetails>
    <DocumentID>Document1</DocumentID>
    <DocumentSource>DocumentSource1</DocumentSource>
    <Category>Category1</Categoty>
  </DocumentDetails>
<DocumentDetails>
    <DocumentID>Document2</DocumentID>
    <DocumentSource>DocumentSource2</DocumentSource>
    <Category>Category2</Categoty>
  </DocumentDetails>
  <DocumentDetails>
    <DocumentID>Document3</DocumentID>
    <DocumentSource>DocumentSource2</DocumentSource>
    <Category>Category2</Categoty>
  </DocumentDetails>
</DocumentList>


Expected Output:


The DocumentList has to be filtered out using DocumentSource and Category.

For Ex: DocumentSource=DocumentSource2 and Category=Category2
Result:

<DocumentList>
  <DocumentDetails>
    <DocumentID>Document2</DocumentID>
    <DocumentSource>DocumentSource2</DocumentSource>
    <Category>Category2</Categoty>
  </DocumentDetails>
  <DocumentDetails>
    <DocumentID>Document3</DocumentID>
    <DocumentSource>DocumentSource2</DocumentSource>
    <Category>Category2</Categoty>
  </DocumentDetails>
</DocumentList>

Solution:



<xsl:for-each select="/ns0:DocumentList/ns0:DocDetails[./ns0:DocumentSource=$DocumentSource or $DocumentSource=''][./ns0:Category=$Category or $Category=''][./ns0:SubCategory=$SubCategory or $SubCategory='']">

$DocumentSource and $Category are variable holding the data "DocumentSource2" and "Category2" respectively.