XSLT: Need to convert name value pair content into XML - xslt-1.0

I'm new to XSLT. I have a requirement to convert an XML containing name value pair into target XML.
I need to generate a target XML where each FieldName is an element name and it value is FieldValue. Please find below the output which I need.
Thanks in advance for the help.
Source XML:
<SC>
<Header>
<Record>
<FieldName>Schema</FieldName>
<FieldValue>OrderHeader</FieldValue>
</Record>
<Record>
<FieldName>Order</FieldName>
<FieldValue>1234</FieldValue>
</Record>
</Header>
<Detail>
<Record>
<FieldName>Schema</FieldName>
<FieldValue>OrderItem</FieldValue>
</Record>
<Record>
<FieldName>Item</FieldName>
<FieldValue>1</FieldValue>
</Record>
<Record>
<FieldName>Qty</FieldName>
<FieldValue>10</FieldValue>
</Record>
</Detail>
<Detail>
<Record>
<FieldName>Schema</FieldName>
<FieldValue>OrderItem</FieldValue>
</Record>
<Record>
<FieldName>Item</FieldName>
<FieldValue>2</FieldValue>
</Record>
<Record>
<FieldName>Qty</FieldName>
<FieldValue>20</FieldValue>
</Record>
</Detail>
</SC>
Target XML to be generated:
<SC>
<OrderHeader>
<Order>1234</Order>
</OrderHeader>
<OrderItem>
<Item>1</Item>
<Qty>10</Qty>
</OrderItem>
<OrderItem>
<Item>2</Item>
<Qty>20</Qty>
</OrderItem>
</SC>
XSLT which I tried: I'm not getting the desired output
<xsl:template match="Header">
<xsl:apply-templates select="Record"/>
</xsl:template>
<xsl:template match="Record">
<xsl:if test="FieldName = 'Structure'">
<xsl:element name="{FieldValue}">
<xsl:value-of select="./text()"/>
</xsl:element>
</xsl:if>
<xsl:element name="{FieldName}">
<xsl:value-of select="FieldValue"/>
</xsl:element>
</xsl:template>

Here's another option that is similar to Martin's.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<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="Header|Detail">
<xsl:element name="{Record[1]/FieldValue}">
<xsl:apply-templates select="Record[position()>1]"/>
</xsl:element>
</xsl:template>
<xsl:template match="Record">
<xsl:element name="{FieldName}">
<xsl:value-of select="FieldValue"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

It seems you want to process the first Record child as a container element and the following siblings are to be transformed as in your description:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="SC">
<xsl:copy>
<xsl:apply-templates select="*/Record[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="SC/*/Record[1]">
<xsl:element name="{FieldValue}">
<xsl:apply-templates select="following-sibling::Record"/>
</xsl:element>
</xsl:template>
<xsl:template match="SC/*/Record[position() gt 1]">
<xsl:element name="{FieldName}">
<xsl:value-of select="FieldValue"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Related

Dynamically update text nodes in XSLT

I'm trying to update the text nodes in xml based on the check if it matches a certain pattern
in xslt 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:regexp="http://exslt.org/regular-expressions">
<xsl:output method="xml" version="1.0"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:copy>
<xsl:call-template name="CheckAndReplace">
<xsl:with-param name="text" select="."/>
<xsl:with-param name="pattern" select=""/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="CheckAndReplace">
<xsl:param name="text"/>
<xsl:param name="pattern"/>
<xsl:for-each select="regexp:match( $text, $pattern, 'gi' )">
<xsl:copy-of select="regexp:replace( $text, $pattern, 'gi','*' )"
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
XML:
<Root>
<Name> Kabir </Name>
<Id>  </Id>
</Root>
Here the request has ID tag which matches my pattern and that needs to be replaced
Result Required:
<Root>
<Name> Kabir </Name>
<Id> * </Id>
</Root>
There is no regex in XSLT 1.0. If your goal is to replace all occurrences of the  character with a * then try:
<xsl:template match="text()">
<xsl:value-of select="translate(., '', '*')" />
</xsl:template>

XSLT code for converting attributes to child elements and putting the value of current element into its another new child element

