Removing duplicate records from xml - xslt

<?xml version="1.0" encoding="utf-8"?>
<Employee_Data>
<Employee>
<NEW_HIRE_OR_REHIRE />
<RETIREMENT_BENEFITS />
<ADDRESS />
<PERSONAL>
<Record>
<SSN>327408678</SSN>
<WDEmpID>10032417</WDEmpID>
<Initiator />
<Effective>20141014</Effective>
<SeqNum>320</SeqNum>
<Last_Name>VAN TREECK</Last_Name>
<First_Name>DENISE</First_Name>
<Middle_Name>J</Middle_Name>
<Social_Suffix />
<Birth_Date>19560422</Birth_Date>
<Gender>F</Gender>
<Ethnicity>0</Ethnicity>
<Marital_Status_Date>19781202</Marital_Status_Date>
<Marital_Status>M</Marital_Status>
<CITIZENSHIP />
<Military_Service_Status />
<Disability />
<Indicator>PersonalRecordChangesIndicator</Indicator>
</Record>
</PERSONAL>
<STATUS />
<POSITION>
<Record>
<SSN>327408678</SSN>
<WDEmpID>10032417</WDEmpID>
<Initiator />
<Effective>20141006</Effective>
<SeqNum>250</SeqNum>
<ActionCode />
<DEFAULTJOBCODE>YYY01</DEFAULTJOBCODE>
<SAPJOBCODE>30000715</SAPJOBCODE>
<PayEntity>NC1</PayEntity>
<DIVISION>CORP</DIVISION>
<ORGANIZATION>GES</ORGANIZATION>
<COMPANYNUMBER>01</COMPANYNUMBER>
<LEDGERDEPARTMENT>CHEN050D</LEDGERDEPARTMENT>
<SALARY_GRADE>LC008</SALARY_GRADE>
<TEMPORARY_POSITION_INDICATOR_FOR_POSITION_RECORD />
<LocationCode>AP10</LocationCode>
<LocationDepartment>050D</LocationDepartment>
<WDEmpID>10032417</WDEmpID>
<Indicator>Position and Location Change Indicator</Indicator>
</Record>
<Record>
<SSN>327408678</SSN>
<WDEmpID>10032417</WDEmpID>
<Initiator />
<Effective>20141006</Effective>
<SeqNum>250</SeqNum>
<ActionCode />
<DEFAULTJOBCODE>YYY01</DEFAULTJOBCODE>
<SAPJOBCODE>30000715</SAPJOBCODE>
<PayEntity>NC1</PayEntity>
<DIVISION>CORP</DIVISION>
<ORGANIZATION>GES</ORGANIZATION>
<COMPANYNUMBER>01</COMPANYNUMBER>
<LEDGERDEPARTMENT>CHEN050D</LEDGERDEPARTMENT>
<SALARY_GRADE>LC008</SALARY_GRADE>
<TEMPORARY_POSITION_INDICATOR_FOR_POSITION_RECORD />
<LocationCode>AP10</LocationCode>
<LocationDepartment>050D</LocationDepartment>
<WDEmpID>10032417</WDEmpID>
<Indicator>Position and Location Department change Indicator
</Indicator>
</Record>
</POSITION>
<COMPENSATION />
<SALES_TERRITORY />
<TERMINATION />
</Employee>
</Employee_Data>
This is an xml generated by 1 xslt. I basically want to check if 2 records under Position tab are similar then keep only 1 else keep both of them. In this case the output should be like as given below.
<?xml version="1.0" encoding="utf-8"?>
<Employee_Data>
<Employee>
<NEW_HIRE_OR_REHIRE />
<RETIREMENT_BENEFITS />
<ADDRESS />
<PERSONAL>
<Record>
<SSN>327408678</SSN>
<WDEmpID>10032417</WDEmpID>
<Initiator />
<Effective>20141014</Effective>
<SeqNum>320</SeqNum>
<Last_Name>VAN TREECK</Last_Name>
<First_Name>DENISE</First_Name>
<Middle_Name>J</Middle_Name>
<Social_Suffix />
<Birth_Date>19560422</Birth_Date>
<Gender>F</Gender>
<Ethnicity>0</Ethnicity>
<Marital_Status_Date>19781202</Marital_Status_Date>
<Marital_Status>M</Marital_Status>
<CITIZENSHIP />
<Military_Service_Status />
<Disability />
<Indicator>PersonalRecordChangesIndicator</Indicator>
</Record>
</PERSONAL>
<STATUS />
<POSITION>
<Record>
<SSN>327408678</SSN>
<WDEmpID>10032417</WDEmpID>
<Initiator />
<Effective>20141006</Effective>
<SeqNum>250</SeqNum>
<ActionCode />
<DEFAULTJOBCODE>YYY01</DEFAULTJOBCODE>
<SAPJOBCODE>30000715</SAPJOBCODE>
<PayEntity>NC1</PayEntity>
<DIVISION>CORP</DIVISION>
<ORGANIZATION>GES</ORGANIZATION>
<COMPANYNUMBER>01</COMPANYNUMBER>
<LEDGERDEPARTMENT>CHEN050D</LEDGERDEPARTMENT>
<SALARY_GRADE>LC008</SALARY_GRADE>
<TEMPORARY_POSITION_INDICATOR_FOR_POSITION_RECORD />
<LocationCode>AP10</LocationCode>
<LocationDepartment>050D</LocationDepartment>
<WDEmpID>10032417</WDEmpID>
<Indicator>Position and Location Change Indicator</Indicator>
</Record>
</POSITION>
<COMPENSATION />
<SALES_TERRITORY />
<TERMINATION />
</Employee>
</Employee_Data>

