XSLT: Modify attribute value based on sibling attribute value
I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<ODM FileOID="some oid" Description="some desc" CreationDateTime="2010-10-06T22:35:00-06:00" FileType="Snapshot" >
<Study OID="S_TEST">
<GlobalVariables>
<StudyName>Study_Name</StudyName>
<StudyDescription>
Some study description
</StudyDescription>
<ProtocolName>Some protocol name</ProtocolName>
</GlobalVariables>
<MetaDataVersion OID="v1.0.0" Name="MetaDataVersion_v1.0.0">
<Protocol>
<StudyEventRef StudyEventOID="SE01" OrderNumber="36" Mandatory="Yes"/>
<StudyEventRef StudyEventOID="SE02" OrderNumber="37" Mandatory="Yes"/>
</Protocol>
<StudyEventDef OID="SE01" Name="Some name 01" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"/>
<FormRef FormOID="F02" Mandatory="Yes"/>
</StudyEventDef>
<StudyEventDef OID="SE02" Name="Some name 02" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"/>
<FormRef FormOID="F02" Mandatory="Yes"/>
</StudyEventDef>
<FormDef OID="F01" Name="Some form name 01" Repeating="No">
<ItemGroupRef ItemGroupOID="IG01" Mandatory="Yes"/>
</For开发者_运维知识库mDef>
<FormDef OID="F02" Name="Some form name 02" Repeating="No">
<ItemGroupRef ItemGroupOID="IG02" Mandatory="Yes"/>
<ItemGroupRef ItemGroupOID="IG03" Mandatory="No"/>
</FormDef>
<ItemGroupDef OID="IG01" Name="Ungrouped" Repeating="No" SASDatasetName="UNGROUPE">
<ItemRef ItemOID="I01" OrderNumber="1" Mandatory="Yes"/>
<ItemRef ItemOID="I02" OrderNumber="2" Mandatory="Yes"/>
<ItemRef ItemOID="I03" OrderNumber="3" Mandatory="Yes"/>
</ItemGroupDef>
<ItemGroupDef OID="IG02" Name="Reasons2" Repeating="Yes" SASDatasetName="REASONS2">
<ItemRef ItemOID="I04" OrderNumber="1" Mandatory="No"/>
</ItemGroupDef>
<ItemGroupDef OID="IG03" Name="Ungrouped" Repeating="No" SASDatasetName="UNGRO002">
<ItemRef ItemOID="I05" OrderNumber="1" Mandatory="Yes"/>
<ItemRef ItemOID="I06" OrderNumber="2" Mandatory="Yes"/>
</ItemGroupDef>
</MetaDataVersion>
</Study>
</ODM>
What I want to do is, for each <ItemGroupDef>
element with a "Name" attribute equal to "Ungrouped", change this attribute value to "XXX-Ungrouped", where XXX is the value of the OID attribute for the <FormDef>
element that has a child <ItemGroupRef
> with an ItemGroupOID attribute equal to the OID atrribute of the ItemGroupDef element. All of the other attributes and all of the children of this element should be left unaltered.
For example, for the <ItemGroupDef OID="IG01">
above, the Name attribute should be changed from "Ungrouped" to "F01-Ungrouped" since this OID, IG01, appears as a child of the <FormDef OID="F01">
element. It is guaranteed that any ItemGroupDef OID value appears as a child of only one <FormDef>
element.
The transformation should act on <ItemGroupDef>
elements with a Name attribute value of "Ungrouped" only. All of the <ItemGroupDef>
elements with Name attribute other than "Ungrouped" and all of the other elements in the XML file should be left unaltered.
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kOIDbyItemGroup" match="FormDef/@OID"
use="../ItemGroupRef/@ItemGroupOID"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ItemGroupDef/@Name[.='Ungrouped']">
<xsl:attribute name="Name">
<xsl:value-of select="concat(key('kOIDbyItemGroup',../@OID),
'-',.)"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Output:
<ODM FileOID="some oid" Description="some desc" CreationDateTime="2010-10-06T22:35:00-06:00" FileType="Snapshot">
<Study OID="S_TEST">
<GlobalVariables>
<StudyName>Study_Name</StudyName>
<StudyDescription>
Some study description
</StudyDescription>
<ProtocolName>Some protocol name</ProtocolName>
</GlobalVariables>
<MetaDataVersion OID="v1.0.0" Name="MetaDataVersion_v1.0.0">
<Protocol>
<StudyEventRef StudyEventOID="SE01" OrderNumber="36" Mandatory="Yes"></StudyEventRef>
<StudyEventRef StudyEventOID="SE02" OrderNumber="37" Mandatory="Yes"></StudyEventRef>
</Protocol>
<StudyEventDef OID="SE01" Name="Some name 01" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"></FormRef>
<FormRef FormOID="F02" Mandatory="Yes"></FormRef>
</StudyEventDef>
<StudyEventDef OID="SE02" Name="Some name 02" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"></FormRef>
<FormRef FormOID="F02" Mandatory="Yes"></FormRef>
</StudyEventDef>
<FormDef OID="F01" Name="Some form name 01" Repeating="No">
<ItemGroupRef ItemGroupOID="IG01" Mandatory="Yes"></ItemGroupRef>
</FormDef>
<FormDef OID="F02" Name="Some form name 02" Repeating="No">
<ItemGroupRef ItemGroupOID="IG02" Mandatory="Yes"></ItemGroupRef>
<ItemGroupRef ItemGroupOID="IG03" Mandatory="No"></ItemGroupRef>
</FormDef>
<ItemGroupDef OID="IG01" Name="F01-Ungrouped" Repeating="No" SASDatasetName="UNGROUPE">
<ItemRef ItemOID="I01" OrderNumber="1" Mandatory="Yes"></ItemRef>
<ItemRef ItemOID="I02" OrderNumber="2" Mandatory="Yes"></ItemRef>
<ItemRef ItemOID="I03" OrderNumber="3" Mandatory="Yes"></ItemRef>
</ItemGroupDef>
<ItemGroupDef OID="IG02" Name="Reasons2" Repeating="Yes" SASDatasetName="REASONS2">
<ItemRef ItemOID="I04" OrderNumber="1" Mandatory="No"></ItemRef>
</ItemGroupDef>
<ItemGroupDef OID="IG03" Name="F02-Ungrouped" Repeating="No" SASDatasetName="UNGRO002">
<ItemRef ItemOID="I05" OrderNumber="1" Mandatory="Yes"></ItemRef>
<ItemRef ItemOID="I06" OrderNumber="2" Mandatory="Yes"></ItemRef>
</ItemGroupDef>
</MetaDataVersion>
</Study>
</ODM>
Note: Overwriting indentity rule. Keys for cross reference. Node set keys.
From Comments:
One question: the XSLT outputs elements like this
<FormRef FormOID="F01" Mandatory="Yes"></FormRef>
when the original elements was<FormRef FormOID="F01" Mandatory="Yes"/>
. Both of these are correct by XML standards, but is there a way to tell XSLT to output elements in the same exact format?
Maybe (Tested with MSXSL, Altova, Saxon, Oracle, XQSharp)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kOIDbyItemGroup" match="FormDef/@OID"
use="../ItemGroupRef/@ItemGroupOID"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]">
<xsl:element name="{name()}">
<xsl:apply-templates select="@*"/>
</xsl:element>
</xsl:template>
<xsl:template match="ItemGroupDef/@Name[.='Ungrouped']">
<xsl:attribute name="Name">
<xsl:value-of select="concat(key('kOIDbyItemGroup',../@OID),
'-',.)"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Output:
<ODM FileOID="some oid" Description="some desc" CreationDateTime="2010-10-06T22:35:00-06:00" FileType="Snapshot">
<Study OID="S_TEST">
<GlobalVariables>
<StudyName>Study_Name</StudyName>
<StudyDescription>
Some study description
</StudyDescription>
<ProtocolName>Some protocol name</ProtocolName>
</GlobalVariables>
<MetaDataVersion OID="v1.0.0" Name="MetaDataVersion_v1.0.0">
<Protocol>
<StudyEventRef StudyEventOID="SE01" OrderNumber="36" Mandatory="Yes"/>
<StudyEventRef StudyEventOID="SE02" OrderNumber="37" Mandatory="Yes"/>
</Protocol>
<StudyEventDef OID="SE01" Name="Some name 01" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"/>
<FormRef FormOID="F02" Mandatory="Yes"/>
</StudyEventDef>
<StudyEventDef OID="SE02" Name="Some name 02" Repeating="No" Type="Scheduled">
<FormRef FormOID="F01" Mandatory="Yes"/>
<FormRef FormOID="F02" Mandatory="Yes"/>
</StudyEventDef>
<FormDef OID="F01" Name="Some form name 01" Repeating="No">
<ItemGroupRef ItemGroupOID="IG01" Mandatory="Yes"/>
</FormDef>
<FormDef OID="F02" Name="Some form name 02" Repeating="No">
<ItemGroupRef ItemGroupOID="IG02" Mandatory="Yes"/>
<ItemGroupRef ItemGroupOID="IG03" Mandatory="No"/>
</FormDef>
<ItemGroupDef OID="IG01" Name="F01-Ungrouped" Repeating="No" SASDatasetName="UNGROUPE">
<ItemRef ItemOID="I01" OrderNumber="1" Mandatory="Yes"/>
<ItemRef ItemOID="I02" OrderNumber="2" Mandatory="Yes"/>
<ItemRef ItemOID="I03" OrderNumber="3" Mandatory="Yes"/>
</ItemGroupDef>
<ItemGroupDef OID="IG02" Name="Reasons2" Repeating="Yes" SASDatasetName="REASONS2">
<ItemRef ItemOID="I04" OrderNumber="1" Mandatory="No"/>
</ItemGroupDef>
<ItemGroupDef OID="IG03" Name="F02-Ungrouped" Repeating="No" SASDatasetName="UNGRO002">
<ItemRef ItemOID="I05" OrderNumber="1" Mandatory="Yes"/>
<ItemRef ItemOID="I06" OrderNumber="2" Mandatory="Yes"/>
</ItemGroupDef>
</MetaDataVersion>
</Study>
</ODM>
精彩评论