I have given below the XSL codes i have tried and the part of input and output codes.If I use XSL1 to rename the namespace prefix values in the xml tags , unfortunately it collapses the attribute values and if I use XSL2 attributes are getting created a separate nodes. Can someone pls help to write an XSL to rename the prefixes but to keep the attributes in the same node.
XSL 1:
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:*">
<xsl:element name="ubl:{local-name()}" namespace="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
XSL2:
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy></xsl:template>
<xsl:template match="#*">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="ns0:*">
<xsl:element name="ubl:{local-name()}" namespace="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
Input:
<ns5:LegalMonetaryTotal>
<ns2:LineExtensionAmount currencyID="EUR">35.38</ns2:LineExtensionAmount>
<ns2:TaxExclusiveAmount currencyID="EUR">35.38</ns2:TaxExclusiveAmount>
<ns2:TaxInclusiveAmount currencyID="EUR">37.5</ns2:TaxInclusiveAmount>
<ns2:PrepaidAmount currencyID="EUR">37.5</ns2:PrepaidAmount>
<ns2:PayableAmount currencyID="EUR">0.00</ns2:PayableAmount>
</ns5:LegalMonetaryTotal>
Output1:
<cac:LegalMonetaryTotal >
<cbc:LineExtensionAmount >EUR35.38</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount >EUR35.38</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount >EUR37.5</cbc:TaxInclusiveAmount>
<cbc:PrepaidAmount >EUR37.5</cbc:PrepaidAmount>
<cbc:PayableAmount >EUR0.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
Output2:
<cac:LegalMonetaryTotal >
<cbc:LineExtensionAmount >
<currencyID>EUR</currencyID>
35.38
</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount >
<currencyID>EUR</currencyID>
35.38
</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount >
<currencyID>EUR</currencyID>
37.5
</cbc:TaxInclusiveAmount>
<cbc:PrepaidAmount >
<currencyID>EUR</currencyID>
37.5
</cbc:PrepaidAmount>
<cbc:PayableAmount>
<currencyID>EUR</currencyID>
0.00
</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
But Expected output is: I have tried multiple options guys. Please help me to get the below format.
<cbc:LegalMonetaryTotal>
<cac:LineExtensionAmount currencyID="EUR">35.38</cac:LineExtensionAmount>
<cac:TaxExclusiveAmount currencyID="EUR">35.38</cac:TaxExclusiveAmount>
<cac:TaxInclusiveAmount currencyID="EUR">37.5</cac:TaxInclusiveAmount>
<cac:PrepaidAmount currencyID="EUR">37.5</cac:PrepaidAmount>
<cac:PayableAmount currencyID="EUR">0.00</cac:PayableAmount>
</cbc:LegalMonetaryTotal>
Regards,
Indu
The reason why your first stylesheet does not output any attributes is that you have no template that handles attributes. Therefore, the instruction:
<xsl:apply-templates select="#* | node()"/>
does not do anything for attributes.
Try changing your first template:
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
to the standard identity transform template:
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
That will probably make it work. I say probably, because your stylesheet does not fit your input nor the expected output. Your stylesheet looks for:
<xsl:template match="ns0:*">
but your input has no elements with a ns0 prefix. And your stylesheet outputs a ubl prefix, while your expected output uses cbc and cac prefixes. And - as already mentioned in the comments to your question - all these prefixes need to be bound to namespaces in order for the input and the input to be well-formed XML documents.
Related
I need to change order of elements. But also rename elements into elements.
So,
I have xml:
<transactionality>
<rollbackexttransactionid>
<rollbackvalidity>3600</rollbackvalidity>
<rollbackscheduledattemps>3</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackexttransactionid>
<transactionalitylogspath>TransactionalityLogs</transactionalitylogspath>
<rollbacklifecycleevents>
<rollbacklifecycle>1200</rollbacklifecycle>
<rollbackscheduledattemps>2</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbacklifecycleevents>
<rollbackpayment>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattemps>2</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackpayment>
</transactionality>
I need to do element transactionalitylogspath as first in to transactionality.
Rename all elements "rollbackscheduledattemps" to "rollbackscheduledattempts"
Rename rollbacklifecycleevents/rollbacklifecycle to rollbacklifecycleevents/rollbackvalidity
I would'like to have:
<transactionality>
<transactionalitylogspath>TransactionalityLogs</transactionalitylogspath>
<rollbackexttransactionid>
<rollbackvalidity>3600</rollbackvalidity>
<rollbackscheduledattempts>3</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackexttransactionid>
<rollbacklifecycleevents>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattempts>2</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbacklifecycleevents>
<rollbackpayment>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattempts>2</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackpayment>
</transactionality>
I did:
<xsl:template match="transactionality">
<xsl:variable name="elements-after" select="rollbackexttransactionid|rollbacklifecycleevents|rollbackpayment"/>
<xsl:copy>
<xsl:copy-of select="transactionalitylogspath"/>
<xsl:copy-of select="$elements-after">
</xsl:copy-of >
</xsl:copy>
</xsl:template>
<xsl:template match="rollbackscheduledattemps">
<rollbackscheduledattempts>
<xsl:apply-templates select="#* | node()"/>
</rollbackscheduledattempts>
</xsl:template>
byt it doesn't work :(.
Help me please.
Here's how I would do it :
<?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="transactionality">
<xsl:copy>
<xsl:apply-templates select="transactionalitylogspath"/>
<xsl:apply-templates select="*[local-name() != 'transactionalitylogspath']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="rollbackscheduledattemps">
<rollbackscheduledattempts>
<xsl:value-of select="."/>
</rollbackscheduledattempts>
</xsl:template>
<xsl:template match="rollbacklifecycleevents/rollbacklifecycle">
<rollbackvalidity>
<xsl:value-of select="."/>
</rollbackvalidity>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Here's a working example : https://xsltfiddle.liberty-development.net/6pS26mL
I've tried to combine solutions to the similar questions asked here but all of them work in very specific cases. My case is the following: I have an arbitrary xml document which contains some tags, let's say <separator/>. What I want is to split parent elements of these tags like that:
INPUT:
<some_tag some_attr="some_value">
some text
<some_other_tag>some another text</some_other_tag>
<separator/>
some other content
</some_tag>
OUTPUT:
<some_tag some_attr="some_value">
some text
<some_other_tag>some another text</some_other_tag>
</some_tag>
<separator/>
<some_tag some_attr="some_value">
some other content
</some_tag>
Also, I am limited to XSLT 1.0 since Xalan is used in the project
Either use sibling recursion or use a key to find the nodes "belonging" to a separator. Additional care is needed to copy stuff following the last separator:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="sep" match="*[separator]/node()[not(self::separator)]" use="generate-id(following-sibling::separator[1])"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[separator]">
<xsl:apply-templates select="separator" mode="split"/>
<xsl:if test="separator[last()]/following-sibling::node()">
<xsl:copy>
<xsl:apply-templates select="#* | separator[last()]/following-sibling::node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="separator" mode="split">
<xsl:apply-templates select=".." mode="split">
<xsl:with-param name="separator" select="."/>
</xsl:apply-templates>
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="*" mode="split">
<xsl:param name="separator"/>
<xsl:copy>
<xsl:apply-templates select="#* | key('sep', generate-id($separator))"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/pPqsHTc
Note that if you use Xalan Java then in the Java world this is much easier with Saxon 9 and XSLT 2/3's <xsl:for-each-group select="node()" group-adjacent="boolean(self::separator)"> or group-starting-with="separator".
i have something like this:
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar</groupme>
<groupme>baz</groupme>
<groupme>42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar</groupme>
<groupme>foo</groupme>
<z>thats it</z>
</root>
now i need all groume's which are direct neighbours to be a single node like:
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar baz 42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar foo</groupme>
<z>thats it</z>
</root>
also the groupme nodes containing other nodes, i've just leave them to provide a simple example.
the groupme nodes only apear in a specific level, no groupme nodes in others then root.
any help for me?
Such grouping can be achieved with an approach called "sibling recursion", for your problem I would suggest a stylesheet as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[not(preceding-sibling::*[1][self::groupme])]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="following-sibling::*[1][self::groupme][1]" mode="list"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]"/>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]" mode="list">
<xsl:text> </xsl:text>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="following-sibling::*[1][self::groupme][1]" mode="list"/>
</xsl:template>
</xsl:stylesheet>
When applied to the input
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar</groupme>
<groupme>baz</groupme>
<groupme>42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar</groupme>
<groupme>foo</groupme>
<z>thats it</z>
</root>
the result is
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar baz 42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar foo</groupme>
<z>thats it</z>
</root>
As an alternative to the sibling recursion it is also possible to "grab" the following siblings with a key based approach:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:key
name="first"
match="root/groupme[preceding-sibling::*[1][self::groupme]]"
use="generate-id(preceding-sibling::groupme[not(preceding-sibling::*[1][self::groupme])][1])"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[not(preceding-sibling::*[1][self::groupme])]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="key('first', generate-id())" mode="list"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]"/>
<xsl:template match="root/groupme" mode="list">
<xsl:text> </xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
I was looking for some guidance on how best to approach my issue.
I have an XML document like the following but on a larger scale.
<NewDataSet>
<Table Attri1="Attri1Val" Attri2="Attri2Val" Attri3="Attri3Val" Attri4="Attri4Val" Attri5="Attri5Val" Attri6="Attri6Val" Attri7="Attri7" />
</NewDataSet>
I need to move certain attributes from the Table node, for example Attri2 and Attri5 into elements within the Table node, however I need to leave the rest of the attributes as they are.
What would be the best way to approach this? The data scale is about 3-4 times that shown.
EDIT:
Expected output:
<NewDataSet>
<Table Attri1="Attri1Val" Attri3="Attri3Val" Attri4="Attri4Val" Attri6="Attri6Val" Attri7="Attri7">
<Attri2>Attri2Val</Attri2>
<Attri5>Attri5Val</Attri5>
</Table>
</NewDataSet>
The complexity is not really the issue, more the scale of the data and what is the best way to deal with it.
Use
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Table">
<xsl:copy>
<xsl:apply-templates select="#*[not(name() = 'Attri2') and not(name() = 'Attri5')]"/>
<xsl:apply-templates select="#Attri2 | #Attri5 | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Table/#Attri2 | Table/#Attri5">
<xsl:element name="{name()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
[edit]
The name comparison of the attributes is a bit ugly but will probably do for your sample. What we really need is #* execpt (#Attri2, #Attri5), only that is XPath 2.0. With XPath 1.0 the equivalent is
<xsl:template match="Table">
<xsl:copy>
<xsl:variable name="all-attributes" select="#*"/>
<xsl:variable name="to-be-transformed" select="#Attri2 | #Attri5"/>
<xsl:apply-templates select="$all-attributes[count(. | $to-be-transformed) != count($to-be-transformed)]"/>
<xsl:apply-templates select="$to-be-transformed | node()"/>
</xsl:copy>
</xsl:template>
This generic transformation can handle any set of attributes, with any length, whose names can be specified externally to the transformation:
<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:param name="pToTransform" select="'|Attri2|Attri5|'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Table">
<xsl:copy>
<xsl:apply-templates select=
"#*[not(contains($pToTransform, concat('|',name(),'|')))] | node()"/>
<xsl:apply-templates mode="makeElement"
select="#*[contains($pToTransform, concat('|',name(),'|'))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*" mode="makeElement">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document:
<NewDataSet>
<Table Attri1="Attri1Val" Attri2="Attri2Val"
Attri3="Attri3Val" Attri4="Attri4Val"
Attri5="Attri5Val" Attri6="Attri6Val"
Attri7="Attri7" />
</NewDataSet>
the wanted, correct result is produced:
<NewDataSet>
<Table Attri1="Attri1Val" Attri3="Attri3Val" Attri4="Attri4Val" Attri6="Attri6Val" Attri7="Attri7">
<Attri2>Attri2Val</Attri2>
<Attri5>Attri5Val</Attri5>
</Table>
</NewDataSet>
How i check select="document('02.xml')/*/Person"/ and select="document('04.xml')/*/Person"/ is available in xsl. when xsl is running
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/xmlResponse">
<xsl:copy>
<xsl:apply-templates select="document('02.xml')/*/Person"/>
<xsl:apply-templates select="document('04.xml')/*/Person"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XSLT processor dependent.
Check first the parser
<xsl:variable name="vendor" select="system-property('xsl:vendor')" />
and then make a choose.
Microsoft use embedded javascript custom function (http://dev.ektron.com/kb_article.aspx?id=482), use FileSystemObject and returns 1 or 0 that can be then tested in XSLT.
Saxon,Xalan:
<xsl:variable name="d03" select="document('03.xml')"/>
<xsl:choose>
<xsl:when test="$d03">
<xsl:apply-templates select="document('03.xml')/*/Person"/>
</xsl:when>
<xsl:otherwise>
<Person name="Matthew" missing="true"/>
</xsl:otherwise></xsl:choose>