Excluding Namespaces in XML results - xslt

I am trying to figure out how best I can process the XML file below so the resulting XML file excludes namespace declarations.
XML Input
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/">
<b:title>Book Title</b:title>
<p:number>page001</p:number>
<p:number>page002</p:number>
<p:number>page001</p:number>
<p:number>page002</p:number>
</page>
Current XSL File
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="http://book.com/"
xmlns:p="http://page.com/"
>
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:template match="resource">
<xsl:apply-templates select="b:title" />
<xsl:apply-templates select="p:number" />
</xsl:template>
<xsl:template match="b:title">
<title exclude-result-prefixes="#all">
<xsl:value-of select="." />
</title>
</xsl:template>
<xsl:template match="p:number">
<page exclude-result-prefixes="#all">
<xsl:value-of select="." />
</page>
</xsl:template>
</xsl:stylesheet>
Current Output
<title xmlns:b="http://book.com/" xmlns:p="http://page.com/" exclude-result-prefixes="#all">Book Title</title>
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/" exclude-result-prefixes="#all">page001</page>
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/" exclude-result-prefixes="#all">page002</page>
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/" exclude-result-prefixes="#all">page001</page>
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/" exclude-result-prefixes="#all">page002</page>
Desired Output
<?xml version="1.0" encoding="UTF-8"?>
<title>Book Title</title>
<page>page001</page>
<page>page002</page>
<page>page001</page>
<page>page002</page>

This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[local-name()='number']">
<page>
<xsl:value-of select="."/>
</page>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<page xmlns:b="http://book.com/" xmlns:p="http://page.com/">
<b:title>Book Title</b:title>
<p:number>page001</p:number>
<p:number>page002</p:number>
<p:number>page001</p:number>
<p:number>page002</p:number>
</page>
produces the wanted, correct result:
<page>
<title>Book Title</title>
<page>page001</page>
<page>page002</page>
<page>page001</page>
<page>page002</page>
</page>
Explanation:
Use of the xsl:element instruction to create (not copy!) a new element with name that is the local-name() of the matched element.
A template matching elements with local-name() number to "rename" them to page

Use the exclude-result-prefixes attribute on the xsl:stylesheet element.
In your case, something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="http://book.com/"
xmlns:p="http://page.com/"
exclude-result-prefixes="b p"
>
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:template match="resource">
<xsl:apply-templates select="b:title" />
<xsl:apply-templates select="p:number" />
</xsl:template>
<xsl:template match="b:title">
<title>
<xsl:value-of select="." />
</title>
</xsl:template>
<xsl:template match="p:number">
<page>
<xsl:value-of select="." />
</page>
</xsl:template>
</xsl:stylesheet>

Related

XSL Transformation using templates in sequence