To remove the duplicate records, you can use Muenchian Grouping:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="seqNumByRecord" match="Record" use="SeqNum"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"Record[not(generate-id() = generate-id(key('seqNumByRecord', SeqNum)[1]))]"
/>
</xsl:stylesheet>
The first template is an identity transform that matches all attributes and nodes and copies them. The second template is an empty template that matches all duplicates. Because the template is empty, these Records will be removed. For a detailed explanation of Muenchian Grouping this article by Jeni Tennison is recommended: http://www.jenitennison.com/xslt/grouping/muenchian.html, and you will also find many excellent answers on Stackoverflow.
For variety, a second solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Record[SeqNum = following::Record/SeqNum]"/>
</xsl:stylesheet>
In this approach, the empty template for removing the duplicates matches all Records that have the same SeqNum as following Records. As you'll find in the mentioned article, the Muenchian method is considered to be more efficient.

Related

Selecting distinct values from XSLT sub query

I have this XML document:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<properties>
<property name="prop1" type="type1"/>
<property name="prop2" type="type2"/>
<property name="prop3" type="type3"/>
<property name="prop4" type="type1"/>
</properties>
<types>
<type name="type1" group="group1"/>
<type name="type2" group="group1"/>
<type name="type3" group="group2"/>
<type name="type4" group="group3"/>
</types>
<groups>
<group name="group1" owner="owner1"/>
<group name="group2" owner="owner2"/>
<group name="group3" owner="owner3"/>
</groups>
</metadata>
I am transforming it using this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="docRoot" select="/" />
<xsl:for-each select="distinct-values($docRoot/metadata/properties/property/#type)">
<xsl:variable name="groupOwner" select="$docRoot/metadata/groups/group[#name=$docRoot/metadata/types/type[#name=current()]/#group]/#owner" />
<xsl:value-of select="$groupOwner"/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
What I want to do is print out the list of unique group owners for all of the properties in the document. I'm successfully filtering out duplicate types with distinct-values but can't see how to filter out duplicate owners.
The current output:
owner1
owner1
owner2
The required output:
owner1
owner2
If it helps no two groups have the same owner.
Keys can be your friend here...
<xsl:key name="types" match="type" use="#name" />
<xsl:key name="groups" match="group" use="#name" />
Then you can do this, without even any need for distinct-values because you won't get duplicate nodes returned this way:
<xsl:for-each select="key('groups', key('types', metadata/properties/property/#type)/#group)">
For example, try this XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:key name="types" match="type" use="#name" />
<xsl:key name="groups" match="group" use="#name" />
<xsl:template match="/">
<xsl:for-each select="key('groups', key('types', metadata/properties/property/#type)/#group)">
<xsl:value-of select="concat(#owner, '
')" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
In fact, you can simplify the xsl:for-each to this:
<xsl:value-of select="key('groups', key('types', metadata/properties/property/#type)/#group)/#owner" separator="
" />
Ah, just needed to try a bit harder:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="docRoot" select="/" />
<xsl:for-each select="distinct-values($docRoot/metadata/groups/group[#name=$docRoot/metadata/types/type[#name=$docRoot/metadata/properties/property/#type]/#group]/#owner)">
<xsl:value-of select="current()"/><xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Open to any suggestions for simplifying this though!

