Use XSLT to convert delimited text to XML - xslt-1.0

I have some double pipe delimited data inside some XML tags and I would like to replace/convert the delimited text to XML.
The delimited text also uses a colon to separate the heading and the data, like so: ||tagname:data||
The headings or tag names could be anything, this is just one example. So I don't know in advance what I'm getting. I must take what's listed in front of the colon and use that.
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname ||phone:3282||email:Lori.KS#.edu||officenumber:D-107A||vcard:https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b||photo:https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846||pronunciation:https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846|| </str>
</arr>
</doc>
Can I use XSLT to transform this XML into this?
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname
<phone>3282</phone>
<email>Lori.KS#.edu</email>
<officenumber>D-107A</officenumber>
<vcard>https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b</vcard>
<photo>https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</photo>
<pronunciation>https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</pronunciation>
</str>
</arr>
</doc>
The URLs will have to be wrapped in CDATA and the delimited version will have to be replaced.
Can someone point me in the right direction?
Thank you,

analyze-string can help, with Saxon 9.5 the stylesheet
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="str">
<xsl:copy>
<xsl:analyze-string select="." regex="\|((\|[^|]+\|)+)\|">
<xsl:matching-substring>
<xsl:analyze-string select="regex-group(1)" regex="\|(\w+):([^|]+)\|">
<xsl:matching-substring>
<xsl:element name="{regex-group(1)}">
<xsl:value-of select="regex-group(2)"/>
</xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
transforms the input
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname ||phone:3282||email:Lori.KS#.edu||officenumber:D-107A||vcard:https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b||photo:https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846||pronunciation:https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846|| </str>
</arr>
</doc>
into the result
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname <phone>3282</phone>
<email>Lori.KS#.edu</email>
<officenumber>D-107A</officenumber>
<vcard>https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b</vcard>
<photo>https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</photo>
<pronunciation>https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</pronunciation>
</str>
</arr>
</doc>

Related

How to read Data from a file using XSLT in IBM API connect

I am working on creating REST API's in IBM API connect. our requirement is to get the backend URL's from a property file which is present on the datapower gateway server and then invoke the back-end service in the API's.
In API assembly I have written the XSLT code to open the file and read the data from the file, but the xslt is returning an empty response.
XSLT Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:func="http://exslt.org/functions"
xmlns:apim="http://www.ibm.com/apimanagement"
extension-element-prefixes="dp func apim"
exclude-result-prefixes="dp func apim">
<!-- Cotains the APIM functions -->
<xsl:import href="local:///isp/policy/apim.custom.xsl"/>
<xsl:template match="/">
<xsl:variable name="FileContent">
<dp:url-open target="'https://localhost:9090/dp'" response="xml" data-type="filename">local:///policy/propertyfiles/URLs.xml
</dp:url-open>
</xsl:variable>
<xsl:variable name="policy-props" select="apim:policyProperties()"/>
<xsl:variable name="catalog" select="apim:getContext('env.path')"/>
<outputXml>
<data><xsl:copy-of select="$FileContent" /></data>
<catalog><xsl:value-of select="$catalog" /></catalog>
<xsl:for-each select="$FileContent/catalogs/catalog">
<xsl:variable name="ReferencedID" select="#name"/>
<xsl:choose>
<xsl:when test="$ReferencedID = $catalog">
<backend_url><xsl:value-of select="$FileContent/response/catalogs/catalog/backend_url" /></backend_url>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</outputXml>
</xsl:template>
</xsl:stylesheet>
I am expecting to see the data from the file in the xslt response . But I see the below response which is missing the data from the file.
Body:
<?xml version="1.0" encoding="UTF-8"?>
<outputXml>
<data/>
<catalog>sb</catalog>
</outputXml>
Either use dp:url-open or possibly the document() function.
Another option is to add a GWS action to read the file and set it in a context variable.
Use below XSLT code it will capture Reques-
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.datapower.com/extensions"
xmlns:json="http://www.ibm.com/xmlns/prod/2009/jsonx"
xmlns:func="http://exslt.org/functions"
xmlns:apim="http://www.ibm.com/apimanagement" extension-element-prefixes="dp func apim" exclude-result-prefixes="xsl dp func apim">
<!-- Contains the APIM functions -->
<xsl:import href="local:///isp/policy/apim.custom.xsl" />
<xsl:template match="/">
<xsl:variable name="input" select="apim:payloadRead()" />
<xsl:message>
The input payload is
<xsl:copy-of select="$input" />
</xsl:message>
</xsl:template>
</xsl:stylesheet>

