[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] How to do this unique grouping on XML using XSLT 1.0


Subject: RE: [xsl] How to do this unique grouping on XML using XSLT 1.0
From: Scott Trenda <Scott.Trenda@xxxxxxxx>
Date: Tue, 19 Jun 2012 09:32:43 -0500

Pretty easy, overall. Mainly you need to remember that you can register multiple node-set matches under a single key name, and retrieve them all at the same time through one key() call. This allows you to do Muenchian grouping over multiple node-sets whose nodes have similar but not identical structure. After you have the groups, it's just a matter of choosing which element you retrieve for grouping and for the medicinalproduct node. The self:: axis ends up being slightly more succinct than a predicate that checks name(). It's repeated three times here; I don't know if that starts to be a case for pulling out the string itself into an XML entity. YMMV.


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output encoding="utf-8" indent="yes" omit-xml-declaration="yes" />
  <xsl:key name="drug" match="DrugSafetyReportDrug" use="MedicinalProductName" />
  <xsl:key name="drug" match="DrugSafetyReportMedicalDevice" use="MedicalDeviceName" />
  <xsl:variable name="drugs" select="//DrugSafetyReportDrug | //DrugSafetyReportMedicalDevice" />
  <xsl:template match="/*">
    <Root>
      <xsl:for-each select="$drugs[generate-id(key('drug', self::DrugSafetyReportDrug/MedicinalProductName | self::DrugSafetyReportMedicalDevice/MedicalDeviceName)) = generate-id()]">
        <Drug>
          <medicinalproduct>
            <xsl:value-of select="self::DrugSafetyReportDrug/MedicinalProductName | self::DrugSafetyReportMedicalDevice/MedicalDeviceName" />
          </medicinalproduct>
          <xsl:copy-of select="key('drug', self::DrugSafetyReportDrug/MedicinalProductName | self::DrugSafetyReportMedicalDevice/MedicalDeviceName)/*[not(self::MedicinalProductName or self::MedicalDeviceName)]" />
        </Drug>
      </xsl:for-each>
    </Root>
  </xsl:template>
</xsl:stylesheet>


XSLT2 would be just slightly more convenient here, with <xsl:for-each-group select="//DrugSafetyReportDrug | //DrugSafetyReportMedicalDevice" group-by="self::DrugSafetyReportDrug/MedicinalProductName | self::DrugSafetyReportMedicalDevice/MedicalDeviceName">, and then using current-group() instead of calling key() again... but the underlying logic would stay the same.

~ Scott


-----Original Message-----
From: Amit Agarwal [mailto:aagarwal123@xxxxxxxxx] 
Sent: Tuesday, June 19, 2012 8:12 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx; xsl-list-help@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] How to do this unique grouping on XML using XSLT 1.0

My input xml looks like:


 Root>
  <ReportDrugSafetyReport>
   <DrugSafetyReportPatient>
    <DrugSafetyReportDrug>
     <MedicinalProductName>BPM Infra</MedicinalProductName>
     <ObtainedCountryCode>US</ObtainedCountryCode>
    </DrugSafetyReportDrug>

    <DrugSafetyReportDrug>
     <MedicinalProductName>Multistandard VCR</MedicinalProductName>
     <ObtainedCountryCode>UK</ObtainedCountryCode>
    </DrugSafetyReportDrug>

    <DrugSafetyReportDrug>
     <MedicinalProductName>Pharmaceuticals</MedicinalProductName>
     <ObtainedCountryCode>IN</ObtainedCountryCode>
    </DrugSafetyReportDrug>

   </DrugSafetyReportPatient>

   <DrugSafetyReportMedicalDevice>
    <MedicalDeviceName>BPM Infra</MedicalDeviceName>
    <DeviceProductCode>1234</DeviceProductCode>
   </DrugSafetyReportMedicalDevice>

   <DrugSafetyReportMedicalDevice>
    <MedicalDeviceName>Different Product name</MedicalDeviceName>
    <DeviceProductCode>456</DeviceProductCode>
   </DrugSafetyReportMedicalDevice>
  </ReportDrugSafetyReport>
 </Root>

 And My target xml is:

 <Root>
  <Drug>
   <medicinalproduct>BPM Infra</medicinalproduct>
   <ObtainedCountryCode>US</ObtainedCountryCode>
   <DeviceProductCode>1234</DeviceProductCode>
  </Drug>
  <Drug>
   <medicinalproduct>Multistandard VCR</medicinalproduct>
   <ObtainedCountryCode>UK</ObtainedCountryCode>
  </Drug>
  <Drug>
   <medicinalproduct>Pharmaceuticals</medicinalproduct>
   <ObtainedCountryCode>IN</ObtainedCountryCode>
  </Drug>
  <Drug>
   <medicinalproduct>Different Product name</medicinalproduct>
   <DeviceProductCode>456</DeviceProductCode>
  </Drug>
 </Root>

  Input xml contains two unbounded elements DrugSafetyReportDrug and DrugSafetyReportMedicalDevice. Both of these elements belongs to different parent elements, e.g.
 <root>ReportDrugSafetyReport/
DrugSafetyReportPatient/DrugSafetyReportDrug and <root>/ReportDrugSafetyReport/DrugSafetyReportMedicalDevice

 Each of these elements has a set of child elements. Out of which, MedicinalProductName is child element of  DrugSafetyReportDrug
(DrugSafetyReportDrug/MedicinalProductName)  and MedicalDeviceName is child element of DrugSafetyReportMedicalDevice (DrugSafetyReportMedicalDevice/MedicalDeviceName).

 Target xml has an unbounded element: drug.

If MedicinalProductName = MedicalDeviceName then DrugSafetyReportDrug and DrugSafetyReportMedicalDevice should be grouped to a single drug element (in the target xml). Otherwise, there would be a separate drug element for each DrugSafetyReportDrug and DrugSafetyReportMedicalDevice.

Thanks for your help!.

Thanks,
Amit


Current Thread
Keywords