XSL to get values from nodes basing on the attribute value match

I am pretty much new to xsl.Currently facing a challenge in transforming the below sample xml to required output.
Sample XML:
<root>
<types>
<entity-type>
<field-type identifier="FieldType1" proxy-ref="TypeA">
<object-name>aclProxy</object-name>
<persistence-class-name>java.lang.Long</persistence-class-name>
</field-type>
<field-type identifier="FieldType2" proxy-ref="TypeB">
<object-name>aclName</object-name>
<persistence-class-name>java.lang.String</persistence-class-name>
</field-type>
</entity-type>
</types>
<custom>
<category identifier="parent" order="1">
<name>%category.parent</name>
</category>
<category identifier="texts" order="2">
<name>%category.Texts</name>
</category>
<field identifier="ArticleID" category-ref="parent" field-type-ref="FieldType1" proxy-entity-ref="ABC">
<name>%field.name</name>
<description>%field.Article.description</description>
</field>
<field identifier="ArticleName" category-ref="texts" field-type-ref="FieldType2" proxy-entity-ref="ABCD">
<name>%field.name.text</name>
<description>%field.Articletext.description</description>
</field>
</custom>
</root>
Output
<field identifier="ArticleID">
<name>%field.name</name>
<description>%field.Article.description</description>
<category-ref-name>%category.parent</category-ref-name>
<field-type-ref>Long</field-type-ref>
<proxy-entity-ref>TypeA</proxy-entity-ref>
</field>
<field identifier="ArticleName" >
<name>%field.name.text</name>
<description>%field.Articletext.description</description>
<category-ref-name>%category.Texts</category-ref-name>
<field-type-ref>String</field-type-ref>
<proxy-entity-ref>TypeB</proxy-entity-ref>
</field>
XSLT which I have been trying:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="category" match="category" use="#identifier" />
<xsl:key name="field" match="field" use="#category-ref" />
<xsl:apply-templates select="custom[not(key('field',category/#identifier))]"/>
<xsl:template match="/">
<xsl:text>something</xsl:text>
<xsl:value-of select="category/#identifier"/>
<xsl:apply-templates select="."/>
</xsl:template>
<xsl:template match="/">
<xsl:value-of select="field/#identifier"/>
<xsl:variable name="categoryparam" select="key('category', field/#category-ref)" />
<xsl:if test="$categoryparam">
<xsl:apply-templates select="$categoryparam"/>
<xsl:text>something</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Basically the output should have only field(s) in it referring to the attributes and get the node values.
Any help is much appreciated.
Thanks in advance.
Let us start off with these 2 keys:
<xsl:key name="kCategory" match="category" use="#identifier" />
<xsl:key name="kFieldID" match="field-type" use="#identifier" />
you will need the values in category and field-type nodes later.
This template:
<xsl:template match="/">
<xsl:apply-templates select="root/custom/field"/>
</xsl:template>
will output the target field nodes
Having a template match with the field node to further manipuate the output:
<xsl:template match="field">
<xsl:copy>
<!-- copies the identifier attribute and all children -->
<xsl:copy-of select="#identifier|node()"/>
<category-ref-name>
<!-- gets the child name of the target category node
that matches the category-ref attribute -->
<xsl:value-of select="key('kCategory', #category-ref)/name"/>
</category-ref-name>
<field-type-ref>
<!-- gets the child persistence-class-name of the target
field-type node that matches the field-type-ref attribute,
with further substring manipulations -->
<xsl:value-of select="substring-after(key('kFieldID', #field-type-ref)/persistence-class-name, 'java.lang.')"/>
</field-type-ref>
<proxy-entity-ref>
<!-- gets the attribute proxy-ref of the target
field-type node that matches the field-type-ref
attribute -->
<xsl:value-of select="key('kFieldID', #field-type-ref)/#proxy-ref"/>
</proxy-entity-ref>
</xsl:copy>
</xsl:template>
The whole stylesheet is below:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="kCategory" match="category" use="#identifier" />
<xsl:key name="kFieldID" match="field-type" use="#identifier" />
<xsl:template match="/">
<xsl:apply-templates select="root/custom/field"/>
</xsl:template>
<xsl:template match="field">
<xsl:copy>
<xsl:copy-of select="#identifier|node()"/>
<category-ref-name>
<xsl:value-of select="key('kCategory', #category-ref)/name"/>
</category-ref-name>
<field-type-ref>
<xsl:value-of select="substring-after(key('kFieldID', #field-type-ref)/persistence-class-name, 'java.lang.')"/>
</field-type-ref>
<proxy-entity-ref>
<xsl:value-of select="key('kFieldID', #field-type-ref)/#proxy-ref"/>
</proxy-entity-ref>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
See it in action (http://xsltfiddle.liberty-development.net/gWmuiJc).

xsl copy if attribute of current node equals to attribute of another node

I have a sample XML File:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<MetaData>
<Ref MDID='ID'></Ref>
</MetaData>
<MetaData2>
<Ref MDID='ID2'></Ref>
</MetaData2>
<Items ID='ID'>
<Item OID='haveit'></Item>
<Item OID='ornot'></Item>
</Items>
<Items ID= ID2'>
<Item OID='ornot'></Item>
<Item OID='ornot'></Item>
</Items>
</XML>
I have to transform it so that I receive the following result.
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<MetaData>
<Ref MDID='ID'></Ref>
</MetaData>
<Items ID='ID'>
<Item OID='haveit'></Item>
</Items>
</XML>
So first I have to check if the Item 'haveit' exists. Then I copy the corresponding parent "Item". Then I need to copy the MetaData where the MDID equals to the Items ID (in this case 'ID', but I don't know the exact value in my real example)
What I have so far:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="Item" select = "'haveit'"/>
<xsl:template match="XML">
<xsl:copy>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="Items">
<xsl:if test="child::Item[#OID = $Item]">
<xsl:copy>
<xsl:copy-of select="#*" /> <!-- copy attributes -->
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
With this code I'm able to copy the Item I want and the corresponding Items Element. Now I don't know how to get the right MetaData element. How can I check if the MDID of Ref hase the same value as the Items ID?
How about:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="oid" select="'haveit'"/>
<xsl:key name="meta" match="*" use="Ref/#MDID" />
<xsl:template match="/XML">
<xsl:variable name="matching-items" select="Items[Item/#OID=$oid]" />
<xsl:copy>
<xsl:copy-of select="key('meta', $matching-items/#ID)"/>
<xsl:apply-templates select="$matching-items"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Items">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:copy-of select="Item[#OID=$oid]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

XSLT v1.0 Updating attribute in node-set based on previous node's attribute

I have the following XML file.
<Record
Name="My_Record"
<Fields
StartingBit="0"
Size="3"
Name="Field_1">
</Fields>
<Fields
StartingBit="1"
Size="5"
Name="Field_2">
</Fields>
<Fields
StartingBit="2"
Size="8"
Name="Field_3">
</Fields>
<Fields
StartingBit="3"
Size="4"
Name="Field_4"
</Fields>
</Record>
And I would like to use XSLT to properly update the #StartingBit attribute from the previous node's #StartingBit + #Size - this will be the current node's #StartingBit value. The resulting XML should be as follows:
<Record
Name="My_Record"
<Fields
StartingBit="0"
Size="3"
Name="Field_1">
</Fields>
<Fields
StartingBit="3"
Size="5"
Name="Field_2">
</Fields>
<Fields
StartingBit="8"
Size="8"
Name="Field_3">
</Fields>
<Fields
StartingBit="16"
Size="4"
Name="Field_4"
</Fields>
</Record>
So far, my latest attempts to my XSLT is as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match ="Fields/#StartingBit">
<xsl:value-of select ="(preceding-sibling::Fields[1]/#StartingBit + preceding-sibling::Fields[1]/#Size)"/>
</xsl:template>
</xsl:stylesheet>
The above transform does not generate what I would like - basically #StartingBit does not change. I am not proficicent in node navigation to get the results I like - can someone assist in my transform? Thank you in advance.
Lorentz
When this simple XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="vStartingBit" select="/*/Fields[1]/#StartingBit" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Fields[position() > 1]">
<xsl:copy>
<xsl:attribute name="StartingBit">
<xsl:value-of
select="$vStartingBit + sum(preceding-sibling::Fields/#Size)" />
</xsl:attribute>
<xsl:apply-templates select="#*[not(name() = 'StartingBit')]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...is applied to the original XML (corrected to be well-formed):
<?xml version="1.0" encoding="utf-8"?>
<Record Name="My_Record">
<Fields StartingBit="0" Size="3" Name="Field_1" />
<Fields StartingBit="1" Size="5" Name="Field_2" />
<Fields StartingBit="2" Size="8" Name="Field_3" />
<Fields StartingBit="3" Size="4" Name="Field_4" />
</Record>
...the expected result is produced:
<?xml version="1.0"?>
<Record Name="My_Record">
<Fields StartingBit="0" Size="3" Name="Field_1" />
<Fields StartingBit="3" Size="5" Name="Field_2" />
<Fields StartingBit="8" Size="8" Name="Field_3" />
<Fields StartingBit="16" Size="4" Name="Field_4" />
</Record>
Explanation:
The first template is the Identity Template. Its purpose is to copy all nodes and attributes from the source document to the result document as-is.
One template overrides the Identity Template. It's purpose is to add the original starting bit to the correct #Size attributes (those that precede the current <Fields> element), which forms the value of each subsequent <Fields> element's #StartingBit attribute.

xpath get matches in sublist

I've got the following xml:
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="descriptione" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
I'm using XSLT to transform it, and I'm need, for each update, to get the fields in the vo that correspond to the field defined in the input. It would be something like this:
<xsl:variable name="fields" select="vo/field" />
<xsl:for-each select="update">
<xsl:variable name='fieldsForInput' select = "$fields[#name]=input/fields[#name]"/>
<xsl:for-each select="$fieldsForInput">
<xsl:value-of select="#type"/> <xsl:value-of select="#name"/>
<xsl:for-each>
</xsl:for-each>
But it doesn't found anything. Any ideas?
Thanks
JL
From the shown fragments it's difficult helping you and understadning what you want. However your case seems perfect for using xsl:key.
For example, if you create a key at the beginning of the transform like this:
<xsl:key name="fields" match="vo/field" use="#name"/>
You can use it inside your matching template as follows:
<xsl:for-each select="update/input">
<xsl:copy-of select="key('fields',current()/field/#name)"/>
</xsl:for-each>
I would not use a xsl:foreach anyway. But it's hard to give you a complete solution if you provide only fragments. Also is not clear if you want just match or replace field.
Example showing how to get the field name/type for each update/input/field.
XSLT 1.0 tested with Saxon 6.5.5
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="fields" match="vo/field" use="#name"/>
<xsl:template match="/root">
<xsl:apply-templates select="update"/>
</xsl:template>
<xsl:template match="update">
<xsl:value-of select="concat('-',#method,'
')"/>
<xsl:apply-templates select="input/field"/>
</xsl:template>
<xsl:template match="input/field">
<xsl:value-of select="concat('--',#name,' ',key('fields',#name)/#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
Applied on:
<root>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
<update method="deleteMember" modificationMode="DELETE_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</root>
Produces:
-addMember
--member String[]
--description String
-deleteMember
--member String[]
--description String
Two solutions:
Solution1 (no keys):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match=
"vo/field[#name=../../update/*/*/#name]">
<xsl:value-of select="concat(#name,' ',#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
When applied on the provided XML document (corrected to be made well-formed):
<t>
<vo class="GroupEntry" buildByAlias="true">
<objectClass name="groupOfNames"/>
<field name="commonName" nameLDAP="cn" type="String"/>
<field name="description" nameLDAP="description" type="String"/>
<field name="member" nameLDAP="member" type="String[]"/>
</vo>
<update method="addMember" modificationMode="ADD_ATTRIBUTE">
<input>
<field name="member"/>
<field name="description"/>
</input>
</update>
</t>
the wanted, correct result is produced:
description String
member String[]
Solution2 (using a key):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFieldByName" match="vo/field"
use="#name"/>
<xsl:template match="/*">
<xsl:apply-templates mode="selected" select=
"key('kFieldByName', update/*/*/#name)"/>
</xsl:template>
<xsl:template match="vo/field" mode="selected">
<xsl:value-of select="concat(#name,' ',#type,'
')"/>
</xsl:template>
</xsl:stylesheet>
when applied on the same XML document (above), the same correct result is produced:
description String
member String[]