issues outputting xml value due to namespace - xslt

xml code
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="MyXmlTransformer.xsl"?>
<JMO_obsList xmlns="urn:metoc:jmcbl:jmibl">
<urn:JMO_obs urn:observationTime ="20110118150000" urn:platformID="A001" urn:reporTypeCode="AUTO"
urn:HorizontalDatum="WGE" urn:verticalDatum="MSL" urn:stationMode="0"
urn:networkType="PTDS" xmlns:urn="urn:metoc:jmcbl:jmcbl:jmibl">
<JMO_surfaceObs urn:stationPressure ="998.308" urn:airTemperature="28.56"
urn:windDirection="320" urn:windSpeed="3.807"/>
<urn:JMO_precipitation urn:PrecipAmount="6.858" urn:observationPeriod="60"
urn:precipType="L" urn:occcurenceID="1"/>
</urn:JMO_obs>
</JMO_obsList>
xslt code
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="/">
<html>
<body>
<b>METAR</b>
<br/>
<span style="color:blue">
<xsl:value-of select="JMO_obsList/JMO_surfaceObs/windSpeed"/>
</span><br/>
<span style="color:blue">
<xsl:value-of select="JMO_obsList/JMO_surfaceObs/stationPressure"/>
</span><br/>
<span style="color:blue">
<xsl:value-of select="JMO_obsList/JMO_Obs/observationTime"/>
</span><br/>
<span style="color:blue">
<xsl:value-of select="JMO_obsList/JMO_precipitation/PrecipAmount"/>
</span><br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

In your stylesheet you will have to define prefixes for the namespace "urn:metoc:jmcbl:jmibl" and urn:metoc:jmcbl:jmcbl:jmibl and use them to explicitly qualify the references to JMO_obsList and other elements. Furthermore, the references to windSpeed and other XML attributes need to be referenced with the attribute: axis
An example of a complete value-of declaration:
<span style="color:blue">
<xsl:value-of xmlns:ns1="urn:metoc:jmcbl:jmibl"
xmlns:ns2="urn:metoc:jmcbl:jmcbl:jmibl"
select="ns1:JMO_obsList/ns2:JMO_obs/ns1:JMO_surfaceObs/#ns2:stationPressure"/>
</span>

Related

XSLT: Using xsl:key in nested XML structures

EXAMPLE
Here is an example from MSDN. It show how to transform a XML file into HTML using xsl:key.
Example XML (input)
<books>
<book title="XML Today" author="David Perry" release="2016"/>
<book title="XML and Microsoft" author="David Perry" release="2015"/>
<book title="XML Productivity" author="Jim Kim" release="2015"/>
</books>
Example XSL (input)
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
Example HTML (output)
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
MY PROBLEM
I would like to produce the same HTML output but using a different XML input. How should the corresponding XSL file look like?
My XML (input)
<books>
<book>
<a n="author"><s>David Perry</s></a>
<a n="title"><s>XML Today</s></a>
<a n="release"><i>2016</i></a>
</book>
<book>
<a n="author"><s>David Perry</s></a>
<a n="title"><s>XML and Microsoft</s></a>
<a n="release"><i>2015</i></a>
</book>
<book>
<a n="author"><s>Jim Kim</s></a>
<a n="title"><s>XML Productivity</s></a>
<a n="release"><i>2015</i></a>
</book>
</books>
My XSL (input)
???
My HTML (output)
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
In the first example, your key matched book elements by their author attribute, but in the new XML, you want to match them by the a element where the n attribute is "author", so the key looks like this.
<xsl:key name="title-search" match="book" use="a[#n='author']/s"/>
Then, to get the title for the a matched book you would do this...
<xsl:value-of select="a[#n='title']/s"/>
Therefore your XSLT would look like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:key name="title-search" match="book" use="a[#n='author']/s"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="a[#n='title']/s"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
You could actually drop the /s in the expressions here, if the s element was only ever going to be the only element under each a element.
This would work too:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:key name="title-search" match="book" use="a[#n='author']"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="a[#n='title']"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
This is basic XSLT transformation, you can do something like this:
<xsl:template match="book">
<div>
Author: <xsl:value-of select="a[#n='author']/s" />
title: <xsl:value-of select="a[#n='title']/s" >
release: <xsl:value-of select="a[#n='release']/s" >
</div>
</xsl:template>

XSLT, I'm studying with my own XSLT example, but it doesn't work as I expected