How to get shortest XML subtree with current node?

I have something like:
<XML>
<LEVEL1A>
<LEVEL2AA>
<LEVEL3AAA>Some textAAA</LEVEL3AAA>
</LEVEL2AA>
<LEVEL2AB>Some textAB</LEVEL2AB>
</LEVEL1A>
<LEVEL1B>
<LEVEL2BA>Some textBA</LEVEL2BA>
</LEVEL1B>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAA>Some textCAA</LEVEL3CAA>
<LEVEL3CAB>Some textCAB</LEVEL3CAB>
</LEVEL2CA>
<LEVEL2CB>Some textCB</LEVEL2CB>
<LEVEL2CC>Some textCC</LEVEL2CC>
</LEVEL1C>
</XML>
And if I need to get all parents as XML-tree of node //XML/LEVEL1C/LEVEL2CA/LEVEL3CAB, then result should be receive:
<XML>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAB>Some textCAB</LEVEL3CAB>
</LEVEL2CA>
</LEVEL1C>
</XML>
So, I don't need to just get parents names, but I need entire subtree.
If I have points //XML/LEVEL1C/LEVEL2CA/LEVEL3CAB and //XML/LEVEL1A/LEVEL2AA/LEVEL3AAA to a node tree, then I have to receive:
<XML>
<LEVEL1A>
<LEVEL2AA>
<LEVEL3AAA>Some textAAA</LEVEL3AAA>
</LEVEL2AA>
</LEVEL1A>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAB>Some textCAB</LEVEL3CAB>
</LEVEL2CA>
</LEVEL1C>
</XML>
Is there a way to do it?
UPD:
I have for-each loop, where at end I return <xsl:copy-of select="$output-node"/> it's a part of named template, where $output-node is <xsl:with-param name="output-node" select="//XML/LEVEL1A/LEVEL2CA/LEVEL3CAB"/> when this named template called.
But now I need to not just print that node, but print that node and shortest XML subtree with that node.
UPD2:
Here is xslt example to parse it:
<xsl:template name="printme">
<xsl:param name="output-node"/>
<CURRENT_NODE>
<xsl:copy-of select="$output-node"/>
</CURRENT_NODE>
</xsl:template>
<xsl:for-each select="//XML">
<xsl:if test="//current()/text() = 'Some textCAB'">
<xsl:call-template name="comparefunc">
<xsl:with-param name="output-node" select="//current()"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
Now I need incide CURRENT_NODE not just <LEVEL3CAB>Some textCAB</LEVEL3CAB>, but whole:
<CURRENT_NODE>
<XML>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAB>Some textCAB</LEVEL3CAB>
</LEVEL2CA>
</LEVEL1C>
</XML>
</CURRENT_NODE>
For simplicity, let me adjust your input example to:
<XML>
<LEVEL1A>
<LEVEL2AA>
<LEVEL3AAA>error</LEVEL3AAA>
</LEVEL2AA>
<LEVEL2AB>ok</LEVEL2AB>
</LEVEL1A>
<LEVEL1B>
<LEVEL2BA>ok</LEVEL2BA>
</LEVEL1B>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAA>ok</LEVEL3CAA>
<LEVEL3CAB>error</LEVEL3CAB>
</LEVEL2CA>
<LEVEL2CB>ok</LEVEL2CB>
<LEVEL2CC>ok</LEVEL2CC>
</LEVEL1C>
</XML>
In this example, we'll be interested in elements that contain the text "error". The first step will create a variable containing a node-set of all elements that pass this test. Then we'll go over the entire tree and leave only these elements and their ancestors:
XSLT 1.0
<?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" />
<!-- 1. identify nodes of interest -->
<xsl:variable name="errors" select="//*[.='error']" />
<!-- 2. traverse the entire tree, leaving only nodes of interest and their ancestors -->
<xsl:template match="*">
<xsl:choose>
<xsl:when test="descendant::*[count(.|$errors) = count($errors)]">
<!-- at least one of the descendants is a member of $errors -->
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:when>
<xsl:when test="count(.|$errors) = count($errors)">
<!-- this element is a member of $errors -->
<xsl:copy-of select="."/>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When applied to our example input, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LEVEL1A>
<LEVEL2AA>
<LEVEL3AAA>error</LEVEL3AAA>
</LEVEL2AA>
</LEVEL1A>
<LEVEL1C>
<LEVEL2CA>
<LEVEL3CAB>error</LEVEL3CAB>
</LEVEL2CA>
</LEVEL1C>
</XML>

