For XML Transformation, i have to transform XML in such a way in adds counter value to all child node attribute Below is my xml sample
<hs>
<hscode>
<hsdetail>
<Name>Shirt</Name>
<ItemPrice>30</ItemPrice>
</hsdetail>
<hsdetail>
<Name>Shirt</Name>
<ItemPrice>30</ItemPrice>
</hsdetail>
</hscode>
</hs>
Using Xslt i want to apply counter on each child nodes of , id there are multiple hsdetails, each attribute in this node will use counter, and so on, Theconverted xml looks like below
<hs>
<hscode>
<hsdetail>
<Name1>Shirt</Name1>
<ItemPrice1>30</ItemPrice1>
</hsdetail>
<hsdetail>
<Name2>Shirt</Name2>
<ItemPrice2>30</ItemPrice2>
</hsdetail>
</hscode>
</hs>
I am using xsl but does not seems to be working when applying transformation
Any help on this? The xsl is as follows:
<xsl:stylesheet xmlns:xsl="w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="hsdetail/*">
<xsl:element
name="{name()}{count(preceding-sibling::*[name() = name(current())]) + 1}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template> </xsl:stylesheet>
How about:
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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="hsdetail">
<xsl:variable name="i" select="position()" />
<xsl:copy>
<xsl:for-each select="*">
<xsl:element name="{name()}{$i}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Related
Is there a way for me to update the label element to Selma if "LastName" exists and if the label LastName doesn't exist then add the "LastName" and "label" elements to the XML?
<xml>
<udfs>
<udf>
<desc>FirstName</desc>
<label>Sam</label>
</udf>
<udf>
<desc>LastName</desc>
<label>Selman</label>
</udf>
</udfs>
</xml>
Here's what I have right now:
<xsl:stylesheet>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="udf[desc='LastName']/fieldValue">
<xsl:value-of select="'Selma'"/>
</xsl:template>
<xsl:template match="udf[not(desc='LastName')]">
<desc>LastName</desc>
<label>Selma</label>
</xsl:template>
</xsl:stylesheet>
I think you want to 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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="udf[desc='LastName']/label">
<label>Selma</label>
</xsl:template>
<xsl:template match="udfs[not(udf/desc='LastName')]">
<xsl:copy>
<xsl:apply-templates/>
<udf>
<desc>LastName</desc>
<label>Selma</label>
</udf>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I have an xml with subelements and need to change one of the subelement to attribute using XSLT 1.0
<TransportationRequest>
<actionCode>01</actionCode>
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
The Expected xml is as below using the XSLT code:
<TransportationRequest actionCode="01">
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
First, close the root tag on your xml:
<TransportationRequest>
<actionCode>01</actionCode>
<ContractConditionCode>DC</ContractConditionCode>
<ShippingTypeCode>17</ShippingTypeCode>
<MovementTypeCode>3</MovementTypeCode>
<DangerousGoodsIndicator>false</DangerousGoodsIndicator>
<DefaultCurrencyCode>SAR</DefaultCurrencyCode>
</TransportationRequest>
then this xsl will do what you asked for:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" />
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<!-- Copy every node as is -->
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TransportationRequest">
<!-- transform the TransportationRequest node in a special way -->
<xsl:element name="TransportationRequest">
<xsl:attribute name="actionCode"><xsl:value-of select="actionCode" /></xsl:attribute>
<!-- don't transform the actionCode node (is in the attribute) -->
<xsl:apply-templates select="#*|node()[name()!='actionCode']"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
You could to it like this :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="TransportationRequest">
<xsl:copy>
<xsl:attribute name="actionCode">
<xsl:value-of select="actionCode"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="actionCode"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
See it working here : https://xsltfiddle.liberty-development.net/naZYrpW/1
Input XML is
<Operations>
<ID>10</ID>
<UserArea>
<AdditionalPhantomInformation>
<PhantomItem>
<ItemCode>41341288</ItemCode>
<SubComponent>40241289</SubComponent>
<Position>1</Position>
</PhantomItem>
</AdditionalPhantomInformation>
</UserArea>
<ConsumedItem>
<LineNumber>3</LineNumber>
<ParentItem>40241288</ParentItem>
</ConsumedItem>
<UserArea>
<AdditionalPhantomInformation>
<PhantomItem>
<ItemCode>41341288</ItemCode>
<SubComponent>40241302</SubComponent>
<Position>5</Position>
</PhantomItem>
</AdditionalPhantomInformation>
</UserArea>
</Operations>
And my expected output is
<Operations>
<ID>10</ID>
<UserArea>
<AdditionalPhantomInformation>
<PhantomItem>
<ItemCode>41341288</ItemCode>
<SubComponent>40241289</SubComponent>
<Position>1</Position>
</PhantomItem>
<PhantomItem>
<ItemCode>41341288</ItemCode>
<SubComponent>40241302</SubComponent>
<Position>5</Position>
</PhantomItem>
</AdditionalPhantomInformation>
</UserArea>
<ConsumedItem>
<LineNumber>3</LineNumber>
<ParentItem>40241288</ParentItem>
</ConsumedItem>
</Operations>
I have searched various sources and tried, but i'm unable to get the xslt right. I don't know how to use xsl:for-each-group. Please help. I'm using XSLT 2.0.
You don't necessarily need xsl:for-each-group here, as all you are doing is combining specific nodes into one.
Start off with the identity template...
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
Or, if you could use XSLT 3.0....
<xsl:mode on-no-match="shallow-copy"/>
Then have a template matching the first UserArea which does the combining...
<xsl:template match="UserArea[1]">
<xsl:copy>
<xsl:apply-templates select="node()|following-sibling::UserArea/node()" />
</xsl:copy>
</xsl:template>
You would then just need another template to ensure the other UserArea elements are not output in their original position.
<xsl:template match="UserArea" />
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="UserArea[1]">
<xsl:copy>
<xsl:apply-templates select="node()|following-sibling::UserArea/node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="UserArea" />
</xsl:stylesheet>
Note, if you did want to use xsl:for-each-group you would do it this way
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Operations">
<xsl:copy>
<xsl:for-each-group select="*" group-by="name()">
<xsl:choose>
<xsl:when test="current-grouping-key() = 'UserArea'">
<xsl:copy>
<xsl:apply-templates select="current-group()/node()" />
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This has the advantage of being easily extended if you had nodes other than UserArea you wished to combine.
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<web-inf metadata-complete="true">
<A>
<A1>DGDDG</A1>
<A1>TYTY</A1>
</A>
</web-inf>
When i am applying my transforms then the O/P XML is just dumping the <web-inf> tag without the metadata-complete="true" i.e as below
<?xml version="1.0" encoding="UTF-8"?>
<web-inf>
<A>
<A1>DGDDG</A1>
<A1>TYTY</A1>
</A>
</web-inf>
My XSLT Transform file has below in the beginning.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="web-inf[not(A/A1='hello')]">
<xsl:copy>
<xsl:call-template name="XXX"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Not sure what going wrong here.
Any suggestions?
<xsl:copy> copies only the current node, but not any attributes or child nodes. You are already catering for the child nodes with <xsl:apply-templates /> (which is equivalent to <xsl:apply-templates select="node()" />), but you also need to handle selecting attributes separately.
<xsl:template match="web-inf[not(A/A1='hello')]">
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:call-template name="XXX"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
Below Is My Input XML.
<ServiceIncident xmlns="http://b2b.ibm.com/schema/IS_B2B_CDM/R2_2">
<ProviderID>INC0011731</ProviderID>
<ProviderPriority>4</ProviderPriority>
<WorkflowStatus>NEW</WorkflowStatus>
<ServiceProvider1>
<Person Role="AffectedUser">
<ContactID>ITELLA_BRIDGE_USER</ContactID>
<FullName>Chad Whaley</FullName>
</Person>
</ServiceProvider1>
Below is my XSL
<xsl:template match="r2:Person/#Role">
<xsl:attribute name="Role">Owner</xsl:attribute>
</xsl:template>
<xsl:template match="r2:Person/#Role">
<xsl:attribute name="Role">ReportedBy</xsl:attribute>
</xsl:template>
My issue is i want to get these 2 fields in output replacing the old one in input.Iam able to get one value in output but iam not getting other value.
I put on a space as a separator between attributes:
<xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:r2="http://b2b.ibm.com/schema/IS_B2B_CDM/R2_2" exclude-result-prefixes="r2">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="r2:Person">
<xsl:copy>
<xsl:attribute name="Role">Owner ReportedBy</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>