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: Amit Agarwal <aagarwal123@xxxxxxxxx>
Date: Tue, 19 Jun 2012 20:52:42 +0530
Hi Scott,

Thanks a lot for your prompt response.

Your input has helped me to resolve the issue to a great extent.

Highly Appreciate your support !

Thanks,
Amir

On Tue, Jun 19, 2012 at 8:02 PM, Scott Trenda <Scott.Trenda@xxxxxxxx> wrote:
> 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::MedicinalP
roductName 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