Using XSLT to visit child nodes and retrieve element values

Using the following input XML, my goal is to initially select portfolios/portfolio node, then the <tradeContribution> child nodes - specifically contributions/tradeContribution .
These tradeContribution nodes will then be transformed into the <trade> nodes in the xml output shown below.
My xml output and XSLT code follows below...
<outBound>
<requestReceivedTime>2014-05-15 15:20:42.279</requestReceivedTime>
<responseSentTime>2014-05-15 15:20:42.338</responseSentTime>
<body>
<portfolios>
<portfolio id="36" nodeDate="2014-05-06">
<query>
<firstTerm>
<date>2014-05-06</date>
</firstTerm>
<lastTerm>
<date>2014-05-06</date>
</lastTerm>
</query>
<exposure>492691.50878619519</exposure>
<contributions>
<tradeContribution contextId="0" contribution="267624.242492124" dealId="IRSW-TRADE-00011" desc="IRSW-FIX-FLOAT" order="0" sysId="1" tradeId="IRSW-TRADE-00011">
<hideTrade>false</hideTrade>
<readOnly>false</readOnly>
</tradeContribution>
<tradeContribution contextId="7" contribution="225067.26629407122" dealId="IRSW-TRADE-00020" desc="IRSW-FIX-FLOAT" order="1" sysId="2" tradeId="IRSW-TRADE-00020">
<hideTrade>false</hideTrade>
<readOnly>false</readOnly>
</tradeContribution>
</contributions>
<nodeAnalysis id="HSVaR 5D 100 ES">
<method>INTERPOLATED_EXPECTED_SHORTFALL</method>
<exposure>true</exposure>
<percentile>100</percentile>
</nodeAnalysis>
</portfolio>
</portfolios>
</body>
</outBound>
My desired XML output is:
<?xml version="1.0" ?>
<collection>
<trade>
<legal_id>36</legal_id>
<tradeRef>IRS-RRT-002</tradeRef>
<system>MY SYSTEM IRS</system>
<indepMtmValuation>111111</indepMtmValuation>
<indepMtmValuationCcy>USD</indepMtmValuationCcy>
<principalDealLevelUpfront>TRUE</principalDealLevelUpfront>
<principalDealLevelAmount>14</principalDealLevelAmount>
<principalDealLevelCurrency>USD</principalDealLevelCurrency>
<principalDealLevelType>Independent Amount</principalDealLevelType>
<operation>U</operation>
</trade>
<trade>
<legal_id>36</legal_id>
<system>MY SYSTEM CDS</system>
<tradeRef>CDS-RRT-008</tradeRef>
<mtmValuation>222222</mtmValuation>
<mtmValuationDate>2013-09-11</mtmValuationDate>
<mtmValuationLocalSysCcy>USD</mtmValuationLocalSysCcy>
<counterpartyDealLevelUpfront>TRUE</counterpartyDealLevelUpfront>
<counterpartyDealLevelAmount>15</counterpartyDealLevelAmount>
<counterpartyDealLevelCurrency>JPY</counterpartyDealLevelCurrency>
<counterpartyDealLevelType>Independent Amount</counterpartyDealLevelType>
</trade>
</collection>
The XSLT I have so far is as follows; however, I have a problem:
1) Trying to find the best way to pull the value of attribute "id", which is part of <portfolio id="36" nodeDate="2014-05-06"> .
I need to output it to <legal_id>, but this here is NOT working:
<legal_id><xsl:value-of select="../portfolio[#id]"/></legal_id>
Your advice would be greatly appreciate in helping to properly construct my XSLT to produce the desired XML output shown above:
My XSLT code thus far:
<?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"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="xs xd"
version="1.0">
<!-- Variable declaration -->
<xsl:variable name="hsVar1D" select="'1D (99%)'"></xsl:variable>
<xsl:variable name="hsVar5D" select="'HSVaR 5D 100 ES'"></xsl:variable>
<xsl:template match="/*">
<collection>
<xsl:apply-templates select="/outbound/body/portfolios/portfolio[descendant::nodeAnalysis[#id[contains(.,$hsVar5D)]]]" />
</collection>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates select="contributions/tradeContribution"/>
</xsl:template>
<xsl:template match="contributions/tradeContribution">
<trade>
<!-- QUESTION: For <legal_id> what is the best way to select the #id attrib from the ancestor node <portfolio> -->
<legal_id><xsl:value-of select="#id"/></legal_id>
<legal_id222><xsl:value-of select="../portfolio[#id]"/></legal_id222>
<tradeRef>IRS-RRT-002</tradeRef>
<system>MY SYSTEM IRS</system>
<indepMtmValuation>111111</indepMtmValuation>
<indepMtmValuationCcy>USD</indepMtmValuationCcy>
<principalDealLevelUpfront>TRUE</principalDealLevelUpfront>
<principalDealLevelAmount><xsl:value-of select="exposure"></xsl:value-of></principalDealLevelAmount>
<principalDealLevelCurrency>USD</principalDealLevelCurrency>
<principalDealLevelType>Independent Amount</principalDealLevelType>
<operation>U</operation>
</trade>
</xsl:template>
Try it this way:
<?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"/>
<!-- Variable declaration -->
<xsl:variable name="hsVar1D" select="'1D (99%)'"></xsl:variable>
<xsl:variable name="hsVar5D" select="'HSVaR 5D 100 ES'"></xsl:variable>
<xsl:template match="/">
<collection>
<xsl:apply-templates select="outBound/body/portfolios/portfolio[nodeAnalysis[contains(#id,$hsVar5D)]]/contributions/tradeContribution" />
</collection>
</xsl:template>
<xsl:template match="tradeContribution">
<trade>
<legal_id>
<xsl:value-of select="../../../portfolio/#id"/>
</legal_id>
<tradeRef>IRS-RRT-002</tradeRef>
<system>RAZOR IRS</system>
<indepMtmValuation>111111</indepMtmValuation>
<indepMtmValuationCcy>USD</indepMtmValuationCcy>
<principalDealLevelUpfront>TRUE</principalDealLevelUpfront>
<principalDealLevelAmount>
<xsl:value-of select="../../nodeAnalysis/exposure"/>
</principalDealLevelAmount>
<principalDealLevelCurrency>USD</principalDealLevelCurrency>
<principalDealLevelType>Independent Amount</principalDealLevelType>
<operation>U</operation>
</trade>
</xsl:template>
</xsl:stylesheet>
--
Note outBound vs. razorOutbound

