XSLT template matching issue - html

I am confused about XSLT apply-template statement. For example, here in w3school.
http://www.w3schools.com/xsl/xsl_apply_templates.asp
It is mentioned -- "The <xsl:apply-templates> element applies a template to the current element or to the current element's child nodes.", my question is whether it is applied to current element or to child nodes or both? The word "or" makes me confused about its definite behavior.
EDIT 1: here is the code snippet I am confused, I am confused when xslt processor finds <xsl:apply-templates/>, it will match all child nodes of "current node". Here "current node" means catalog or another virtual abstract XML root node? and why?
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
thanks in advance,
George

The w3schools documentation is not all it's cracked up to be, and I agree, it's quite misleading in this case.
The spec says:
In the absence of a select attribute, the xsl:apply-templates instruction processes all of the children of the current node, including text nodes.
"Children" in XML always means direct children. Children's children etc are called "descendents".
The "current node" means exactly that. It's determined by the context in which the apply-templates instruction appears.
So initially you might have:
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
Here the current node is the document node, and the apply-templates will act on the children to that, i.e. the top level element of the XML.
In this sample:
<xsl:template match="cd">
<xsl:apply-templates />
</xsl:template>
the current node will be a node somewhere in the XML called "cd" and the apply-templates will act on the direct children of that.
Note that this need not apply to every element called "cd", nor in fact need it apply to any element called "cd", that will depend on how the other templates in the XSLT process the input XML. All it says is that whenever that template is matched, the current node will be a "cd" node.

In case you want to apply templates to the current element, use:
<xsl:apply-templates select="."/>

<xsl:apply-templates/> matches all the child nodes of the current node.
In the e.g.
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection</h2>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
the current node (/) is catalog (root node). Hence will apply the templates that match all the child nodes (cd, title, artist, country, ...) if they exist.
Best way for you to understand would be to change the xslt in the example and observe the various outputs you get.
One way would be remove all the other 3 templates (cd, artist & title) and run the xslt again.

my question is whether it is applied
to current element or to child nodes
or both?
That depends on whether there is a select attribute in the apply-templates element.
If it's just <xsl:apply-templates/> then the template(s) that match the current element's child nodes will get applied. In the case from w3Schools this means that cd, title and artist all get applied.
However if you was to do something like <xsl:apply-templates select="/catalog/cd/artist"/> instead then only that element would get the template applied to it.

Related

Generation of XSLT From XML

I have an XML File with very large content.
I had an xsd file for that xml file.
For example : Please visit this link
XML CONTENT : http://formalmind.com/sites/default/files/blog/manual-testing.reqif
XSD For that XML : https://www.omg.org/spec/ReqIF/20110401/reqif.xsd
I need to display that xml in HTML page. For that i need XSLT.
Is it possible to generate XSLT for the given XML Automatically ? or is there is any other way to display in html Page?
Html Result Should be like
HTML_OUTPUT_IMAGE
Thanks
Sivabalakrishnan
Yes, this is possible, but it's not clear that it's a useful approach. What information in the schema do you intend to use to generate your XSLT? You need to give some examples of constructs that you find in the schema, and the resulting XSLT rules that you want to generate.
There are two other options you should consider:
(a) writing a completely generic XSLT stylesheet, that handles any document regardless of its schema. For example, it could contain rules like this:
<xsl:template match="*[count(*)>1 and count(*)=count(distinct-values(*/node-name())]">
<table>
<xsl:for-each select="*">
<tr>
<td><xsl:value-of select="name()"/></td>
<td><xsl:apply-templates/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
This rule says that if you encounter an element with 2 or more element children, and all the children have distinct names, then display a table containing the element names in one column and their values in another.
(b) writing a generic schema-aware (XSLT 2.0) stylesheet that handles any input document, but uses schema information from the type annotations on validated nodes to decide what output to generate. For example you might have a rule like this:
<xsl:template match="#*[data(.) instance of xs:decimal]">
<xsl:value-of select="format-number(., '#,00', 'continental')"/>
</xsl:template>
which causes all decimal attribute values to be displayed using a format such as 3,14.

How to change the root of <xsl:for-each > dynamically in xslt file

I want to change the root of <xsl:for-each> dynamically. Actually I used nested loop. Based on the outer loop I want to change the root of inner loop.
For that I write the following code but I am not able to do it.
outer loop start
then
variable that hold root
<xsl:variable name="cdtitle">
<xsl:value-of select="/root/Data/AppNameEncrpt"/>
</xsl:variable>
inner loop
<xsl:for-each select="msxsl:node-set($cdtitle)">
..
</xsl:for-each>
If I pass the static value of msxsl:node-set($cdtitle) then it work but when I pass it as a varible in root it not work
How can achieve the same. Can anyone help me.
In XSLT (as in any functional language), variables are immutable. However, inside a "loop" (which technically is not a loop) you can set the variable to anything that is in the context of that loop. Since you didn't show any input XML, I am guessing to what you want to achieve, but there's always a (simple) way.
Suppose you have this variable:
<xsl:variable name="cdtitles" select="/data/cds/title" />
It will hold all cd titles. Now I can do:
<xsl:for-each select="$cdtitles">
<xsl:variable name="cdtitle" select="." />
<!-- do something with the title, var changes with each title -->
</xsl:for-each>
Have a look at XSLT: Getting started, it will help you understand these and other principles of the language.