First, my code is..
<?xml version="1.0" encoding="UTF-8"?>
<mpml>
<problem>
<context>
<p>두 다항식 $A=x^2 - xy + 2y^2$, $B=3x^2 + 2xy - y^2$에 대하여 $A-B$를 계산한 식이 $ax^2 +bxy + cy^2$일 때, 상수 $a+b+c$의 값은?</p>
</context>
<answerlist>
<i>-4</i>
<i>-2</i>
<i>0</i>
<i>2</i>
<i>4</i>
</answerlist>
</problem>
<problem>
<context>
<p>연립방정식 $\begin{cases} x+y+z=30 \\ 2x+3y+4z=93 \\ y=z+3 \end{cases}$의 해를 $x=a$, $y=b$, $z=c$라 할 때, $a-2b+3c$의 값은? (단, $a$, $b$, $c$는 실수.)</p>
</context>
<answerlist>
<i>7</i>
<i>9</i>
<i>11</i>
<i>13</i>
<i>15</i>
</answerlist>
</problem>
</mpml>
and it's xsl code is..
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h2> Testing.. </h2>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="problem">
<div class="problem">
<xsl:apply-templates select="context"/>
<xsl:apply-templates select="answerlist"/>
</div>
</xsl:template>
<xsl:template match="context">
<div class="context">
</div>
</xsl:template>
<xsl:template match="answerlist">
<div class="answerlist">
test answerlist
</div>
</xsl:template>
</xsl:transform>
In XSLT Tryit editor (thanks to w3school), above XSLT work as I expected. However when I tried this in my server, there is an 'extra content at the end of the document.' error and nothings shown except very first template.
I think the problem is that your XSLT does not produce well-formed XML in output: in the template <xsl:template match="/">, you should wrap content within a single root tag.
E.g.:
<xsl:template match="/">
<body>
<h2> Testing.. </h2>
<xsl:apply-templates/>
</body>
</xsl:template>

Template declared to match element, but never triggered

I've the following XML.
<?xml version="1.0" encoding="UTF-8"?>
<docs>
<biblos>
<texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">
<parrafo>
<en-origen estilo-fuente="cursiva">This is cursive text.</en-origen>
</parrafo>
</texto>
</biblos>
</docs>
and the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<section class="chapter">
<xsl:apply-templates select="docs"/>
</section>
</body>
</html>
</xsl:template>
<xsl:template match="docs">
<div class="chapter">
<xsl:text>Docs Block</xsl:text>
<xsl:apply-templates select="biblos"/>
</div>
</xsl:template>
<xsl:template match="biblos">
<xsl:text>biblos block</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="texto">
<xsl:text>Text To Block</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="parrafo">
<div class="para">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="parrafo">
<span class="format-smallcaps">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="en-origen">
<xsl:variable name="fontStyle">
<xsl:choose>
<xsl:when test="./#estilo-fuente">
<xsl:value-of select="concat('font-style-',#estilo-fuente)"/>
</xsl:when>
<xsl:when test="./#format">
<xsl:value-of select="concat('format-',#format)"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:template>
</xsl:transform>
when i run this, I'm getting the below output.
<!DOCTYPE html
PUBLIC "XSLT-compat">
<html>
<body>
<section class="chapter">
<div class="chapter">Docs Blockbiblos block
This is cursive text.
</div>
</section>
</body>
</html>
Here the problem is, though I've declared texto and child nodes of it in my XSLT, it is not getting called, but the text is directly getting printed.
Please let me know where I'm going wrong and how I can fix it.
Good question (thanks for providing a complete, working example!). Often, if elements are not matched, the cause lies in missing namespaces:
You have the following in your input XML:
<texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">
In other words, the texto element is in a namespace. In your XSLT you have the following:
<xsl:template match="texto">
Since no namespace is declared for XPath (xpath-default-namespace on the containing xsl:template or xsl:stylesheet), this will operate on elements texto in no namespace, meaning, as written, it will not match texto from your source.
You can solve this by:
<xsl:transform
xmlns:tto="http://www.aranzadi.es/namespace/contenido/biblos/texto"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
and:
<xsl:template match="tto:texto">
Now your template will be matched.
Remember that element names can be in a namespace if the namespace is declared on that element, but the attributes, unless prefixes, are in no nammespace, so this solution is only required (given your example input) on matching or selecting elements.
Also, it is important to realize that prefixes do not matter, they do not need to match the prefix (or absence thereof) from the source document. What matters, is that the namespace bound to the prefix matches.
If there are child elements, in this case parrafo and en-origen, these inherit the namespace given on their parent element. So if you want to match these elements as well, you should adjust their names to tto:paraffo and tto:en-origin in patterns and XPath expressions.

