I am trying to convert the following input XML based on grouping of qualifier but its not working and not giving me expected output.
Below is the Input XML which has to be comverted.
<document>
<item>
<gtin>1000909090</gtin>
<attrGroupMany name="foodAndBevPreparationInfo">
<row>
<attr name="preparationType">BOILING</attr>
<attrQualMany name="preparationInstructions">
<value qual="en">Prep 8</value>
<value qual="en">Prep 9</value>
<value qual="ar">Test</value>
</attrQualMany>
</row>
</attrGroupMany>
</item>
</document>
The XSLT which I am using but not giving me expected output.
XSLT:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="prepmvl" match="preparationInstructions" use="concat(generate-id(..), '|', #qual)" />
<xsl:template match="document">
<CatalogItem>
<RelationshipData>
<xsl:for-each select="item/attrGroupMany[#name ='foodAndBevPreparationInfo']/row">
<Relationship>
<RelationType>Item_Master_Food_And_Bev_Prep_MVL</RelationType>
<RelatedItems count="{count(attrQualMany[#name='preparationInstructions']/value[generate-id() = generate-id(key('prepmvl', concat(generate-id(..), '|', #qual))[1])])}">
<xsl:apply-templates select="attrQualMany[#name='preparationInstructions']/value[generate-id() = generate-id(key('prepmvl', concat(generate-id(..), '|', #qual))[1])]"/>
</RelatedItems>
</Relationship>
</xsl:for-each>
</RelationshipData>
</CatalogItem>
</xsl:template>
<xsl:template match="preparationInstructions">
<RelatedItem1 referenceKey="{concat('Food_And_Bev_Prep_MVL','-',ancestor::item/gtin,'-',attr[#name='preparationType'],'-',#qual)}"/>
</xsl:template>
</xsl:stylesheet>
And the expected output should be
<?xml version="1.0" encoding="UTF-8"?>
<CatalogItem>
<RelationshipData>
<Relationship>
<RelationType>Item_Master_Food_And_Bev_Prep_MVL</RelationType>
<RelatedItems count="2">
<RelatedItem1 referenceKey="Food_And_Bev_Prep_MVL-1000909090-BOILING-en" />
<RelatedItem1 referenceKey="Food_And_Bev_Prep_MVL-1000909090-BOILING-ar" />
</RelatedItems>
</Relationship>
</RelationshipData>
</CatalogItem>
you need to change
<xsl:key name="prepmvl" match="preparationInstructions" use="concat(generate-id(..), '|', #qual)" />
to
<xsl:key name="prepmvl" match="value" use="concat(generate-id(..), '|', #qual)" />
and
<xsl:template match="preparationInstructions">
<RelatedItem1 referenceKey="{concat('Food_And_Bev_Prep_MVL','-',ancestor::item/gtin,'-',attr[#name='preparationType'],'-',#qual)}"/>
</xsl:template>
to
<xsl:template match="value">
<RelatedItem1 referenceKey="{concat('Food_And_Bev_Prep_MVL','-',ancestor::item/gtin,'-',../preceding-sibling::attr[#name='preparationType'],'-',#qual)}"/>
</xsl:template>
Related
I am new to XSLT, and I am trying to create new group based on node value eventType so if eventType is alert, create new group event.
I am checking for last sibling
Input XML
<?xml version="1.0" encoding="UTF-8"?><Rowsets >
<Row>
<eventId>2</eventId>
<plantId>1020</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>3</eventId>
<plantId>1021</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>4</eventId>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>eventtext</eventText>
<eventDesc>failed</eventDesc>
</Row>
<Row>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>Text</eventText>
<eventDesc>failed</eventDesc>
</Row>
</Rowsets>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<Rowsets>
<Alert>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
</Alert>
<Incident>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
</Incident>
</Rowsets>
Based on eventType, I want to generate group.
I am using this XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<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:template match="/">
<Rowsets>
<Rowset>
<xsl:variable name="Type" select="'alert'"/>
<xsl:for-each select="/Rowsets/Rowset/Row">
<xsl:choose>
<xsl:when test="$Type = eventType">
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:when>
<xsl:otherwise>
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Rowset>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Need help in generating id and key based on eventType
This is a grouping problem - and a rather trivial one at that. In XSLT 2.0 you could do simply:
XSLT 2.0
<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:template match="Rowsets">
<Rowsets>
<xsl:for-each-group select="Row" group-by="eventType">
<xsl:element name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<element>
<Title>
<xsl:value-of select="eventText, workCenter" separator=":"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Alternatively, with only two possible types, you could do:
XSLT 1.0
<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:template match="Rowsets">
<Rowsets>
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</Rowsets>
</xsl:template>
<xsl:template match="Row">
<element>
<Title>
<xsl:value-of select="eventText"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="workCenter"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:template>
</xsl:stylesheet>
This is assuming you don't mind creating a group even if it is empty. Otherwise you would do:
<xsl:template match="Rowsets">
<Rowsets>
<xsl:variable name="alerts" select="Row[eventType='alert']"/>
<xsl:variable name="incidents" select="Row[eventType='incident']"/>
<xsl:if test="$alerts">
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
</xsl:if>
<xsl:if test="$incidents">
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</xsl:if>
</Rowsets>
</xsl:template>
P.S. Note that XML is case-sensitive: <Alert> is not the same as <alert>.
I need to analyse the following XML input:
<LIST>
<PRODUCT TYPE="1" REP="0">
<SUB CAT="1.1" COUNT="2">
<ITEM NAME="OCC" BEGIN="0" ND="49">
</ITEM>
<ITEM NAME="OCC" BEGIN="0" END="49">
</ITEM>
</SUB>
</PRODUCT>
<PRODUCT TYPE="1" REP="1">
<SUB CAT="1.1" COUNT="1">
<ITEM NAME="PRC" BEGIN="0" END="49">
</ITEM>
</SUB>
</PRODUCT>
</LIST>
and transform it with Xslt to obtain the following result:
<LIST>
<PRODUCT TYPE="1" REP="0">
<SUB CAT="1.1" COUNT="2">
<MULTIPLE />
<ITEM NAME="OCC" BEGIN="0" END="49">
</ITEM>
<MULTIPLE />
<ITEM NAME="OCC" BEGIN="0" END="49">
</ITEM>
</SUB>
</PRODUCT>
<PRODUCT TYPE="1" REP="1">
<SUB CAT="1.1" COUNT="1">
<MULTIPLE />
<ITEM NAME="PRC" BEGIN="0" END="49">
</ITEM>
</SUB>
</PRODUCT>
</LIST>
What I need to do is to check that the BEGIN and END of the ITEMS in two different PRODUCT node are the same, and if this is the case add the MULTIPLE node as a flag.
Any idea on how to proceed?
This is how I thought it could work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//PRODUCT[#TYPE='1']/SUB[#CAT='1.1']/ITEM">
<xsl:if test="//PRODUCT[#TYPE='1']/SUB[#CAT='1.1']/ITEM /RULE (#BEGIN <= current()/#BEGIN) and (#END >= current()/#END)]">
<xsl:element name="MULTIPLE">
</xsl:element>
</xsl:if>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This can be achieved by means of a key to look up ITEM elements
<xsl:key name="item" match="ITEM" use="concat(#BEGIN, '|', #END)" />
Then, you just need a template that matches ITEM elements where there is at least 2 items in the key
<xsl:template match="ITEM[key('item', concat(#BEGIN, '|', #END))[2]]">
Using this in conjunction with the XSLT identity transform, gives you this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="item" match="ITEM" use="concat(#BEGIN, '|', #END)" />
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM[key('item', concat(#BEGIN, '|', #END))[2]]">
<MULTIPLE />
<xsl:call-template name="identity" />
</xsl:template>
</xsl:stylesheet>
If you wish to restrict it to look for matches in the same product and sub-category, change the key to this...
<xsl:key name="item" match="ITEM" use="concat(../../#TYPE, '|', ../#CAT, '|', #BEGIN, '|', #END)" />
And adjust the template match accordingly....
<xsl:template match="ITEM[key('item', concat(../../#TYPE, '|', ../#CAT, '|', #BEGIN, '|', #END))[2]]">
You can try like this way by match the ITEM context:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM">
<xsl:if test="(
(#BEGIN = ancestor::PRODUCT/following-sibling::PRODUCT/descendant::ITEM/#BEGIN) and
(#END = ancestor::PRODUCT/following-sibling::PRODUCT/descendant::ITEM/#END))
or (
(#BEGIN = ancestor::PRODUCT/preceding-sibling::PRODUCT/descendant::ITEM/#BEGIN) and
(#END = ancestor::PRODUCT/preceding-sibling::PRODUCT/descendant::ITEM/#END)
)
">
<xsl:element name="MULTIPLE"/>
</xsl:if>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
having performance issues with my xslt code:
this is my input file:
<?xml version="1.0" encoding="UTF-8"?>
<Products>
<Product ID="111111" Type="Item" ParentID="7402">
<Name>ABC</Name>
<Values>
<Value AttributeID="11">8.00</Value>
<Value AttributeID="12">8.00</Value>
<Value AttributeID="13">0.18</Value>
</Values>
<Product ID="B582B65D" Type="UID" ParentID="111111">
<Values>
<Value AttributeID="11">8.00</Value>
<Value AttributeID="12">8.00</Value>
<Value AttributeID="13">0.18</Value>
<Value AttributeID="14">0.18</Value>
</Values>
</Product>
</Product>
<Product ID="222222" Type="Item" ParentID="7402">
<Name>XYZ</Name>
<Values>
<Value AttributeID="12">8.00</Value>
<Value AttributeID="13">8.00</Value>
<Value AttributeID="15">0.18</Value>
</Values>
<Product ID="B582B65D" Type="UID" ParentID="111111">
<Values>
<Value AttributeID="11">8.00</Value>
<Value AttributeID="12">8.00</Value>
<Value AttributeID="16">0.18</Value>
<Value AttributeID="18">0.18</Value>
</Values>
</Product>
</Product>
</Products>
and this is my transformation code:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://exslt.org/math"
extension-element-prefixes="math">
<xsl:output method="xml" indent="yes" />
<xsl:param name="file2" select="document('Mapping.xml')" />
<xsl:template match="/Products">
<Products>
<xsl:for-each select="Product">
<xsl:call-template name="item" />
</xsl:for-each>
</Products>
</xsl:template>
<xsl:template name="item">
<Product type="{./#Type}" ID="{./#ID}">
<xsl:for-each select="./Values/Value">
<xsl:variable name="Idval" select="#AttributeID" />
<xsl:element name="{$file2//Groups/AttributeID[#ID=$Idval]/#group}">
<xsl:element name="{$file2//Groups/AttributeID[#ID=$Idval]}">
<xsl:attribute name="ID"><xsl:value-of select="$Idval"/></xsl:attribute>
<xsl:value-of select="." />
</xsl:element>
</xsl:element>
</xsl:for-each>
<xsl:call-template name="uid" />
</Product>
</xsl:template>
<xsl:template name="uid">
<Product type="{./Product/#Type}" ParentId="{./Product/#ParentID}">
<xsl:for-each select="./Product/Values/Value">
<xsl:variable name="Idval" select="#AttributeID" />
<xsl:element name="{$file2//Groups/AttributeID[#ID=$Idval]/#group}">
<xsl:element name="{$file2//Groups/AttributeID[#ID=$Idval]}">
<xsl:attribute name="ID"><xsl:value-of select="$Idval"/></xsl:attribute>
<xsl:value-of select="." />
</xsl:element>
</xsl:element>
</xsl:for-each>
</Product>
</xsl:template>
</xsl:stylesheet>
above xslt is using below xml file for mapping attribute id to corresponding name and group
Mapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<Groups>
<AttributeID ID="11" group="Pack1">Height</AttributeID>
<AttributeID ID="12" group="Pack2">Width</AttributeID>
<AttributeID ID="13" group="Pack1">Depth</AttributeID>
<AttributeID ID="14" group="Pack3">Length</AttributeID>
<AttributeID ID="15" group="Pack3">Lbs</AttributeID>
<AttributeID ID="16" group="Pack4">Litre</AttributeID>
</Groups>
Replace the use of expressions like
select="$file2//Groups/AttributeID[#ID=$Idval]"
with a key:
<xsl:key name="ID" match="Groups/AttributeID" use="#ID"/>
and then
select="key('ID', $IDval, $file)"/>
Alternatively, Saxon-EE will do this optimization for you automatically.
The key() function with 3 arguments is XSLT 2.0 syntax. If you have the misfortune to be using XSLT 1.0, you have to write a dummy xsl:for-each that makes $file the context item, because key() will only select within the document containing the context item.
Define a key for the cross document lookup: <xsl:key name="by-id" match="Groups/AttributeID" use="#ID"/>, then (assuming an XSLT 2.0 processor) you can simplify expressions like <xsl:element name="{$file2//Groups/AttributeID[#ID=$Idval]/#group}"> to <xsl:element name="{key('by-id', #AttributeID, $file2)/#group">. Make the same change for the other cross references you have, i.e. all those $file2//Groups/AttributeID[#ID=$Idval] expressions should use the key lookup.
Making the simplified assumption that your second file isn't too big, you want to fold the values there into your template. It would work with XSLT 1.0 too. Something like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://exslt.org/math"
extension-element-prefixes="math">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<Products>
<xsl:apply-templates select="/Products/Product" />
</Products>
</xsl:template>
<xsl:template match="Product">
<xsl:element name="Product">
<xsl:apply-templates select="#*" />
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="Name">
<Name>
<xsl:value-of select="." />
</Name>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="Values">
<Values>
<xsl:apply-templates />
</Values>
</xsl:template>
<!-- Templates for individual AttributeIDs, only when there are few -->
<xsl:template match="Value[#AttributeID='11']">
<Pack1>
<xsl:element name="Height">
<xsl:attribute name="ID">
<xsl:value-of select="#AttributeID" />
</xsl:attribute>
<xsl:value-of select="." />
</xsl:element>
</Pack1>
</xsl:template>
<!-- Repeat for the other AttributeID values -->
</xsl:stylesheet>
(Typed off my head, will contain typos)
Of course if it is big Michael's advice is the best course of action.
I have the input XML as
<document>
<item>
<gtin>4341</gtin>
<functionalName lang="en">Filte</functionalName>
<functionalName lang="en">test1</functionalName>
<functionalName lang="chi">Filters2</functionalName>
<functionalName lang="hin">Filters3</functionalName>
<gtinName lang="en">gtinName1</gtinName>
<gtinName lang="en">gtinName2</gtinName>
<gtinName lang="hin">gtinName3</gtinName>
</item>
<item>
<gtin>4342</gtin>
<functionalName lang="en">Filte</functionalName>
<functionalName lang="chi">Filters</functionalName>
<functionalName lang="en">Filters1</functionalName>
<gtinName lang="en">gtinName1</gtinName>
<gtinName lang="chi">gtinName2</gtinName>
<gtinName lang="chi">gtinName3</gtinName>
</item>
</document>
I want to loop through each language and get the count with respect to group by of language
Expected output XML should be
<?xml version="1.0" encoding="UTF-8"?>
<CatalogItem>
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="3">
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-4341-en" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-4341-chi" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-4341-hin" />
</RelatedItems>
</Relationship>
</RelationshipData>
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="2">
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-4342-en" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-4342-chi" />
</RelatedItems>
</Relationship>
</RelationshipData>
</CatalogItem>
Sample XSLT which is used by me but its not giving me expected Output
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="functional" match="gtinName" use="concat(generate-id(..), '|', #lang)" />
<xsl:template match="document">
<CatalogItem>
<xsl:for-each select="item">
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="{count(gtinName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])])}">
<xsl:apply-templates select="gtinName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])]"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</xsl:for-each>
</CatalogItem>
</xsl:template>
<xsl:template match="gtinName|functionalName">
<RelatedItem1 referenceKey="{concat('ITEM_DESCRIPTION','-',ancestor::item/gtin,'- ',#lang)}"/>
</xsl:template>
</xsl:stylesheet>
If you want the count of language attributes on either "functionName" or "gtimName" then change your key to this
<xsl:key name="functional" match="gtinName|functionalName" use="concat(generate-id(..), '|', #lang)" />
Then, to get the count of the languages, do this
count((functionalName|gtinName)[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])])}">
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="functional" match="gtinName|functionalName" use="concat(generate-id(..), '|', #lang)" />
<xsl:template match="document">
<CatalogItem>
<xsl:for-each select="item">
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<xsl:variable name="lang" select="(functionalName|gtinName)[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])]" />
<RelatedItems count="{count($lang)}">
<xsl:apply-templates select="$lang"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</xsl:for-each>
</CatalogItem>
</xsl:template>
<xsl:template match="gtinName|functionalName">
<RelatedItem1 referenceKey="{concat('ITEM_DESCRIPTION','-',ancestor::item/gtin,'- ',#lang)}"/>
</xsl:template>
</xsl:stylesheet>
As an alternative, if only "gtinName" and "functionalName" have a "lang" attribute, you could use the syntax *[#lang] instead....
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="functional" match="*[#lang]" use="concat(generate-id(..), '|', #lang)" />
<xsl:template match="document">
<CatalogItem>
<xsl:for-each select="item">
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<xsl:variable name="lang" select="*[#lang][generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])]" />
<RelatedItems count="{count($lang)}">
<xsl:apply-templates select="$lang"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</xsl:for-each>
</CatalogItem>
</xsl:template>
<xsl:template match="*[#lang]">
<RelatedItem1 referenceKey="{concat('ITEM_DESCRIPTION','-',ancestor::item/gtin,'- ',#lang)}"/>
</xsl:template>
</xsl:stylesheet>
I have the input XML as
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document>
<item>
<functionalName lang="en">Filte</functionalName>
<functionalName lang="hin">test1</functionalName>
<functionalName lang="chi">Filters2</functionalName>
<functionalName lang="hin">Filters3</functionalName>
</item>
<item>
<functionalName lang="en">Filte</functionalName>
<functionalName lang="chi">Filters</functionalName>
<functionalName lang="en">Filters1</functionalName>
</item>
And the desired output after parsing through the XSLT is mentioned below
XSLT is mentioned at the end of the query
Output XML:
<?xml version="1.0" encoding="UTF-8"?>
<CatalogItem>
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="3">
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-functionalName-en" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-functionalName-hin" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-functionalName-chi" />
</RelatedItems>
</Relationship>
</RelationshipData>
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="2">
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-functionalName-en" />
<RelatedItem1 referenceKey="ITEM_DESCRIPTION-functionalName-chi" />
</RelatedItems>
</Relationship>
</RelationshipData>
XSLT which I am using is not giving me the desired response. Please help
<xsl:output method="xml" indent="yes" />
<xsl:key name="functional" match="functionalName" use="#lang" />
<xsl:template match="document">
<CatalogItem>
<xsl:for-each select="item">
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems>
<xsl:attribute name="count">
<xsl:value-of select="count(functionalName[generate-id(.)=generate-id(key('functional',#lang)[1])])"/>
</xsl:attribute>
<xsl:apply-templates select="functionalName[generate-id(.)=generate-id(key('functional',#lang)[1])]"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</xsl:for-each>
</CatalogItem>
</xsl:template>
<xsl:template match="functionalName">
<xsl:for-each value="{#lang}">
<xsl:variable name="language" select="../#lang" />
<RelatedItem1>
<xsl:attribute name="referenceKey">
<xsl:value-of select="concat('ITEM_DESCRIPTION','-','functionalName','-',../#lang)"/>
</xsl:attribute>
</RelatedItem1>
</xsl:for-each>
</xsl:template>
Change your key from
<xsl:key name="functional" match="functionalName" use="#lang" />
to
<xsl:key name="functional" match="functionalName" use="concat(generate-id(..), '|', #lang)" />
then you can use
<RelatedItems count="{count(functionalName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])])}">
and
<xsl:apply-templates select="functionalName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])]"/>
and finally you can simplify the template for functionaName to
<xsl:template match="functionalName">
<RelatedItem1 referenceKey="{concat('ITEM_DESCRIPTION','-','functionalName','-', #lang)}"/>
</xsl:template>
So the complete samples is
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="functional" match="functionalName" use="concat(generate-id(..), '|', #lang)" />
<xsl:template match="document">
<CatalogItem>
<xsl:for-each select="item">
<RelationshipData>
<Relationship>
<RelationType>Descriptions_for_Item</RelationType>
<RelatedItems count="{count(functionalName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])])}">
<xsl:apply-templates select="functionalName[generate-id() = generate-id(key('functional', concat(generate-id(..), '|', #lang))[1])]"/>
</RelatedItems>
</Relationship>
</RelationshipData>
</xsl:for-each>
</CatalogItem>
</xsl:template>
<xsl:template match="functionalName">
<RelatedItem1 referenceKey="{concat('ITEM_DESCRIPTION','-','functionalName','-', #lang)}"/>
</xsl:template>
</xsl:stylesheet>