I am unaware of XSLT,Please help:
I have the following XML:
<OLifE>
<Holding id="1234">
<HoldingKey>1397650618090</HoldingKey>
<HoldingTypeCode tc="2">Policy</HoldingTypeCode>
<HoldingStatus tc="2">Inactive</HoldingStatus>
<CarrierAdminSystem>PAS</CarrierAdminSystem>
</Holding>
</OLifE>
I want the output like this:
<OLifE>
<Holding>
<id>1234</id>
<HoldingKey>1397650618090</HoldingKey>
<HoldingTypeCode>
<tc>2</tc>
<value>Policy</value>
</HoldingTypeCode>
<HoldingStatus>
<tc>2</tc>
<value>Inactive</value>
</HoldingStatus>
<CarrierAdminSystem>PAS</CarrierAdminSystem>
</Holding>
</OLifE>
please note that, all attributes are needed to be converted to child elements but, for elements that have a tc attribute specified:
<HoldingTypeCode tc="2">Policy</HoldingTypeCode>
need to be handled carefully.
I DO NOT want the output like:
<HoldingTypeCode>
<tc>2</tc>Policy</HoldingTypeCode>
I have the following XSLT code which needs the slight modification:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:for-each select="#*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates select="*|text()"/>
</xsl:element>
</xsl:template>
Please help.
Assuming you want a generic solution, 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="*"/>
<!-- modified identity transform -->
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- attributes to elements -->
<xsl:template match="#*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<!-- avoid mixed content -->
<xsl:template match="text()[../#*]">
<value>
<xsl:value-of select="."/>
</value>
</xsl:template>
</xsl:stylesheet>
Edit
However, the root element in my original XML has got xmlns="some web
address" attribute.
In such case, change the first template to:
<!-- modified identity transform -->
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
This is assuming you want all the output nodes to be in no namespace.
I think you can define a template like this to be called where you want to output the attributes :
<xsl:template name="transform.attrs">
<xsl:for-each select="#*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:template>
For the most general case you use almost the same template as before, just call the new template for attributes:
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:call-template name="transform.attrs">
<xsl:apply-templates select="*|text()"/>
</xsl:element>
</xsl:template>
And for the specific elements, bearing the #tc attribute:
<xsl:template match="*[#tc]">
<xsl:element name="{name()}">
<xsl:call-template name="transform.attrs" />
<value>
<xsl:apply-templates select="*|text()"/>
</value>
</xsl:element>
</xsl:template>

template not getting applied with XSLT

I am using xslt to convert xml to xml.
<root>
<elem>
<confs>
<conf1>1</conf1>
<conf2>2</conf2>
</confs>
</elem>
</root>
My XSL
<xsl:template match="elem">
<xsl:copy>
<xsl:attribute name="className">confs</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="confs">
<confs>
<xsl:for-each select="*">
<conf>
<value>
<xsl:value-of select="node()"></xsl:value-of>
</value>
</conf>
</confs>
</xsl:template>
desired output:
<root>
<elem className="confs>
<confs>
<conf>
<value>1</value>
</conf>
<conf>
<value>1</value>
</conf>
</confs>
</elem>
</root>
When ran each template individaully they are good. But I run both the confs template is not affected at all.
Any help?
I believe the most straightforward way to achieve your output would be by:
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="elem">
<elem className="confs">
<xsl:apply-templates/>
</elem>
</xsl:template>
<xsl:template match="confs/*">
<conf>
<value>
<xsl:value-of select="."/>
</value>
</conf>
</xsl:template>
</xsl:stylesheet>

Iterate through xml nodes within XSLT