insert into cdata text from xml node usning xslt

My scenario is that we have to check for a div tag in the cdata of a body element. If div is present we have to insert the the text from node2 into the div tag.
This is my input xml:
<?xml version="1.0" encoding="utf-8"?>
<root>
<node1>abc</node1>
<node2> needs to replace inside cdata div</node2>
<body> <![CDATA[
<p>some text some textabcabcabcabc</p>
<div class="marginBottom_4px">
</div>
<p>some text some textabcabc</P>
]]>
</body>
</root>
The out put xml would be:
<?xml version="1.0" encoding="utf-8"?>
<div class="marginBottom_10px">
abc
</div>
<div class="marginBottom_5px">
<p>some text some textabcabcabcabc</p>
<div class="marginBottom_4px">
needs to replace inside cdata div
</div>
<p>some text some textabcabc</P>
</div>
My transform is:
<?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"/>
<xsl:template match="/">
<xsl:value-of disable-output-escaping="yes" select ="$firstnode"/>
<xsl:text disable-output-escaping="yes"><![CDATA[ <div class="marginBottom_10px">
]]>
</xsl:text>
<xsl:value-of disable-output-escaping ="yes" select="root/body"/>
<xsl:text disable-output-escaping="yes"><![CDATA[
</div>
]]>
</xsl:text>
</xsl:template>
<xsl:variable name="firstnode">
<xsl:text disable-output-escaping="yes"><![CDATA[
<div class="marginBottom_10px">
]]>
</xsl:text>
<xsl:value-of disable-output-escaping ="yes" select="root/node1"/>
<xsl:text disable-output-escaping="yes"><![CDATA[
</div>
]]>
</xsl:text>
</xsl:variable>
</xsl:stylesheet>
I am able to produce the out put. but my xml is very complex like below:
<?xml version="1.0" encoding="utf-8" ?>
<ComplexXML>
<environment>
couple of nodes..
</environment>
<document>
nodes
</document>
<element cd="dsjdhfjk" input="abc.xml" mode="" >
<cd position="1">
<attributes>
<type>dummy text</type>
<title>dummy text</title>
</attributes>
<content>
<node2>
<![CDATA[
needs to replace inside cdata div
]]>
</node2>
<body>
<![CDATA[
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book </p>
<div class="marginBottom_4px">
</div>
<p>Lorem Ipsum is simply dummy text of her including versions of Lorem Ipsum. </p>
]]>
</body>
<abt >
<![CDATA[
text from abt node
]]>
</abt>
</content>
</cd>
</element>
</ComplexXML>
In the above xml I have to check for the abt node.If data is there in abt node the out should be like below:
<?xml version="1.0" encoding="UTF-8"?>
<div>
text from abt node
<div class="marginBottom_5px">
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled it to make a type
specimen book </p>
**<div class="marginBottom_4px">
</div>** I need to remove this div tag and place the node2 content here.
<p>Lorem Ipsum is simply dummy text of her including versions of Lorem Ipsum. </p>
</div>
</div>
Sorry to bother you..I am very new to xslt..I am in learning stage only..Can you please guide me..
The following XSLT 1.0 stylesheet produces what I believe the desired output is, based upon the example output and comments. It relies upon the text in the CDATA of the input document being well-formed, and leverages disable-output-escaping:
<?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"/>
<xsl:template match="node1">
<div class="marginBottom_10px">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="node2" />
<xsl:template match="body">
<div class="marginBottom_5px">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="body/text()[contains(.,'<div') and contains(.,'</div>')]">
<xsl:value-of
disable-output-escaping="yes"
select="substring-before(.,'</div')" />
<xsl:value-of select="../../node2"/>
<xsl:value-of
disable-output-escaping="yes"
select="substring-after(.,substring-before(.,'</div'))" />
</xsl:template>
</xsl:stylesheet>
When applied against the example input, produces:
<?xml version="1.0" encoding="UTF-8"?>
<div class="marginBottom_10px">abc</div>
<div class="marginBottom_5px">
<p>some text some textabcabcabcabc</p>
<div class="marginBottom_4px">
needs to replace inside cdata div</div>
<p>some text some textabcabc</P>
</div>
Note: the output is not well-formed. There is no document element. You would likely want to create a template for the <root> to create a <div> or other containing element.
This version handles the other input format and generates what I believe the desired output is:
<?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"/>
<!--rely on built-in templates,
which apply-templates to child nodes of elements
and get value-of for text() -->
<xsl:template match="content">
<xsl:choose>
<!-- if <abt> has a value, do the following -->
<xsl:when test="normalize-space(abt)">
<div>
<!-- apply templates to <abt>,
built-in template will copy text to output-->
<xsl:apply-templates select="abt"/>
<!-- apply templates to <body>, template defined below will handle it -->
<xsl:apply-templates select="body"/>
</div>
</xsl:when>
<xsl:otherwise>
<!--process child nodes -->
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node1">
<div class="marginBottom_10px">
<xsl:apply-templates/>
</div>
</xsl:template>
<!--empty template ensures that no content produced when templates applied to <node2>-->
<xsl:template match="node2" />
<xsl:template match="body">
<div class="marginBottom_5px">
<xsl:apply-templates/>
</div>
</xsl:template>
<!--Template for handling body/text() when <abt> does not have a value-->
<xsl:template match="*[not(normalize-space(abt))]/body/text()[contains(.,'<div') and contains(.,'</div>')]">
<!--get the value of content preceding "</div"-->
<xsl:value-of
disable-output-escaping="yes"
select="substring-before(.,'</div')" />
<!--get the value of <node2> -->
<xsl:value-of select="../../node2"/>
<!--get the value of content starting at "</div" -->
<xsl:value-of
disable-output-escaping="yes"
select="substring-after(.,substring-before(.,'</div'))" />
</xsl:template>
<!--Template for handling body/text() when <abt> does have a value -->
<xsl:template match="*[normalize-space(abt)]/body/text()[contains(.,'<div') and contains(.,'</div>')]">
<!--get the value preceding "<div" -->
<xsl:value-of
disable-output-escaping="yes"
select="substring-before(.,'>div')" />
<xsl:value-of select="../../node2"/>
<!--get the value following "</div>" -->
<xsl:value-of
disable-output-escaping="yes"
select="substring-after(.,'</div>')" />
</xsl:template>
</xsl:stylesheet>

