In context to my earlier question at "XSLT transformation from XML to XML document". Further i was trying
to rename the "<value>" element to "<sName>" along with updating the value to "ABC" if the value of "dataset/type/text() ='test'". I wrote below code
for the same but it was not working as expected. please help.
Source XML-
<soapenv:Header/>
<soapenv:Body>
<v1:QueryRequest version="1">
<subject>
<dataList>
<!--1 or more repetitions:-->
<dataset>
<type>company</type>
<value>abc</value>
</dataset>
<dataset>
<type>user</type>
<value>xyz</value>
</dataset>
</dataList>
</subject>
<testList>
<!--1 or more repetitions:-->
<criteria>
<type>test</type>
<value>1234</value>
</criteria>
<criteria>
<type>test2</type>
<value>false</value>
</criteria>
</testList>
</v1:QueryRequest>
</soapenv:Body>
</soapenv:Envelope>
XSL file :-
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://www.abc.com/s/v1.0"
exclude-result-prefixes="old"
xmlns:v2="http://www.abc.com/s/v2.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"
version="1.0" />
<xsl:param name="newversion" select="'2.0'" />
<xsl:param name="ABC" select="'ABC'" />
<xsl:param name="XYZ" select="'XYZ'" />
<xsl:param name="DFG" select="'DFG'" />
<!-- fix namespace declarations on root element -->
<xsl:template match="/*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<!-- copy the v2: binding from the stylesheet document -->
<xsl:copy-of select="document('')/xsl:stylesheet/namespace::v2" />
<xsl:apply-templates select="#* | node()" />
</xsl:element>
</xsl:template>
<!-- replace namespace of elements in old namespace -->
<xsl:template match="old:*">
<xsl:element name="v2:{local-name()}">
<xsl:apply-templates select="#* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="old:QueryRequest/#version">
<xsl:attribute name="version">
<xsl:value-of select="$newversion" />
</xsl:attribute>
</xsl:template>
<xsl:template match="criteria[type='service']/value">
<xsl:choose>
<xsl:when test="criteria[type='service']/value/text()='1234'">
<xsl:element name="sName">
<xsl:value-of select="$ABC"/>
</xsl:element>
</xsl:when>
<xsl:when test="criteria[type='service']/value/text()='5464'">
<xsl:element name="sName">
<xsl:value-of select="$XYZ"/>
</xsl:element>
</xsl:when>
<xsl:when test="criteria[type='service']/value/text()='8755'">
<xsl:element name="sName">
<xsl:value-of select="$DFG"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="type/text()">
<xsl:value-of
select="translate(., 'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
</xsl:template>
</xsl:stylesheet>
Expected Output:
<testList>
<criteria>
<type>test</type>
<sName>ABC</sName>
</criteria>
<criteria>
<type>test2</type>
<value>false</value>
</criteria>
</testList>
Within a
<xsl:template match="criteria[type='service']/value">
the value element is the current context node, so your other XPath expressions need to be relative to that, i.e. instead of
<xsl:when test="criteria[type='service']/value/text()='1234'">
you would just use
<xsl:when test="text()='1234'">
or better
<xsl:when test=".='1234'">
Related
I am very new in xsl. I was trying to add the <quote> tag in between the <para>.tag. but the output printing twice.
Here is my xsl code
<?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="2.0">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*" mode="pretrans">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[count(child::node())=0]" mode="pretrans"/>
<xsl:template match="doc">
<poc>
<xsl:apply-templates/>
</poc>
</xsl:template>
<xsl:template match="text">
<chapter>
<xsl:variable name="pos" select="count(child::node()[#style='H5']/preceding-sibling::p)+1"/>
<xsl:apply-templates select="child::node()[position()<$pos]" mode="presec"/>
<section>
<xsl:variable name="nodesets" >
<xsl:apply-templates select="child::node()[position()>=$pos]" mode="pretrans"/>
</xsl:variable>
<xsl:apply-templates select="$nodesets" mode="postsec"/> <!---->
</section>
</chapter>
</xsl:template>
<xsl:template match="p" mode="presec">
<xsl:choose>
<xsl:when test="#style='H2'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="#style='H4'">
<subdivision>
<title><xsl:apply-templates/></title>
</subdivision>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="p" mode="postsec">
<xsl:variable name="pos" select="count(preceding-sibling::p[#style='H5'][1]/preceding-sibling::p)+1"/>
<xsl:variable name="pos" select="count(preceding-sibling::p)+1"/>
<xsl:variable name="styleblock" select="count(preceding-sibling::p[#style='BlockStyle'][1]/preceding-sibling::p)+1"/>
<xsl:choose>
<xsl:when test="#style='H5'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="count(child::node())=0"/>
<xsl:otherwise>
<paragraph>
<xsl:if test="#style='BlockStyle'">
<quotes>
<xsl:apply-templates/>
</quotes>
</xsl:if>
<xsl:apply-templates/>
</paragraph>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
expected output:
<poc>
<chapter>
<section>
<paragraph>
<quote>
Hi welcome to new year 2022
</quote>
Hi welcome to new year 2022
</paragraph>
</section>
</chapter>
</poc>
The message is printing twice.
can anyone help me in this.
Depending on your needs delete the first or the second
<paragraph>
<xsl:if test="#style='BlockStyle'">
<quotes>
<xsl:apply-templates/><!-- First -->
</quotes>
</xsl:if>
<xsl:apply-templates/><!-- Second -->
</paragraph>
this is sample xml:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd
http://www.liquibase.org/xml/ns/dbchangelog">
<changeSet id="1" author="a">
<createTable tableName="TABLE1">
<column>
</column>
</createTable>
</changeSet>
<changeSet id="1-1" author="a">
<createSequence sequenceName="SEQ_TABLE1" />
</changeSet>
<changeSet id="4" author="A">
<createTable tableName="TABLE4">
<column>
</column>
</createTable>
</changeSet>
</databaseChangeLog>
this is template:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.liquibase.org/xml/ns/dbchangelog">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:variable name="coreTables" select="('TABLE1','TABLE2')"/>
<xsl:template match="node()[not(self::*)]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="databaseChangeLog">
<!-- CORE-->
<xsl:comment>CORE TABLES</xsl:comment>
<xsl:variable name="coreTablesVariable" select="changeSet[createTable/#tableName=$coreTables]"/>
<xsl:comment>CORE SEQUENCES</xsl:comment>
<xsl:variable name="coreSequencesVariable" select="changeSet[createSequence[starts-with(#sequenceName, 'SEQ_') and substring-after(#sequenceName, 'SEQ_') = $coreTables]]"/>
<xsl:comment>CORE INDEXES</xsl:comment>
<xsl:variable name="coreIndexesVariable" select="changeSet[createIndex/#tableName=$coreTables]"/>
<xsl:comment>CORE FOREIGN CONSTRAINTS</xsl:comment>
<xsl:variable name="coreForeignConstraintsVariable" select="changeSet[addForeignKeyConstraint/#baseTableName=$coreTables]"/>
<xsl:comment>CORE VIEWS</xsl:comment>
<xsl:variable name="coreViewsVariable" select="changeSet[createView/#viewName=$coreTables]"/>
<xsl:call-template name="createChangeLog">
<xsl:with-param name="outputFile" select="'core-changelog.xml'"/>
<xsl:with-param name="changeLogContent" select="$coreTablesVariable,$coreSequencesVariable,$coreIndexesVariable,$coreForeignConstraintsVariable,$coreViewsVariable"/>
</xsl:call-template>
<xsl:comment>UNMATCHED</xsl:comment>
<xsl:variable name="unmatchedChangeSets"
select="changeSet[not(some $set in ($coreTablesVariable | $coreSequencesVariable | $coreIndexesVariable |$coreForeignConstraintsVariable |$coreViewsVariable) satisfies $set is .)]"/>
<xsl:call-template name="createChangeLog">
<xsl:with-param name="outputFile" select="'unmatched-changes-changelog.xml'"/>
<xsl:with-param name="changeLogContent" select="$unmatchedChangeSets"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="createChangeLog">
<xsl:param name="outputFile"/>
<xsl:param name="changeLogContent"/>
<xsl:result-document encoding="UTF-8" indent="true" method="xml" href="{$outputFile}">
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.6.xsd http://www.liquibase.org/xml/ns/dbchangelog" logicalFilePath="TODO">
<xsl:copy-of select="$changeLogContent"/>
</databaseChangeLog>
</xsl:result-document>
</xsl:template>
</xsl:transform>
I'd like to add to output xml processed inside createChangelogTemplate to each element <changeSet> another attribute (context="legacy"). I was trying to add another template which matches databaseChangelog/changeSet with additional xsl:attribute element but that didn't worked for me. If is there way how to do this in one place that would be nice, because I will need to prepare more sections like CORE.
When I've added template:
<xsl:template match="changeSet" mode="legacy">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:attribute name="context">legacy</xsl:attribute>
<xsl:copy-of select="node()"/>
</xsl:copy>
</xsl:template>
and replaced <xsl:copy-of select="$changeLogContent"/> with <xsl:apply-templates select="$changeLogContent" mode="legacy"/> then output file core-changelog.xml was ok but file unmatched-changes-changelog.xml had no elements.
I'm using xslt 2.0 and saxon 9.8he.
When I run this I get changeSets 1 and 1-1 in core-changelog.xml, and changeSet 4 in unmatched-changelog.xml.
If you're still seeing nothing in unmatched-changelog then we need to look in more detail at exactly how you were running it.
Incidentally the selection of unmatched elements could be done as
select="changeSet except ($coreTablesVariable | $coreSequencesVariable | $coreIndexesVariable |$coreForeignConstraintsVariable |$coreViewsVariable)"/>
Hi I have been trying to replace values in a certain tag with sequential numbers, I used position function, but it did not work.
Input xml:
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Header>
<User id="swarnai" />
<Request-Id id="592149819" />
<Type name="Request" />
<Application-Source version="8.1.1.10" name="Siebel" />
<Application-Destination version="1.2.2" name="EVA" />
<Outgo-Timestamp time="11:40:59" date="2015-08-04" />
<DealerCode>82536</DealerCode>
<Market>00000</Market>
</Header>
<Content>
<ClaimContext>
<ClaimControl>
<ClaimEntryFlag>3</ClaimEntryFlag>
<ClaimSaveFlag>1</ClaimSaveFlag>
</ClaimControl>
<Claim>
<DealerClaimNumber>1091871</DealerClaimNumber>
<WHC>WDD</WHC>
<FIN>2120026L020301</FIN>
<RegistrationNumber>JH07E2786</RegistrationNumber>
<FirstRegistrationDate>2012-11-29</FirstRegistrationDate>
<Mileage>14317</Mileage>
<MileageIndicator>0</MileageIndicator>
<RepairDate>2013-12-03</RepairDate>
<RegularlyMaintained>true</RegularlyMaintained>
<NoFirstRegDateInd>false</NoFirstRegDateInd>
<ClaimCurrencyId>EUR</ClaimCurrencyId>
<Taxi>false</Taxi>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<OperationPosition>
<SeqNumber>1</SeqNumber>
<Opcode>02770501</Opcode>
<WorkingUnits>18</WorkingUnits>
<MainOperationCode>true</MainOperationCode>
<OperationText>OPERATIONS: FITTING FOR COOLANT CONNECTION TO CYLINDER</OperationText>
<PriceGroup>01</PriceGroup>
</OperationPosition>
</DamagePosition>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>10</Quantity>
<PartNumber>A6512001056</PartNumber>
<DamageCausingPart>true</DamageCausingPart>
<RetailPriceAmount>1499</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<WarrantyType>0</WarrantyType>
<DamageCode>0121504</DamageCode>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>20</Quantity>
<PartNumber>A0009890825 10</PartNumber>
<DamageCausingPart>false</DamageCausingPart>
<RetailPriceAmount>1319</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
</Claim>
</ClaimContext>
</Content>
</Envelope>
In this xml within PartPosition/SeqNumber tag I want to replace or generate sequence of numbers in SeqNumber tag.
I tried below xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="no"/>
<xsl:key name="Damage_Group" match="/Envelope/Content/ClaimContext/Claim/DamagePosition" use="DamageCode" />
<xsl:template match="Claim">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
<xsl:for-each select="DamagePosition[count(. | key('Damage_Group', DamageCode)[1]) = 1]">
<xsl:sort select="DamageCode" />
<DamagePosition>
<DamageSeqNumber>
<xsl:value-of select="position()" />
</DamageSeqNumber>
<DamageCode>
<xsl:value-of select="DamageCode" />
</DamageCode>
<WarrantyType><xsl:value-of select="WarrantyType" /></WarrantyType>
<xsl:for-each select="key('Damage_Group', DamageCode)">
<xsl:copy-of select="current()/PartPosition"/>
<xsl:copy-of select="current()/OperationPosition"/>
<xsl:copy-of select="current()/SubletPosition"/>
</xsl:for-each>
</DamagePosition>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition">
</xsl:template>
</xsl:stylesheet>
but it is not giving me the desired output as below.
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Header>
<User id="swarnai" />
<Request-Id id="592149819" />
<Type name="Request" />
<Application-Source version="8.1.1.10" name="Siebel" />
<Application-Destination version="1.2.2" name="EVA" />
<Outgo-Timestamp time="12:15:47" date="2015-08-04" />
<DealerCode>82536</DealerCode>
<Market>00000</Market>
</Header>
<Content>
<ClaimContext>
<ClaimControl>
<ClaimEntryFlag>3</ClaimEntryFlag>
<ClaimSaveFlag>1</ClaimSaveFlag>
</ClaimControl>
<Claim>
<DealerClaimNumber>1091871</DealerClaimNumber>
<WHC>WDD</WHC>
<FIN>2120026L020301</FIN>
<RegistrationNumber>JH07E2786</RegistrationNumber>
<FirstRegistrationDate>2012-11-29</FirstRegistrationDate>
<Mileage>14317</Mileage>
<MileageIndicator>0</MileageIndicator>
<RepairDate>2013-12-03</RepairDate>
<RegularlyMaintained>true</RegularlyMaintained>
<NoFirstRegDateInd>false</NoFirstRegDateInd>
<ClaimCurrencyId>EUR</ClaimCurrencyId>
<Taxi>false</Taxi>
<DamagePosition>
<DamageSeqNumber>1</DamageSeqNumber>
<DamageCode>0121504</DamageCode>
<WarrantyType>0</WarrantyType>
<OperationPosition>
<SeqNumber>1</SeqNumber>
<Opcode>02770501</Opcode>
<WorkingUnits>18</WorkingUnits>
<MainOperationCode>true</MainOperationCode>
<OperationText>OPERATIONS: FITTING FOR COOLANT CONNECTION TO CYLINDER</OperationText>
<PriceGroup>01</PriceGroup>
</OperationPosition>
<PartPosition>
<SeqNumber>1</SeqNumber>
<Quantity>10</Quantity>
<PartNumber>A6512001056</PartNumber>
<DamageCausingPart>true</DamageCausingPart>
<RetailPriceAmount>1499</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
<PartPosition>
<SeqNumber>2</SeqNumber>
<Quantity>20</Quantity>
<PartNumber>A0009890825 10</PartNumber>
<DamageCausingPart>false</DamageCausingPart>
<RetailPriceAmount>1319</RetailPriceAmount>
<Express>false</Express>
</PartPosition>
</DamagePosition>
</Claim>
</ClaimContext>
</Content>
</Envelope>
Any help is much appreciated.
Thanks
Firstly, instead of doing this, which copies the elements without further changes to it (or its descendants)
<xsl:copy-of select="current()/PartPosition"/>
<xsl:copy-of select="current()/OperationPosition"/>
<xsl:copy-of select="current()/SubletPosition"/>
You should you template matching instead, to allow you to write a template later on to change the sequence number
<xsl:apply-templates select="PartPosition"/>
<xsl:apply-templates select="OperationPosition"/>
<xsl:apply-templates select="SubletPosition"/>
Now, what you could do, is write a template that matches the various Sequence numbers and counts the preceding siblings for the same DamageCode. Something like this
<xsl:template match="PartPosition/SeqNumber">
<SeqNumber>
<xsl:variable name="DamageCode" select="../../DamageCode" />
<xsl:value-of select="count(../../preceding-sibling::*[PartPosition][DamageCode = $DamageCode]) + 1" />
</SeqNumber>
</xsl:template>
You could repeat the template for OperationPosition and SubletPosition too, although this would be quite repetitive. Alternatively, have a single generic template to match all three:
<xsl:template match="SeqNumber">
<SeqNumber>
<xsl:variable name="DamageCode" select="../../DamageCode" />
<xsl:variable name="Parent" select="name(..)" />
<xsl:value-of select="count(../../preceding-sibling::*[*[name() = $Parent]][DamageCode = $DamageCode]) + 1" />
</SeqNumber>
</xsl:template>
However, this is not necessarily that efficient, as it is not utilizing the key and so would have to check back through all preceding siblings to find a match.
Another solution would be to pass the position of the current DamagePosition in a parameter, and then use that in checking the key.
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:key name="Damage_Group"
match="/Envelope/Content/ClaimContext/Claim/DamagePosition"
use="DamageCode"/>
<xsl:template match="Claim">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:for-each select="DamagePosition[count(. | key('Damage_Group', DamageCode)[1]) = 1]">
<xsl:sort select="DamageCode"/>
<DamagePosition>
<DamageSeqNumber>
<xsl:value-of select="position()"/>
</DamageSeqNumber>
<DamageCode>
<xsl:value-of select="DamageCode"/>
</DamageCode>
<WarrantyType>
<xsl:value-of select="WarrantyType"/>
</WarrantyType>
<xsl:for-each select="key('Damage_Group', DamageCode)">
<xsl:apply-templates select="PartPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
<xsl:apply-templates select="OperationPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
<xsl:apply-templates select="SubletPosition">
<xsl:with-param name="Position" select="position()" />
</xsl:apply-templates>
</xsl:for-each>
</DamagePosition>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition/*">
<xsl:param name="Position" />
<xsl:copy>
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="Position" select="$Position" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="SeqNumber">
<xsl:param name="Position" />
<SeqNumber>
<xsl:value-of select="count(key('Damage_Group', ../../DamageCode)[position() <= $Position][*[name() = name(current()/..)]])" />
</SeqNumber>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="DamagePosition" />
</xsl:stylesheet>
I am getting stuck at a point where I need to remove an element from the input XML:
<message
xmlns="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<m_control>
<control_timestamp>2013-06-06T14:55:37</control_timestamp>
<initiator_id>ASL</initiator_id>
</m_control>
<m_content>
<b_control>
<quote_type>Single Company</quote_type>
<quote_or_print>Quote And Print</quote_or_print>
<generic_quote_ind>Yes</generic_quote_ind>
<tpsdata>
<tps_quote_type>Comparison</tps_quote_type>
</tpsdata>
</b_control>
<application>
<product>
<tpsdata>
<service_type>QuickQuote</service_type>
<quote_type>Standard</quote_type>
</tpsdata>
</product>
</application>
</m_content>
</message>
if <tps_quote_type> is 'Comparison' then change the value of <quote_type> to 'Comparison' and the <tpsdata> field should be removed. The output should look like below.
<message
xmlns="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<m_control>
<control_timestamp>2013-06-06T14:55:37</control_timestamp>
<initiator_id>ASL</initiator_id>
</m_control>
<m_content>
<b_control>
<quote_type>Comparison</quote_type>
<quote_or_print>Quote And Print</quote_or_print>
<generic_quote_ind>Yes</generic_quote_ind>
</b_control>
<application>
<product>
<tpsdata>
<service_type>QuickQuote</service_type>
<quote_type>Standard</quote_type>
</tpsdata>
</product>
</application>
</m_content>
</message>
So far I have tried this XSLT, but I don't know how to remove <tpsdata> field from the output. Could anyone help me in this?
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="dp"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<!-- identity with closing tags -->
<xsl:element name="{name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:variable name="quoteType">
<xsl:value-of select="/*[namespace-uri()='http://www.origoservices.com' and local- name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name() ='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='quote_type']"/>
</xsl:variable>
<xsl:variable name="tpsQuoteType">
<xsl:value-of select="/*[namespace-uri()='http://www.origoservices.com' and local-name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name()='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='tpsdata']/*[namespace-uri()='http://www.origoservices.com' and local-name()='tps_quote_type']"/>
</xsl:variable>
<xsl:template match="/*[namespace-uri()='http://www.origoservices.com' and local-name()='message']/*[namespace-uri()='http://www.origoservices.com' and local-name()='m_content']/*[namespace-uri()='http://www.origoservices.com' and local-name()='b_control']/*[namespace-uri()='http://www.origoservices.com' and local-name()='quote_type']">
<xsl:choose>
<xsl:when test="$tpsQuoteType = 'Comparison' ">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:text>Comparison</xsl:text>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*|comment()|processing-instruction()">
<xsl:copy>
<xsl:copy-of select="#*|namespace::*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Maybe you noticed that your handling of those elements with a namespace is a little painful. Just add the http://www.origoservices.com namespace to your XSLT and the pain goes away.
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:o="http://www.origoservices.com"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="dp"
exclude-result-prefixes="fn date"
>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="o:b_control/o:quote_type[../o:tpsdata/o:tps_quote_type = 'Comparison']">
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:text>Comparison</xsl:text>
</xsl:copy>
</xsl:template>
<xsl:template match="o:tpsdata[o:tps_quote_type = 'Comparison']" />
</xsl:stylesheet>
Notes
Most of your "plumbing" is not necessary.
Template match expressions don't need to be a full path.
Use match expressions rather than <xsl:choose> to pinpoint elements you want to change.
Start with a basic identity template, overriding it as needed with more specific templates. This makes your live much easier than starting with a modified identity template.
Use empty templates to remove specific elements.
<xsl:stylesheet version="1.0" extension-element-prefixes="dp" exclude-result-prefixes="dp regexp fn dpconfig" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" xmlns:dpconfig="http://www.datapower.com/param/config" xmlns:dpfunc="http://www.datapower.com/extensions/functions" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:regexp="http://exslt.org/regular-expressions" >
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name()='tpsdata']/*[local-name()='quote_type']">
<xsl:message dp:priority="debug"> Found quote_type </xsl:message>
<xsl:variable name = "First">
<xsl:value-of select="/*[local-name()='message']/*[local-name()='m_content']/*[local-name()='b_control']/*[local-name()='tpsdata']/*[local-name()='tps_quote_type']/text()"/>
</xsl:variable>
<xsl:variable name = "Second">
<xsl:value-of select = "."/>
</xsl:variable>
<xsl:message dp:priority="debug"> Second:<xsl:value-of select = "$Second"/></xsl:message>
<xsl:message dp:priority="debug"> First: <xsl:value-of select = "$First"/> </xsl:message>
<xsl:choose>
<xsl:when test="$Second = $First">
<xsl:message dp:priority="debug"> Stand and Comp are same </xsl:message>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:message dp:priority="debug"> Stand and Comp are different </xsl:message>
<xsl:copy>
<xsl:value-of select="regexp:replace(*[local-name()='quote_type'],'','',$First)"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*[local-name()='b_control']/*[local-name()='tpsdata']"/>
</xsl:stylesheet>
How can i replace an attribute in xml using xsl transformation, depending on its value.
For example, if there is such xml
<Text Style='style1'>
...
</Text>
transform it to
<Text Font='Arial' Bold='true' Color='Red'>
...
</Text>
For Style='style2' set another attributes and values, for example Font='Sans' Italic='true'.
One posible way: ussing attribute sets. This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:attribute-set name="style1">
<xsl:attribute name="Font">Arial</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
<xsl:attribute name="Color">Red</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="style2">
<xsl:attribute name="Font">Sans</xsl:attribute>
<xsl:attribute name="Italic">true</xsl:attribute>
</xsl:attribute-set>
<xsl:template match="Text[#Style='style1']">
<xsl:copy use-attribute-sets="style1">
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="Text[#Style='style2']">
<xsl:copy use-attribute-sets="style2">
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
With this input:
<root>
<Text Style='style1'></Text>
<Text Style='style2'></Text>
</root>
Output:
<Text Font="Arial" Bold="true" Color="Red"></Text>
<Text Font="Sans" Italic="true"></Text>
Other way: inline "attribute sets". This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my"
exclude-result-prefixes="my">
<xsl:output indent="yes"/>
<my:style1 Font="Arial" Bold="true" Color="Red"/>
<my:style2 Font="Sans" Italic="true"/>
<xsl:template match="Text[#Style]">
<xsl:copy>
<xsl:copy-of select="document('')/*/my:*
[local-name()=current()/#Style]/#*"/>
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You will need to have some kind of rule that you use to convert the style from one to the other. Making the assumption you are inputting html you will need something like.
<xsl:template match="#* | node()">
<xsl:choose>
<xsl:when test="local-name() = 'Style'">
<xsl:apply-templates select="." mode="Style" />
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#Style" mode="Style">
<xsl:choose>
<xsl:when test="node() = 'style1'">
<xsl:attribute name="Font">Arial</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
<xsl:attribute name="Color">Red</xsl:attribute>
</xsl:when>
<xsl:when test="node() = 'style2'">
<xsl:attribute name="Font">Sans</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:template>