With in an xslt 1.0. I am calling a java function getTierByBundleId which returns below xml. I want to iterate through each Tier using for each. How can i do that
<xsl:variable name="varTierList" select="testclass:getTierByBundleId($bid,$ApplicationId)"/>
Xml returned by function getTierByBundleId
<TierList>
<Tier>
<TierId>1</TierId>
<Name>test</Name>
<Type>2</Type>
<Price>10</Price>
</Tier>
<Tier>
<TierId>2</TierId>
<Name>test</Name>
<Type>3</Type>
<Price>11</Price>
</Tier>
</TierList>
Here when I am trying to do xsl:for each on the variable which has the xml I am getting compilation error. How can I access each Tier from variable $varTierList
<xsl:for-each select="$varTierList/TierList/Tier">
<TierId><xsl:for each"Tierid"/>
</xsl:for-each
Below is the xslt which is generation the above TierList xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foxtelclass="test.GetOrderQuote" exclude-result-prefixes="foxtelclass" extension-element-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:if test="count(/ROWSET/ROW) > 0">
<TierList>
<xsl:for-each select="/ROWSET/ROW">
<Tier>
<TierId><xsl:value-of select="TIER_ID" /></TierId>
<Name><xsl:value-of select="NAME" /></Name>
<Type><xsl:value-of select="TIER_TYPE" /></Type>
<Price><xsl:value-of select="PRICE" /></Price>
</Tier>
</xsl:for-each>
</TierList>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<xsl:for-each select="$varTierList/TierList/Tier"> is throwing the error message
Here is the full xslt
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:testclass="test.GetOrderQuote"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="testclass" extension-
element-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="ApplicationId"/>
<xsl:template match="/">
<ServiceList>
<xsl:variable name="unique-list" select="//ROWSET/ROW/SERVICE_ID
[not(.=following::SERVICE_ID)]"/>
<xsl:for-each select="$unique-list">
<xsl:if test=".!=0">
<Service>
<xsl:variable name="Sid" select="."/>
<ServiceInternalId>
<xsl:value-of select="."/>
</ServiceInternalId>
<BundleList>
<xsl:variable name="unique-
bundle" select="//SERVICE_ID/../BUNDLE_ID[not(.=following::BUNDLE_ID)]"/>
<xsl:for-each
select="$unique-bundle">
<xsl:variable
name="bid" select="."/>
<xsl:if
test="count(/ROWSET/ROW/SERVICE_ID[text()=$Sid]/../BUNDLE_ID[text()=$bid])> 0">
<Bundle>
<Bundle_Id>
<xsl:value-of select="$bid"/>
</Bundle_Id>
<Type>
<xsl:value-of select="../BUNDLE_TYPE"/>
</Type>
<Name>
<xsl:value-of select="../BUNDLE_NAME"/>
</Name>
<Price>
<xsl:value-of select="../BUNDLE_PRICE"/>
</Price>
<xsl:variable name="varTierList" select="testclass:getTierByBundleId
($bid,$ApplicationId)"/>
<test>
<xsl:value-of select="$varTierList"/>
</test>
<xsl:for-each select="$varTierList/TierList/Tier"><!--line causing error-->
<TierId>
<xsl:value-of select="TierId"/>
</TierId>
</xsl:for-each>
</Bundle>
</xsl:if>
</xsl:for-each>
</BundleList>
</Service>
</xsl:if>
</xsl:for-each>
</ServiceList>
</xsl:template>
</xsl:stylesheet>
Below is the text from test node which what is xml variable varTierList contains
<test><TierList>
<Tier>
<TierId>109</TierId>
<Name>Boxes</Name>
<Type>10</Type>
<Price>10</Price>
</Tier>
</TierList>
</test>
Please find below input xml
<ROWSET>
<ROW>
<SET_ID>0</SET_ID>
<SET_DATE>2014-11-09 00:00:00.0</SET_DATE>
<BUNDLE_NAME>Test</BUNDLE_NAME>
<BUNDLE_ID>131</BUNDLE_ID>
<BUNDLE_PRICE>30</BUNDLE_PRICE>
<BUNDLE_TYPE>3</BUNDLE_TYPE>
<BUNDLECOMPONENT_LIST>101100</BUNDLECOMPONENT_LIST>
<PACKAGE>10015</PACKAGE>
<PACKAGE_TYPE>5</PACKAGE_TYPE>
<COMPONENT>101100</COMPONENT>
<PRODUCT_DESC>World Movies</PRODUCT_DESC>
<RATE_AMOUNT>10</RATE_AMOUNT>
<DISCOUNT_AMOUNT>0</DISCOUNT_AMOUNT>
<SERVICE_ID>98683812</SERVICE_ID>
<CHARGE_TYPE>RC</CHARGE_TYPE>
<GUID_TOKEN>053944D794856E3FE0540010E00D30B8</GUID_TOKEN>
<NRC_LINE_ID>0</NRC_LINE_ID>
<TIERID>11</TIERID>
</ROW>
<ROW>
<SET_ID>0</SET_ID>
<SET_DATE>2014-11-09 00:00:00.0</SET_DATE>
<BUNDLE_NAME>Optional test</BUNDLE_NAME>
<BUNDLE_ID>131</BUNDLE_ID>
<BUNDLE_PRICE>30</BUNDLE_PRICE>
<BUNDLE_TYPE>3</BUNDLE_TYPE>
<BUNDLECOMPONENT_LIST>101100</BUNDLECOMPONENT_LIST>
<PACKAGE>10015</PACKAGE>
<PACKAGE_TYPE>5</PACKAGE_TYPE>
<COMPONENT>101103</COMPONENT>
<PRODUCT_DESC>RAI International</PRODUCT_DESC>
<RATE_AMOUNT>20</RATE_AMOUNT>
<DISCOUNT_AMOUNT>0</DISCOUNT_AMOUNT>
<SERVICE_ID>98683812</SERVICE_ID>
<CHARGE_TYPE>RC</CHARGE_TYPE>
<GUID_TOKEN>053944D794856E3FE0540010E00D30B8</GUID_TOKEN>
<NRC_LINE_ID>0</NRC_LINE_ID>
<TIERID>14</TIERID>
</ROW>
</ROWSET>
Hope this helps,
this is full xslt that doesn't shows any compilation error at my end
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:testclass="test.GetOrderQuote" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="testclass">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="ApplicationId"/>
<xsl:template match="/">
<ServiceList>
<xsl:variable name="unique-list" select="//ROWSET/ROW/SERVICE_ID[not(.=following::SERVICE_ID)]"/>
<xsl:for-each select="$unique-list">
<xsl:if test=".!=0">
<Service>
<xsl:variable name="Sid" select="."/>
<ServiceInternalId>
<xsl:value-of select="."/>
</ServiceInternalId>
<BundleList>
<xsl:variable name="unique-bundle" select="//SERVICE_ID/../BUNDLE_ID[not(.=following::BUNDLE_ID)]"/>
<xsl:for-each select="$unique-bundle">
<xsl:variable name="bid" select="."/>
<xsl:if test="count(/ROWSET/ROW/SERVICE_ID[text()=$Sid]/../BUNDLE_ID[text()=$bid])> 0">
<Bundle>
<Bundle_Id>
<xsl:value-of select="$bid"/>
</Bundle_Id>
<Type>
<xsl:value-of select="../BUNDLE_TYPE"/>
</Type>
<Name>
<xsl:value-of select="../BUNDLE_NAME"/>
</Name>
<Price>
<xsl:value-of select="../BUNDLE_PRICE"/>
</Price>
<xsl:variable name="varTierList" select="testclass:getTierByBundleId($bid,$ApplicationId)"/>
<test>
<xsl:value-of select="$varTierList"/>
</test>
<xsl:for-each select="$varTierList/TierList/Tier">
<TierId>
<xsl:value-of select="TierId"/>
</TierId>
</xsl:for-each>
</Bundle>
</xsl:if>
</xsl:for-each>
</BundleList>
</Service>
</xsl:if>
</xsl:for-each>
</ServiceList>
</xsl:template>
</xsl:stylesheet>