Styling inline XML tags with XSLT

This is a similar question to Style inline text along with nested tags with XSLT, but I can't comment to get clarification, so I will elaborate my specific scenario here. I basically have an XML document with the following structure:
<book>
<chapter>
<para>This is some text about <place>New York</place></para>
</chapter>
</book>
I am using XSLT to output XHTML from my XML file, and I want to be able to put span tags or something around the content in the place tag in the example above. The purpose is so that I can style these segments of text with CSS. Following the example I referenced above, I added this:
<xsl:template match="book/chapter/para/place">
<span class="place">
<xsl:apply-templates/>
</span>
</xsl:template>
When I load the XML document in the browser I get the error: "Error loading stylesheet: Parsing an XSLT stylesheet failed." (the stylesheet was loading properly before I added this part)
I'm assuming I lack some basic understanding of how xsl:apply-templates should be used. I would appreciate it if someone could point me in the direction of figuring this out.
Thanks!
The match:
<xsl:template match="book/chapter/para/">
applies templates to all children of the place element, rather than place itself.
Use select within apply-templates instead:
<xsl:template match="/">
<xsl:apply-templates select="book/chapter/para/place"/>
</xsl:template>
In the absence of a select attribute, the xsl:apply-templates instruction processes all of the children of the current node, including text nodes.
A select attribute can be used to process nodes selected by an expression instead of processing all children. The value of the select attribute is an expression. The expression must evaluate to a node-set.
References
XSLT 1.0 Specification

How to find a specific substring of text anywhere in my XML and select this text using XSLT

I need to find and select a specific substring of text using XPATH/XSLT (if possible) - in this case the entity code for a non-breaking space "&#xa0" then highlight this in my HTML output using some CSS.
I am not searching within a specific element node, I need to search from the root node of my document and find this entity wherever it appears. I do not know where this will appear in my XML, I just know the entity code I am looking for.
Here is a section of my document where "&#xa0" appears within the text:
<row rowsep="1">
<entry align="left" colname="col1" colsep="1">
<para>N/A = not applicable/not generally used, A = applicable </para>
</entry>
</row>
I'm using XSLT 2.0.
Using XSLT 2.0 you could use analyze-string on all text() nodes e.g.
<xsl:template match="text()">
<xsl:analyze-string select="." regex=" ">
<xsl:matching-substring>
<span class="highlight"><xsl:value-of select="."/></span>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
You would then need to set up other templates to transform the remaining elements to HTML where you include the CSS or link to some CSS document defining something like
span.highlight { color: red; }
The span or similar wrapper element is necessary in my view as CSS does not allow you to style a single letter or word within a text node.

XSL Processing Order

I've had trouble finding an exact, and simple, answer to this question on SO or elsewhere:
In XSL files, how can you tell which template will be processed first, second, etc? I read that it was ordered by how specific the XPath was. Additionally, is there a difference in XSL 1.0 vs. 2.0?
Finally, here is a flawed XSL file I am toying with. Currently the output is just the title "Table of Contents". I'll attach the XML here as well.
<xsl:template match="/">
<h1>
<xsl:text>Table of Contents</xsl:text>
</h1>
</xsl:template>
<xsl:template match="heading1">
<h2>
<xsl:value-of select="."/>
</h2>
</xsl:template>
<p>
<xsl:text>This document contains </xsl:text>
<xsl:value-of select="count(/article/body/heading1)"/>
<xsl:text> chapters. </xsl:text>
</p>
and the XML:
<article>
<title>
Creating output
</title>
<body>
<heading1>Generating text</heading1>
<heading1>Numbering things</heading1>
<heading1>Formatting numbers</heading1>
<heading1>Copying nodes from the input document to the output</heading1>
<heading1>Handling whitespace</heading1>
</body>
Any explanation as to why all the content isn't being displayed? Thank you for your help!
Here's what's happening:
The XSLT processor reads the root element of your XML
Then it looks in the stylesheet to see what matches. It finds your first template
It executes the first template.
The first template says to output the text, and then does nothing else, so the XSLT processor moves on to the next input element.... but you've processed the entire root node, so there are no more input nodes at the same level. It's done.
What you need to do is put an <xsl:apply-templates/> inside the first template. When this is encountered by the processor, it starts over but this time the context is the list of second-level nodes inside the root. It will look at each XML node in turn, find the best matching template in your stylesheet, and execute it.
This is a key concept -- The template is NOT in control, and is not procedural.