How to Import stylesheets in xslt conditionally?

Is there any way to import stylesheets after checking some conditions?
Like,if the value of variable $a="1" then import 1.xsl or else import 2.xsl.
Hi All, Is there any way to import
stylesheets after checking some
conditions?
Like,if the value of variable $a="1"
then import 1.xsl or else import
2.xsl.
No, the <xsl:import> directive is only compile-time.
In XSLT 2.0 one can use the use-when attribute for a limited conditional compilation.
For example:
<xsl:import href="module-A.xsl"
use-when="system-property('xsl:vendor')='vendor-A'"/>
The limitations of the use-when attribute are that there is no dynamic context when the attribute is evaluated -- in particular that means that there are no in-scope variables defined.
A non-XSLT solution is to dynamically change the href attribute of the <xsl:import> declaration before the transformation is invoked:
Parse the xsl stylesheet as an XML file
Evaluate the condition that determines which stylesheet should be imported.
Set the value of the href attribute of the <xsl:import> declaration to the URI of the dynamically determined stylesheet-to-be-imported.
Invoke the transformation with the in-memory xsl stylesheet that was just modified.
I know this post is old, but I want to share my opinion.
Each display could use one template instead of two. The value display will be change with a VB application.
breakfast_menu.xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="conditionDisplay.xsl" ?>
<data>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
<display>1</display>
</data>
In this file, I imported my displays and with a condition I tell the template what I need.
conditionDisplay.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:import href="display1.xsl"/>
<xsl:import href="display2.xsl"/>
<xsl:template match="/">
<xsl:variable name="display"><xsl:value-of select= "data/display"/></xsl:variable>
<xsl:choose>
<xsl:when test="$display='1'">
<xsl:call-template name="display1" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="display2 />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
display1.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="display1">
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select="data/breakfast_menu/food">
<div style="background-color:teal;color:white;padding:4px">
<span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
<xsl:value-of select="price"/>
</div>
<div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
<p>
<xsl:value-of select="description"/>
<span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
</p>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
display2.xsl:
<?xml version="1.0" encoding="UTF-8"?>futur
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="display2">
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#222222">
<xsl:for-each select="data/breakfast_menu/food">
<div style="background-color:teal;color:white;padding:4px">
<span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
<xsl:value-of select="price"/>
</div>
<div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
<p>
<xsl:value-of select="description"/>
<span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
</p>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I genuinely apologize for my terrible English. It will be better to the next post and I hope will help someone as I think it's not the best solution.