Copy a node from parent to child

I would like to copy a parent node into the child but I'm unsure on how to proceed.
I apologize in advanced for the weird looking source file, I'm new to this forum and have no clue on how to properly paste an XML file.
My XML source file is like this:
<?xml version="1.0"?>
<IncidentLogUpload>
<Header>
<BatchID>2013</BatchID>
<SystemID>2013</SystemID>
<DateTime>12/20/2013 3:37 PM</DateTime>
</Header>
<Item>
<IncidentLogs>
<IncidentLog>
<IncidentSource>Source</IncidentSource>
<Property>Property</Property>
<Location>B1</Location>
<SubLocation/>
<DailyLogID>IN2013</DailyLogID>
<IncidentID>IN2013</IncidentID>
<Reference/>
<DateTimeOccured>12/19/2013 8:17 PM</DateTimeOccured>
<IncidentType>Surveillance</IncidentType>
<Specific>Observation</Specific>
<Category>POI</Category>
<IncidentDetails>0400</IncidentDetails>
<RelatedIncidentNo/>
<DateTimeReported>12/19/2013 8:17 PM</DateTimeReported>
<ParticipantSubjectProfiles>
<ParticipantSubjectProfile>
<FirstName>James</FirstName>
<MiddleName></MiddleName>
<LastName>Henderson</LastName>
<ParticipantType>Subject</ParticipantType>
<MembershipNumber></MembershipNumber>
<DriversLicense></DriversLicense>
<PassportNumber></PassportNumber>
<IncidentID>IN2013</IncidentID>
</ParticipantSubjectProfile>
</ParticipantSubjectProfiles>
<ParticipantPersonnelProfiles>
<ParticipantPersonnelProfile>
<BusinessUnit>Games</BusinessUnit>
<FirstName>Edison</FirstName>
<MiddleName>John</MiddleName>
<LastName>Costabile</LastName>
<CSELNumber/>
<StaffID>000408</StaffID>
<DriversLicense/>
<AffBUKey>GamesIN2013</AffBUKey>
<ParticipantType>Personnel</ParticipantType>
</ParticipantPersonnelProfile>
</ParticipantPersonnelProfiles>
</IncidentLog>
</IncidentLogs>
</Item>
<Footer>
<NumberOfRecords>5</NumberOfRecords>
</Footer>
</IncidentLogUpload>
I would like to copy the <Property> node to both <ParticipantSubjectProfile> and <ParticipantPersonnelProfile>. The end result should be like this:
<ParticipantSubjectProfiles>
<ParticipantSubjectProfile>
<FirstName>James</FirstName>
<MiddleName></MiddleName>
<LastName>Henderson</LastName>
<ParticipantType>Subject</ParticipantType>
<MembershipNumber></MembershipNumber>
<DriversLicense></DriversLicense>
<PassportNumber></PassportNumber>
<IncidentID>IN2013</IncidentID>
<Property>Property</Property>
</ParticipantSubjectProfile>
</ParticipantSubjectProfiles>
<ParticipantPersonnelProfiles>
<ParticipantPersonnelProfile>
<BusinessUnit>Games</BusinessUnit>
<FirstName>Edison</FirstName>
<MiddleName>John</MiddleName>
<LastName>Costabile</LastName>
<CSELNumber/>
<StaffID>000408</StaffID>
<DriversLicense/>
<AffBUKey>GamesIN2013</AffBUKey>
<ParticipantType>Personnel</ParticipantType>
<Property>Property</Property>
</ParticipantPersonnelProfile>
</ParticipantPersonnelProfiles>
Please help! Thank you!
Edited
<xsl:template match="/">
<ParticipantSubjectProfiles>
<xsl:for-each select="IncidentLogUpload/Item/IncidentLogs/IncidentLog/ParticipantSubjectProfiles">
<ParticipantSubjectProfile>
<FirstName>James</FirstName>
<MiddleName></MiddleName>
<LastName>Henderson</LastName>
<ParticipantType>Subject</ParticipantType>
<MembershipNumber></MembershipNumber>
<DriversLicense></DriversLicense>
<PassportNumber></PassportNumber>
<IncidentID>IN2013</IncidentID>
<Property> <xsl:value-of select="/IncidentLogUpload/Item/IncidentLogs/IncidentLog/Property"/></Property>
</ParticipantSubjectProfile>
</xsl:for-each>
</ParticipantSubjectProfiles>
</xsl:template>
</xsl:stylesheet>
Try this template out:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.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="/">
<ParticipantSubjectProfiles>
<xsl:for-each select="//ParticipantSubjectProfiles/ParticipantSubjectProfile">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="../preceding-sibling::Property"></xsl:apply-templates>
</xsl:copy>
</xsl:for-each>
</ParticipantSubjectProfiles>
<ParticipantPersonnelProfiles>
<xsl:for-each select="//ParticipantPersonnelProfiles/ParticipantPersonnelProfile">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="../preceding-sibling::Property"></xsl:apply-templates>
</xsl:copy>
</xsl:for-each>
</ParticipantPersonnelProfiles>
</xsl:template>
</xsl:stylesheet>