XProc: XD0001 It is a dynamic error if a non-XML resource is produced on a step output or arrives on a step input

Requirement: Is to add correct Doctype declaration on the output xml [The root element of the input xml can be chapter or section element]
Input XML: chapter.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "docbookx.dtd">
<chapter>
<title>Chapter Template Title</title>
<para>Text</para>
<section>
<title>Section Title</title>
<para>Section text</para>
</section>
</chapter>
XSLT file: test.xsl:
Stylesheet just copies input xml to output and adds #sec on all
element
Stylesheet adds correct doctype declaration to output xml, because
the input xml root element can be <chapter> or
<section> element
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="add-doctype-declaration">
<xsl:choose>
<xsl:when test="/chapter">
<xsl:text disable-output-escaping="yes">
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "docbookx.dtd">
</xsl:text>
</xsl:when>
<xsl:when test="/section">
<xsl:text disable-output-escaping="yes">
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "docbookx.dtd">
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="add-doctype-declaration"/>
<xsl:apply-templates/>
</xsl:template>
<!-- Identity Template -->
<xsl:template match="#*|*|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="section">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="sec">
<xsl:number/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Expected output.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "docbookx.dtd">
<chapter>
<title>Chapter Template Title</title>
<para>Text</para>
<section sec="1">
<title>Section Title</title>
<para>Section text</para>
</section>
</chapter>
Using any XSLT engine, the transformation works absolutely fine, and able to get the expected output
But, if the transformation is done through XProc I end up with the following error. Can someone help in resolving this error
err:XD0001 : XD0001 It is a dynamic error if a non-XML resource is
produced on a step output or arrives on a step input.
XProc file: test.xpl
<?xml version="1.0" encoding="UTF-8"?>
<p:declare-step xmlns:p="http://www.w3.org/ns/xproc"
xmlns:c="http://www.w3.org/ns/xproc-step" version="1.0" name="testing">
<p:input port="source">
<p:document href="chapter.xml"/>
</p:input>
<p:output port="result">
<p:empty/>
</p:output>
<p:xslt version="1.0" name="transform">
<p:input port="stylesheet">
<p:document href="test.xsl"/>
</p:input>
<p:input port="parameters">
<p:empty/>
</p:input>
</p:xslt>
<p:store omit-xml-declaration="false" encoding="utf-8" name="serialize">
<p:with-option name="href" select="output.xml"/>
</p:store>
</p:declare-step>
Here is two simple examples that shows that you don't need to contextualize the Doctype generation
Section
http://www.sharexml.com/x/get?k=uWn0KA7RThnt
Chapter http://www.sharexml.com/x/get?k=wAJlbUJfzIYQ
Hope this helps
[UPDATED AFTER ANSWER]
And if you want that doctype change dynamically
Section http://www.sharexml.com/x/get?k=pBAwCds86RnQ
Chapter http://www.sharexml.com/x/get?k=JHEWghzgWIq1
Hope this helps
What goes wrong here is that the doctype you are creating here, is passed as part of the result of the XSLT step to the XProc engine. However, it is passed as character data outside the root element. XProc does not allow this.
There are actually two issues with approach:
Don't use disable-output-escaping unless you can't do anything else. The xsl:output instruction has perfect means to create the doctype you want, just add a public-doctype and system-doctype attribute to it.
output options of the XSLT will be ignored, as the result isn't actually being serialized by the XSLT engine, but by XPRoc. So you will have to put those doctype attribute on the p:store step, to make it work within XProc.
HTH!

