How to set a namespace prefix to a payload xsl - xslt

I have this payload, what I am intresting to know is how i can add this "TV:" namespace prefix to all nodes and elementes in it.
<TVInqResponse>
<TVInqRS>
<StatusCode>0</StatusCode>
<StatusDescription>Success</StatusDescription>
This is what is expect to have as a result:
<**tv**:TVInqResponse>
<**tv**:TVInqRS>
<**tv**:StatusCode>0</**tv**:StatusCode>
<**tv**:StatusDescription>Success</**tv**:StatusDescription>

This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tv="some:tv">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="tv:{name()}" namespace="some:tv">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document (based on the malformed provided "playload"...):
<TVInqResponse>
<TVInqRS>
<StatusCode>0</StatusCode>
<StatusDescription>Success</StatusDescription>
</TVInqRS>
</TVInqResponse>
produces the wanted, correct result:
<tv:TVInqResponse xmlns:tv="some:tv">
<tv:TVInqRS>
<tv:StatusCode>0</tv:StatusCode>
<tv:StatusDescription>Success</tv:StatusDescription>
</tv:TVInqRS>
</tv:TVInqResponse>
If you also want any attribute name to be in the same namespace, replace the template matching attributes with this one:
<xsl:template match="#*">
<xsl:attribute name="tv:{name()}" namespace="some:tv">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>

Related

How to remove the ns0 prefix from the xml output file with out removing the namespace declaration

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>

xspec: failure when expected and result are the same

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.

apply two consecutive xslt transformations

I have two xslt transformations to apply to an xml message.
The first is to drop all namespaces and prefixes. here is the code :
<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:template match="#*|node()[not(self::*)]">
<xsl:copy/>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The second one is to select elements from the output of the first :
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<onSale><xsl:value-of select="//entry/content/product_product/sale_ok" /></onSale>
<onlineOnly><xsl:value-of select="//entry/content/product_product/online" /></onlineOnly>
<name><xsl:value-of select="//entry/content/product_product/name" /></name>
<isbn><xsl:value-of select="//entry/content/product_product/isbn" /></isbn>
<price><xsl:value-of select="//entry/content/product_product/price" /></price>
<active><xsl:value-of select="//entry/content/product_product/active" /></active>
<format><xsl:value-of select="//entry/content/product_product/format" /></format>
<collection><xsl:value-of select="//entry/content/product_product/collection" /></collection>
<dateParution><xsl:value-of select="//entry/content/product_product/date_parution"/></dateParution>
<ean13><xsl:value-of select="//entry/content/product_product/ean13"/></ean13>
</xsl:template>
</xsl:stylesheet>
How I can apply the two of them in one xslt transformation without doing two transformation separately .
Thanks
I don't know which version of XSLT is supported in your environment, with XSLT 2.0 you can use
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="step1">
<xsl:apply-templates mode="step1"/>
</xsl:variable>
<xsl:template match="#*|node()[not(self::*)]" mode="step1">
<xsl:copy/>
</xsl:template>
<xsl:template match="*" mode="step1">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*" mode="step1"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$step1//entry"/>
</xsl:template>
<xsl:template match="entry">
<onSale><xsl:value-of select="content/product_product/sale_ok" /></onSale>
<onlineOnly><xsl:value-of select="content/product_product/online" /></onlineOnly>
<name><xsl:value-of select="content/product_product/name" /></name>
<isbn><xsl:value-of select="content/product_product/isbn" /></isbn>
<price><xsl:value-of select="content/product_product/price" /></price>
<active><xsl:value-of select="content/product_product/active" /></active>
<format><xsl:value-of select="content/product_product/format" /></format>
<collection><xsl:value-of select="content/product_product/collection" /></collection>
<dateParution><xsl:value-of select="content/product_product/date_parution"/></dateParution>
<ean13><xsl:value-of select="content/product_product/ean13"/></ean13>
</xsl:template>
</xsl:stylesheet>
I would further refactor however and write templates like
<xsl:template match="sale_ok">
<onSale>
<xsl:value-of select="."/>
</onSale>
</xsl:template>
If you use XSLT 1.0 you need an extension function to process the contents of a variable with apply-templates so doing
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="step1">
<xsl:apply-templates mode="step1"/>
</xsl:variable>
<xsl:template match="#*|node()[not(self::*)]" mode="step1">
<xsl:copy/>
</xsl:template>
<xsl:template match="*" mode="step1">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node()|#*" mode="step1"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="exsl:node-set($step1)//entry"/>
</xsl:template>
<xsl:template match="entry">
<onSale><xsl:value-of select="content/product_product/sale_ok" /></onSale>
<onlineOnly><xsl:value-of select="content/product_product/online" /></onlineOnly>
<name><xsl:value-of select="content/product_product/name" /></name>
<isbn><xsl:value-of select="content/product_product/isbn" /></isbn>
<price><xsl:value-of select="content/product_product/price" /></price>
<active><xsl:value-of select="content/product_product/active" /></active>
<format><xsl:value-of select="content/product_product/format" /></format>
<collection><xsl:value-of select="content/product_product/collection" /></collection>
<dateParution><xsl:value-of select="content/product_product/date_parution"/></dateParution>
<ean13><xsl:value-of select="content/product_product/ean13"/></ean13>
</xsl:template>
</xsl:stylesheet>
On the other I wonder why we are getting lots of questions recently trying to eliminate namespaces or to ignore them, if you really want to do that with XSLT 2.0 then doing
<xsl:template match="*:sale_ok">
<onSale>
<xsl:value-of select="."/>
<onSale>
</xsl:template>
and so on suffices.

XSLT select text without children

XML:
<data><ph>Foo</ph>Bar</data>
XSL:
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="data/ph"/>
<xsl:apply-templates select="data"/>
</xsl:template>
<xsl:template match="data/ph">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="data">
<xsl:value-of select="."/>
</xsl:template>
When the XSL selects the text in the /data/ with <xsl:template match="data"><xsl:value-of select="."/> it is also selecting the text in the child entity data/ph. How do I point to only the text of /data/, without including the text of /data/ph/ ?
My output should be: FooBar, and not FooFooBar.
When the XSL selects the text in the /data/ with <xsl:template
match="data"><xsl:value-of select="."/> it is also selecting the text
in the child entity data/ph. How do I point to only the text of
/data/, without including the text of /data/ph/ ?
Use:
<xsl:copy-of select="text()"/>
This copies all text node-children of the current node.
With this correction, the whole transformation becomes:
<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:template match="/">
<xsl:apply-templates select="data/ph"/>
<xsl:apply-templates select="data"/>
</xsl:template>
<xsl:template match="data/ph">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="data">
<xsl:copy-of select="text()"/>
</xsl:template>
</xsl:stylesheet>
and when applied on the provided XML document:
<data><ph>Foo</ph>Bar</data>
the wanted, correct result is produced:
FooBar

XSLT identity transform produces wrong namespace

I have a custom XML schema that is evolving: elements are added, others deleted, and the namespace changes to reflect the new version (e.g., from "http://foo/1.0" to "http://foo/1.1"). I want to write an XSLT that converts XML documents from the old schema to the new one. My first attempt works, but it's verbose and unscalable, and I need help refining it.
Here's a sample document for the 1.0 schema:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo:rootElement xmlns:foo="http://foo/1.0">
<obsolete>something</obsolete>
<stuff>
<alpha>a</alpha>
<beta>b</beta>
</stuff>
</foo:rootElement>
In the 1.1 schema, the "obsolete" element goes away but everything else remains. So the XSLT needs to do two things:
Remove the tag
Change the namespace from http://foo/1.0 to http://foo/1.1
Here's my solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo1="http://foo/1.0"
xmlns:foo="http://foo/1.1"
exclude-result-prefixes="foo1">
<xsl:output method="xml" standalone="yes" indent="yes"/>
<!-- Remove the "obsolete" tag -->
<xsl:template match="foo1:rootElement/obsolete"/>
<!-- Copy the "alpha" tag -->
<xsl:template match="foo1:rootElement/stuff/alpha">
<alpha>
<xsl:apply-templates/>
</alpha>
</xsl:template>
<!-- Copy the "beta" tag -->
<xsl:template match="foo1:rootElement/stuff/beta">
<beta>
<xsl:apply-templates/>
</beta>
</xsl:template>
<!-- Copy the "stuff" tag -->
<xsl:template match="foo1:rootElement/stuff">
<stuff>
<xsl:apply-templates/>
</stuff>
</xsl:template>
<!-- Copy the "rootElement" tag -->
<xsl:template match="foo1:rootElement">
<foo:rootElement>
<xsl:apply-templates/>
</foo:rootElement>
</xsl:template>
</xsl:stylesheet>
Although this produces the output I want, notice that I have a copying template for every element in the schema: alpha, beta, etc. For complex schemas with hundreds of kinds of elements, I'd have to add hundreds of templates!
I thought I could eliminate this problem by reducing all those copying templates into a single identity transform, like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:foo1="http://foo/1.0"
xmlns:foo="http://foo/1.1"
exclude-result-prefixes="foo1">
<xsl:output method="xml" standalone="yes" indent="yes"/>
<xsl:template match="foo1:rootElement/obsolete"/>
<xsl:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="foo1:rootElement/stuff">
<xsl:copy>
<xsl:call-template name="identity"/>
</xsl:copy>
</xsl:template>
<xsl:template match="foo1:rootElement">
<foo:rootElement>
<xsl:apply-templates/>
</foo:rootElement>
</xsl:template>
</xsl:stylesheet>
But it produces:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo:rootElement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:foo="http://foo/1.1">
<stuff xmlns:foo="http://foo/1.0">
<stuff>
<alpha>a</alpha>
<beta>b</beta>
</stuff>
</stuff>
</foo:rootElement>
The "stuff" element was copied, which is what I want, but it's wrapped in another "stuff" element, tagged with the old namespace. I don't understand why this is happening. I've tried many ways of fixing this but have been unsuccessful. Any suggestions? Thanks.
This 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="pOldNS" select="'http://foo/1.0'"/>
<xsl:param name="pNewNS" select="'http://foo/1.1'"/>
<xsl:template match="/*">
<xsl:element name="{name()}" namespace="{$pNewNS}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:copy-of select="namespace::*[not(.=$pOldNS)]"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:choose>
<xsl:when test="namespace-uri()=$pOldNS">
<xsl:attribute name="{name()}" namespace="{$pNewNS}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="obsolete"/>
</xsl:stylesheet>
when applied on this XML document:
<foo:rootElement xmlns:foo="http://foo/1.0">
<obsolete>something</obsolete>
<stuff>
<alpha x="y" foo:t="z">a</alpha>
<beta>b</beta>
</stuff>
</foo:rootElement>
produces the wanted, correct result (obsolute elements deleted, namespace upgraded, attribute nodes correctly processed, including nodes that were in the old namespace):
<foo:rootElement xmlns:foo="http://foo/1.1">
<stuff>
<alpha x="y" foo:t="z">a</alpha>
<beta>b</beta>
</stuff>
</foo:rootElement>
Main advantages of this solution:
Works correctly when there are attributes, belonging to the old-schema namespace.
General, allows the old and new namespace to be passed as external parameters to the transformation.
While you might want to copy the attributes, elements need to be regenerated in the new namespace. So I'd suggest to do it like this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:foo1="http://foo/1.0">
<xsl:template match="foo1:rootElement/obsolete"/>
<xsl:template match="attribute()">
<xsl:copy/>
</xsl:template>
<xsl:template match="element()">
<xsl:variable name="name" select="local-name()"/>
<xsl:element name="{$name}" namespace="http://foo/1.1">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>