Subject: RE: 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: 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
|