Xslt to copy inner xml without unused namespaces

I wish to remove a couple of unused namespaces from a resulting output from an xslt stylesheet.
The xml to feed in is a wrapper around another xml message which is seen in the BodyMessage element. An example of the entire xml can bee seen below:
<?xml version="1.0" encoding="utf-8"?>
<ns0:Wrapper xmlns:ns0="http://ref.fairyliquidplc.ads/Schema/Fairy/Wrapper/1.0" xmlns:mco="http://ref.fairyliquidplc.ads/Schema/Fairy/Common/1.0">
<TaskName>SomeTaskName</TaskName>
<TaskStatus>Start</TaskStatus>
<Id>Y/0070/0010</Id>
<BodyMessage>
<tva:TVAMain rightsOwner="FAIRY" xmlns:tva="urn:tva:metadata:2004">
<tva:Colour>red</tva:Colour>
<tva:Size>12</tva:Size>
<tva:Style>Skinny</tva:Style>
<tva:Fabric>Denim</tva:Fabric>
</tva:TVAMain>
</BodyMessage>
</ns0:Wrapper>
When I try to extract the xml out of the BodyMessage element I get unused namespaces returned
xmlns:ns0="http://ref.fairyliquidplc.ads/Schema/Fairy/Wrapper/1.0"
xmlns:mco="http://ref.fairyliquidplc.ads/Schema/Fairy/Common/1.0"
These are not required but I do not understand how to remove them within my xslt.
Please note I DO want to keep
xmlns:tva="urn:tva:metadata:2004"
The stylesheet I used is:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tva="urn:tva:metadata:2004"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:output encoding="UTF-8" method="xml" omit-xml-declaration="no" version="1.0" />
<xsl:template match="/">
<xsl:variable name="completeTva" select="//tva:TVAMain" />
<xsl:copy-of select ="$completeTva"/>
</xsl:template>
The output of the stylesheet is:
<?xml version="1.0" encoding="utf-8"?>
<tva:TVAMain rightsOwner="FAIRY" xmlns:tva="urn:tva:metadata:2004" xmlns:ns0="http://ref.fairyliquidplc.ads/Schema/Fairy/Wrapper/1.0" xmlns:mco="http://ref.fairyliquidplc.ads/Schema/Fairy/Common/1.0">
<tva:Colour>red</tva:Colour>
<tva:Size>12</tva:Size>
<tva:Style>Skinny</tva:Style>
<tva:Fabric>Denim</tva:Fabric>
What I require is:
<?xml version="1.0" encoding="utf-8"?>
<tva:TVAMain rightsOwner="FAIRY" xmlns:tva="urn:tva:metadata:2004">
<tva:Colour>red</tva:Colour>
<tva:Size>12</tva:Size>
<tva:Style>Skinny</tva:Style>
<tva:Fabric>Denim</tva:Fabric>
Any help would be greatly appreciated.
:)
This transformation (Sorry, this is a bug in the SO code-formatter!):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tva="urn:tva:metadata:2004"
xmlns:ns0="http://ref.fairyliquidplc.ads/Schema/Fairy/Wrapper/1.0"
xmlns:mco="http://ref.fairyliquidplc.ads/Schema/Fairy/Common/1.0"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vtoDiscard" select=
"document('')
/*/namespace::*[name()='ns0' or name()='mco']"/>
<xsl:template match="tva:*">
<xsl:element name="{name()}"
namespace="urn:tva:metadata:2004">
<xsl:copy-of select="namespace::*[not(. = $vtoDiscard)]"/>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="text()[not(ancestor::BodyMessage)]"/>
</xsl:stylesheet>
when applied on the provided XML document:
<ns0:Wrapper
xmlns:ns0="http://ref.fairyliquidplc.ads/Schema/Fairy/Wrapper/1.0"
xmlns:mco="http://ref.fairyliquidplc.ads/Schema/Fairy/Common/1.0">
<TaskName>SomeTaskName</TaskName>
<TaskStatus>Start</TaskStatus>
<Id>Y/0070/0010</Id>
<BodyMessage>
<tva:TVAMain rightsOwner="FAIRY"
xmlns:tva="urn:tva:metadata:2004">
<tva:Colour>red</tva:Colour>
<tva:Size>12</tva:Size>
<tva:Style>Skinny</tva:Style>
<tva:Fabric>Denim</tva:Fabric>
</tva:TVAMain>
</BodyMessage>
</ns0:Wrapper>
produces the wanted, correct result:
<tva:TVAMain xmlns:tva="urn:tva:metadata:2004" rightsOwner="FAIRY">
<tva:Colour>red</tva:Colour>
<tva:Size>12</tva:Size>
<tva:Style>Skinny</tva:Style>
<tva:Fabric>Denim</tva:Fabric>
</tva:TVAMain>
Explanation:
Both xsl:copy and xsl:copy-of copy an element together with the namespace nodes that belong to it.
The way to strip some namespace nodes off an element is to re-create it using the xsl:element, then to copy from the original element only the wanted namespace nodes.