How can I transform XML using two templates in sequence?
For example, I've one XML that has string XML in it, so I need to trasform this string XML into XML and after that I need to remove invoices node.
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<MT_STATEMENT_response >
<Statement_response>
<P_INVOICE>
<invoices>
<invoice>
<number>12345</number>
<status/>
</invoice>
<invoice>
<number>67890</number>
<status/>
</invoice>
</invoices>
</P_INVOICE>
</Statement_response>
</MT_STATEMENT_response>
transformer.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="/*">
<xsl:variable name="t1">
<xsl:apply-templates select="Statement_response" />
</xsl:variable>
<xsl:apply-templates mode="pass2" select="ext:node-set($t1)/*" />
</xsl:template>
<xsl:template match="Statement_response">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="invoices" mode="pass2">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>
</xsl:stylesheet>
Expected
<invoice>
<number>12345</number>
<status/>
</invoice>
<invoice>
<number>67890</number>
<status/>
</invoice>
Using XSLT 3 and the parse-xml function (https://www.w3.org/TR/xpath-functions-31/#func-parse-xml) you could output those invoice elements escaped in the original input in the P_INVOICE element using
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:template match="/">
<xsl:copy-of select="parse-xml(//P_INVOICE)//invoice"/>
</xsl:template>
</xsl:stylesheet>

Build nodes from xpath

I have a source xml and from this source xml I like to select the nodes given by a path e.g. /shiporder/item/title and /shiporder/shipto/name from the sample source:
<?xml version="1.0" encoding="utf-16"?>
<shiporder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" orderid="orderid1">
<orderperson>orderperson1</orderperson>
<shipto>
<name>name1</name>
</shipto>
<item>
<title>foo</title>
</item>
<item>
<title>bar</title>
</item>
</shiporder>
And I like to transform those nodes to certain target tree e.g. each /shiporder/item/title from the source xml should copied to root/Customer/Name/Title in the target xml tree. So my idea was to generate for each level in the source path a template and call this template from the preceding level:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:func="http://www.functx.com">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<root>
<xsl:apply-templates select="/shiporder"/>
</root>
</xsl:template>
<xsl:template match="/shiporder">
<Customer>
<xsl:apply-templates select="item"/>
<xsl:apply-templates select="shipto"/>
</Customer>
</xsl:template>
<xsl:template match="/shiporder/item">
<Name>
<xsl:apply-templates select="title"/>
</Name>
</xsl:template>
<xsl:template match="/shiporder/shipto">
<Address>
<xsl:apply-templates select="name"/>
</Address>
</xsl:template>
<xsl:template match="/shiporder/item/title">
<Title>
<xsl:value-of select="text()" />
</Title>
</xsl:template>
<xsl:template match="/shiporder/shipto/name">
<Street>
<xsl:value-of select="text()" />
</Street>
</xsl:template>
</xsl:stylesheet>
There for I get a huge stylesheet if I have a huge list of source-paths. Has some one a more feasible idea to reach the target?

Facing Issue in XSLT Format

I am looking my xslt in below format:
<xml>
<apis>
<name>API Name</name>
<comment> Comment</comment>
<version>12</version>
</apis>
</xml>
XSLT Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xml>
<xsl:apply-templates select="//L7j:col" />
</xml>
</xsl:template>
<xsl:template match="//L7j:col">
<api>
<xsl:element name="{#name}">
<xsl:value-of select="." /></xsl:element>
</api>
</xsl:template>
</xsl:stylesheet>
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<L7j:jdbcQueryResult xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result">
<L7j:row>
<L7j:col name="name" type="java.lang.String">Policy for service #0b8bab6913cc588557b6973e94d1bfdd, WSTrustSoapService</L7j:col>
<L7j:col name="comment">
<![CDATA[NULL]]>
</L7j:col>
<L7j:col name="version" type="java.lang.Integer">18</L7j:col>
</L7j:row>
<L7j:row>
<L7j:col name="name" type="java.lang.String">Policy for service #0b8bab6913cc588557b6973e94d5893d, UUPRStub</L7j:col>
<L7j:col name="comment">
<![CDATA[NULL]]>
</L7j:col>
<L7j:col name="version" type="java.lang.Integer">16</L7j:col>
</L7j:row>
</L7j:jdbcQueryResult>
If I understand correctly, you want to do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result"
exclude-result-prefixes="L7j">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/L7j:jdbcQueryResult">
<xml>
<xsl:apply-templates/>
</xml>
</xsl:template>
<xsl:template match="L7j:row">
<apis>
<xsl:apply-templates/>
</apis>
</xsl:template>
<xsl:template match="L7j:col">
<xsl:element name="{#name}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Using XPATHs from file and adding relevant attribute

May be my XSL approach is wrong? please correct me the way to handle this situation
I want to grab XPATHs and Attrs from a mapping file, then use XPATH to match, and apply attributes to XML.
Here is my 3 inputs files:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map xpath="//title" class="title" others="moreToCome" />
<map xpath="//subtitle" class="subtitle" others="moreToCome" />
<map xpath="//p" class="p" others="moreToCome" />
</mappings>
Source.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>title text</title>
<subtitle>subtitle text</subtitle>
<p>subtitle text</p>
</root>
StyleMapping.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="fMappings" select="document('mappings.xml')" />
<xsl:variable name="xpath"><xsl:text>justToMakeItGlobal</xsl:text></xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
<!-- loop thru map in mappings.xml -->
<xsl:for-each select="$fMappings//mappings/map">
<xsl:call-template name="dyn">
<xsl:with-param name="xpath" select="#xpath" />
<xsl:with-param name="class" select="#class" />
<xsl:with-param name="others" select="#others" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template match="$xpath" mode="dyn">
<xsl:param name="xpath"/>
<xsl:param name="class"/>
<xsl:param name="others"/>
<xsl:attribute name="class"><xsl:value-of select="$class" /></xsl:attribute>
<xsl:attribute name="others"><xsl:value-of select="$others" /></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
This is what is planning to do, but i'm not getting the correct way of doing it in XSLT:
1. Read mappings.xml file
2. Loop thru each map tag
3. grab xpath and attr's
4. apply template match/select with above xpath
5. add attr's to above selected nodes
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title class="title" others="moreToCome">title text</title>
<subtitle class="subtitle" others="moreToCome">subtitle text</subtitle>
<p class="p" others="moreToCome">subtitle text</p>
</root>
I don't think you can have a template with a calculated match pattern. Let me suggest a different approach:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map elem="title" class="Title" others="moreToCome1" />
<map elem="subtitle" class="Subtitle" others="moreToCome2" />
<map elem="p" class="P" others="moreToCome3" />
</mappings>
stylesheet
<?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"/>
<xsl:variable name="mappings" select="document('mappings.xml')/mappings" />
<xsl:template match="*">
<xsl:variable name="elem" select="name()" />
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:if test="$elem = $mappings/map/#elem">
<xsl:attribute name="class">
<xsl:value-of select="$mappings/map[#elem=$elem]/#class"/>
</xsl:attribute>
<xsl:attribute name="others">
<xsl:value-of select="$mappings/map[#elem=$elem]/#others"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Testing with the following source XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title original="yes">title text</title>
<subtitle>subtitle text</subtitle>
<p>para text</p>
<nomatch attr="test">another text</nomatch>
</root>
results in:
<?xml version="1.0" encoding="utf-8"?>
<root>
<title original="yes" class="Title" others="moreToCome1">title text</title>
<subtitle class="Subtitle" others="moreToCome2">subtitle text</subtitle>
<p class="P" others="moreToCome3">para text</p>
<nomatch attr="test">another text</nomatch>
</root>

Convert string value as XML tag name

Below is my requirement. Can we do this using XSLT? I want to convert value of AttributeName as tag under policy and corresponding AttributeValue as value.
Input :
<Policy>
<Attributes>
<AttributeName>is_policy_loan</AttributeName>
<AttributeValue>Yes</AttributeValue>
</Attributes>
<Attributes>
<AttributeName>is_policy_owners</AttributeName>
<AttributeValue>Yes</AttributeValue>
</Attributes>
<Attributes>
<AttributeName>is_policy_twoyears</AttributeName>
<AttributeValue>Yes</AttributeValue>
</Attributes>
</Policy>
Output :
<Policy>
<is_policy_loan>Yes</is_policy_loan>
<is_policy_owners>Yes</is_policy_owners>
<is_policy_twoyears>Yes</is_policy_twoyears>
</Policy>
The following xsl file will do the job:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- create the <AttributeName>AttributeValue</..> nodes -->
<xsl:template match="//Attributes">
<xsl:variable name="name" select="AttributeName" />
<xsl:element name="{$name}">
<xsl:value-of select="AttributeValue" />
</xsl:element>
</xsl:template>
<!-- wrap nodes in a `Policy` node -->
<xsl:template match="/">
<Policy>
<xsl:apply-templates/>
</Policy>
</xsl:template>
</xsl:stylesheet>
The way i would do,
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8" omit-xml-declaration="yes" />
<xsl:template match="Policy">
<xsl:element name="Policy">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<xsl:template match="Attributes">
<xsl:variable name="name" select="AttributeName" />
<xsl:element name="{$name}">
<xsl:value-of select="AttributeValue" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
output will be,
<Policy>
<is_policy_loan>Yes</is_policy_loan>
<is_policy_owners>Yes</is_policy_owners>
<is_policy_twoyears>Yes</is_policy_twoyears>
</Policy>