I have the requirement to add the prefix to the namespace.
Input XML:
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<ProductMovementReport Version="5.0" xmlns="urn:cidx:names:specification:ces:schema:all:5:0">
<Header>
<ThisDocumentIdentifier>
<DocumentIdentifier>868</DocumentIdentifier>
</ThisDocumentIdentifier>
</Header>
</ProductMovementReport>
</soapenv:Body>
I also need to change the value of the Version ="'5'" which I am able to get successfully.
Below the is the desire output.
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<urn1:ProductMovementReport Version="4.0" xmlns:urn1="urn:cidx:names:specification:ces:schema:all:4:0">
<urn1:Header>
<urn1:ThisDocumentIdentifier>
<urn1:DocumentIdentifier>868</urn1:DocumentIdentifier>
</urn1:ThisDocumentIdentifier>
</urn1:Header>
</urn1:ProductMovementReport>
</soapenv:Body>
I have written the code for this and everything is working except the namespace part is not getting change. I guess I am missing something in the template match.
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*">
<xsl:choose>
<xsl:when test="local-name() = 'Version' ">
<xsl:attribute name="{local-name()}"><xsl:value-of select="'4.0'"/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="{local-name()}"><xsl:value-of select="."/></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*">
<xsl:element name="urn1:{local-name()}" namespace="urn:cidx:names:specification:ces:schema:all:4:0">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
Here is the link in case I missed anything http://xsltransform.net/bdxtpP.
I am very close to solving it except namespace part.
Can anyone please point me where I am doing it wrong?
Your match for match="*" is matching all elements regardless of namespace. Try narrowing the scope by testing the namespace URI.
XSLT 1.0
<xsl:stylesheet version="1.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="*[namespace-uri()='urn:cidx:names:specification:ces:schema:all:5:0']">
<xsl:element name="urn1:{local-name()}" namespace="urn:cidx:names:specification:ces:schema:all:4:0">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#Version">
<xsl:attribute name="{name()}">
<xsl:text>4.0</xsl:text>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Output
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<urn1:ProductMovementReport xmlns:urn1="urn:cidx:names:specification:ces:schema:all:4:0" Version="4.0">
<urn1:Header>
<urn1:ThisDocumentIdentifier>
<urn1:DocumentIdentifier>868</urn1:DocumentIdentifier>
</urn1:ThisDocumentIdentifier>
</urn1:Header>
</urn1:ProductMovementReport>
</soapenv:Body>
Related
i want to remove "nso" prefix from the output xml file with out removing the namespace declaration but in the declaration part also i need to remove "ns0:" & ":ns0".
`
<?xml version="1.0" encoding="UTF-8"?>
<ns0:Document xmlns:ns0="urn:iso:std:iso:20022:tech:xsd:abcd">**<!-- I do not want to remove this declaration line from the output only needs to remove "ns0:" & ":ns0" from the declaration-->**
<ns0:CstmrCdtTrfInitn>
<ns0:GrpHdr>
<ns0:MsgId>abcd</ns0:MsgId>
<ns0:CreDtTm>2023-01-24T14:47:17Z</ns0:CreDtTm>
<ns0:NbOfTxs>2 </ns0:NbOfTxs>
<ns0:CtrlSum>580000.00</ns0:CtrlSum>
<ns0:InitgPty>
<ns0:Nm>abcd</ns0:Nm>
<ns0:CtryOfRes>IN</ns0:CtryOfRes>
</ns0:InitgPty>
</ns0:GrpHdr>
</ns0:CstmrCdtTrfInitn>
</ns0:Document>`
`
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns ="urn:iso:std:iso:20022:tech:xsd:abcd">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>abcd</MsgId>
<CreDtTm>2023-01-24T14:47:17Z</CreDtTm>
<NbOfTxs>2 </NbOfTxs>
<CtrlSum>580000.00</CtrlSum>
<InitgPty>
<Nm>abcd</Nm>
<:CtryOfRes>IN</CtryOfRes>
</InitgPty>
</GrpHdr>
</CstmrCdtTrfInitn>
</Document>`
Please help me on this requirment.
Thanks.
i used below code but it is removing all the nso prefix's along with namespace declarations but i want to remove only nso prefix's for individual xml tags from the element "ns0:CstmrCdtTrfInitn" before this element i want to remove "ns0:" & ":ns0" and keep the declaration with out "ns0".
`
<?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" indent="no" />
<xsl:template match="/|comment()|processing-instruction()">
<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:stylesheet>
Change
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
to
<xsl:template match="/*//*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
and add a template
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
--- edited in view of changed requirement ---
To remove the ns0 prefix from all elements in the input XML, while keeping them in the original namespace, 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="*"/>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I use xspec for testing of stylesheets. Most of the time it works fine, but once in a while tests fail without a valid reason: the expected and the actual result are the same. Seemingly: everything is green in the comparison screen.
In that case, I mostly get it working again after trying all kinds of things, but without knowing what change 'did it'.
It would be most helpful if xspec would report the reason of the failure, but if you can help me (instead of the xspec output) to shine some light on this, I'd be very happy.
This is a reduced test case:
xsl:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:uc="http://www.infinity-loop.de/namespace/upcast/4.0/"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:html="http://www.w3.org/HTML/1998/html4"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="uc xlink html xs xsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="bezwaar">
<xsl:variable name="content">
<xsl:element name="{name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:variable>
<xsl:copy-of select="$content"/>
</xsl:template>
<xsl:template match="#*" >
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
xspec:
<?xml version="1.0" encoding="UTF-8"?>
<x:description
xmlns:x = "http://www.jenitennison.com/xslt/xspec"
stylesheet="file:/home/rdgon/project/kraak/kraak-xslt/publicatiebladen/staatscourant/stcrt_step2.xsl">
<x:param name='ns' select="false()"/>
<x:scenario label='test'>
<x:scenario label='werkt dit'>
<x:context><bezwaar>
<al>Noem in het bezwaarschrift:</al>
<al nadruk="cur">Vergeet niet te ondertekenen.</al>
</bezwaar>
</x:context>
<x:expect>
<bezwaar>
<al>Noem in het bezwaarschrift:</al>
<al nadruk="cur">Vergeet niet te ondertekenen.</al>
</bezwaar>
</x:expect>
</x:scenario>
</x:scenario>
</x:description>
Test report showing failure:
Can you explain what I am failing to see?
Ruud
Because xsl:variable doesn't have #as, your result is a document node. But your x:expect expects an element.
If you want to let your x:expect expect a document node, you need to add select="/" to x:expect. Look for an explanation "If you specify no #select" in XSpec Wiki.
If you have run your XSL then bezwaar Element come 2 times and come extra namespace because you have x:context and x:expect in the same element. if you want to x:expect same as x:context then you can try this code.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:x = "http://www.jenitennison.com/xslt/xspec"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs x">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="x:scenario">
<xsl:apply-templates select="x:scenario/x:context/bezwaar"/>
</xsl:template>
<xsl:template match="bezwaar">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="al">
<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>
or if you want bezwaar multiple times then you can comment 1st template match.
I'm developing an application and I need to add several elements into the header of soap message I receive. The problem is I don't know which prefix the namespace I'm using for adding these elements is using, but it's sure there will be several elements in the body using this prefix, so the namespace is already declared in the message.
For example, I'm receiving this message:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com" xmlns:urn1="urn:sobject.enterprise.soap.sforce.com">
<soapenv:Header/>
<soapenv:Body>
<urn:operation>
</urn:operation>
</soapenv:Body>
</soapenv:Envelope>
And the xpath expression I use for adding these elements in the header is:
<xsl:stylesheet version="1.0" exclude-result-prefixes="xsi xsl" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="Getsed">aBcDeFgHiJkLmNñOpQrStUvWxYz</xsl:param>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[local-name()='Header']">
<xsl:copy>
<urn:SH xmlns:urn="urn:enterprise.soap.sforce.com">
<urn:sed><xsl:value-of select="$Getsed"/></urn:sed>
</urn:SH>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I would like to use the prefix (urn) already declared for the namespace urn:enterprise.soap.sforce.com.
Could you please give me a hand?
I believe a silly workaround like <xsl:value-of select="substring-before(name(//*[namespace-uri() = 'urn:enterprise.soap.sforce.com']), ':')" /> will fit your needs.
Thus your template can be rewrited that way:
<xsl:template match="*[local-name()='Header']">
<!-- this will retrieve the namespace prefix in source document -->
<xsl:variable name="ns-sforce">
<xsl:value-of select="substring-before(name(//*[namespace-uri() = 'urn:enterprise.soap.sforce.com']), ':')" />
</xsl:variable>
<xsl:copy>
<!-- create prefixed elements with the same value as before -->
<xsl:element name="{$ns-sforce}:SH" namespace="urn:enterprise.soap.sforce.com">
<xsl:element name="{$ns-sforce}:sed" namespace="urn:enterprise.soap.sforce.com">
<xsl:value-of select="$Getsed"/>
</xsl:element>
</xsl:element>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
Note: <xsl:template match="//*[local-name()='Header']"> can be replaced by <xsl:template match="*[local-name()='Header']">
I'm struggling with trying to test to see if an element exists. If it doesn't, I'd like to add in a default value. Here's my XML
<records>
<record>
<InstanceData>
<instance>
<FirstName>Johhny</FirstName>
<LastName>Jenkins</LastName>
<AlbumCount>3</AlbumCount>
</instance>
</InstanceData>
</record>
<record>
<InstanceData>
<instance>
<FirstName>Art</FirstName>
<LastName>Tatum</LastName>
<AlbumCount>7</AlbumCount>
</instance>
</InstanceData>
</record>
<record>
<InstanceData>
<instance>
<FirstName>Count</FirstName>
<LastName>Basie</LastName>
</instance>
</InstanceData>
</record>
</records>
I'd like to be able to copy over existing values and set any record without the Album Count element to <AlbumCount>0</AlbumCount>. This is the xslt I've been working with but I think I'm some way off the mark.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="Records">
<xsl:for-each select="node()">
<xsl:choose>
<xsl:when test="name()='AlbumCount'">
<xsl:element name="AlbumCount">
<xsl:choose>
<xsl:when test="name()='AlbumCount'">
<xsl:copy-of select=".">
</xsl:copy-of>
</xsl:when>
<xsl:otherwise>
<AlbumCount>0</AlbumCount>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select=".">
</xsl:copy-of>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Thanks for looking.
Try this:
<?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" omit-xml-declaration="no"/>
<!-- identity template -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="instance[not(AlbumCount)]">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<AlbumCount>0</AlbumCount>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Start with the identity transformation, then just handle the exception differently.
You test for the existance of an element simply with the elements name, for example:
<xsl:if test="not(AlbumCount)">
<AlbumCount>0</AlbumCount>
</xsl:if>
The simpler way to do what you want is to use the standard copy template combined with a special rule for places where AlbumCount elements need adding:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<!-- Standard copy template -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Special template to add AlbumCount elements where required -->
<xsl:template match="records/record/InstanceData/instance">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
<xsl:if test="not(AlbumCount)">
<AlbumCount>0</AlbumCount>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I have an XML document, and I want to change the values for one of the attributes.
First I copied everything from input to output using:
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
And now I want to change the value of the attribute "type" in any element named "property".
This problem has a classical solution: Using and overriding the identity template is one of the most fundamental and powerful XSLT design patterns:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pNewType" select="'myNewType'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="property/#type">
<xsl:attribute name="type">
<xsl:value-of select="$pNewType"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
When applied on this XML document:
<t>
<property>value1</property>
<property type="old">value2</property>
</t>
the wanted result is produced:
<t>
<property>value1</property>
<property type="myNewType">value2</property>
</t>
Tested on a simple example, works fine:
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#type[parent::property]">
<xsl:attribute name="type">
<xsl:value-of select="'your value here'"/>
</xsl:attribute>
</xsl:template>
Edited to include Tomalak's suggestion.
The top two answers will not work if there is a xmlns definition in the root element:
<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<property type="old"/>
</html>
All of the solutions will not work for the above xml.
The possible solution is like:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()[local-name()='property']/#*[local-name()='type']">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
some new value here
</xsl:attribute>
</xsl:template>
<xsl:template match="#*|node()|comment()|processing-instruction()|text()">
<xsl:copy>
<xsl:apply-templates select="#*|node()|comment()|processing-instruction()|text()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You need a template that will match your target attribute, and nothing else.
<xsl:template match='XPath/#myAttr'>
<xsl:attribute name='myAttr'>This is the value</xsl:attribute>
</xsl:template>
This is in addition to the "copy all" you already have (and is actually always present by default in XSLT). Having a more specific match it will be used in preference.
I had a similar case where I wanted to delete one attribute from a simple node, and couldn't figure out what axis would let me read the attribute name. In the end, all I had to do was use
#*[name(.)!='AttributeNameToDelete']
I also came across same issue and i solved it as follows:
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- copy property element while only changing its type attribute -->
<xsl:template match="property">
<xsl:copy>
<xsl:attribute name="type">
<xsl:value-of select="'your value here'"/>
</xsl:attribute>
<xsl:apply-templates select="#*[not(local-name()='type')]|node()"/>
</xsl:copy>
</xsl:template>
For the following XML:
<?xml version="1.0" encoding="utf-8"?>
<root>
<property type="foo"/>
<node id="1"/>
<property type="bar">
<sub-property/>
</property>
</root>
I was able to get it to work with the following XSLT:
<?xml version="1.0" encoding="utf-8"?>
<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="//property">
<xsl:copy>
<xsl:attribute name="type">
<xsl:value-of select="#type"/>
<xsl:text>-added</xsl:text>
</xsl:attribute>
<xsl:copy-of select="child::*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If your source XML document has its own namespace, you need to declare the namespace in your stylesheet, assign it a prefix, and use that prefix when referring to the elements of the source XML - for example:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />
<!-- identity transform -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- exception-->
<xsl:template match="xhtml:property/#type">
<xsl:attribute name="type">
<xsl:text>some new value</xsl:text>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Or, if you prefer:
...
<!-- exception-->
<xsl:template match="#type[parent::xhtml:property]">
<xsl:attribute name="type">
<xsl:text>some new value</xsl:text>
</xsl:attribute>
</xsl:template>
...
ADDENDUM:
In the highly unlikely case where the XML namespace is not known beforehand, you could do:
<?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" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />
<!-- identity transform -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- exception -->
<xsl:template match="*[local-name()='property']/#type">
<xsl:attribute name="type">
<xsl:text>some new value</xsl:text>
</xsl:attribute>
</xsl:template>
Of course, it's very difficult to imagine a scenario where you would know in advance that the source XML document contains an element named "property", with an attribute named "type" that needs replacing - but still not know the namespace of the document. I have added this mainly to show how your own solution could be streamlined.