I have the following xml-node :
<name>P & P</name>
And following XSL
<a href="example.htm" >
<xsl:attribute name="title">
<xsl:value-of select="name" disable-output-escaping="yes"></xsl:value-of>
</xsl:attribute>
<xsl:value-of select="name" disable-output-escaping="yes"></xsl:value-of>
</a>
That compiles to this HTML
<a href="example.com" title="P & P">
P & P
</a>
So the non-escaping worked for the value (the text between <A></A>) but not for the attribute.
Am I missing something here?
Thanks!
From an OP's comment:
I need this xml (P & P) in the title attribute of an HTML tag. A
better solution is most welcome!
What you need to generate can be done perfectly without D-O-E.
<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="/*">
<a href="example.htm" title="{.}">
<xsl:value-of select="."/>
</a>
</xsl:template>
</xsl:stylesheet>
When applied on the following XML document:
<t>P & P</t>
the wanted, correct result is produced:
P & P
I've been looking around and I guess this is why : (if I understand correctly) ?
Out of the specs : (http://www.w3.org/TR/xslt)
It is an error for output escaping to be disabled for a text node that
is used for something other than a text node in the result tree. Thus,
it is an error to disable output escaping for an xsl:value-of or
xsl:text element that is used to generate the string-value of a
comment, processing instruction or attribute node; it is also an error
to convert a result tree fragment to a number or a string if the
result tree fragment contains a text node for which escaping was
disabled. In both cases, an XSLT processor may signal the error; if it
does not signal the error, it must recover by ignoring the
disable-output-escaping attribute.
So disabling output for escaping an attribute is just not possible apparantly. The workaround that I see is to build a string 'by hand' as XSL - How to disable output escaping for an attribute?
Still hard to believe that I'm not missing sth. trivial here.
Related
Is it possible to call a program (e.g. a Perl script) during a XSL transformation if something match a template
<xsl:template match="row">
<p>
<xsl:value-of select="a"/>
</p>
<p>
<!--
I have elements 'b' and 'c' inside a 'row' as well.
I want to execute 'perl "value_of_b" "value_of_c"' and insert output here'
-->
</p>
</xsl:template>
Q.: Is it possible to call a program during a XSL transformation if something match a template
The answer depend on your xslt processor.
For perl have a look to XML::LibXSLT register_function.
Registers an XSLT extension function mapped to the given URI. For example:
XML::LibXSLT->register_function("urn:foo", "bar",
sub { scalar localtime });
Depends. I run something like this inside OxygenXML successfully.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:os-command="java:java.lang.Runtime"
exclude-result-prefixes="xs os-command"
version="2.0">
<xsl:template match="row">
<p>
<xsl:value-of select="a"/>
</p>
<!-- build the OS command string -->
<xsl:variable name="cmd-string" select="concat('perl ',a,' ',b)"/>
<xsl:value-of
select="os-command:exec(os-command:getRuntime(),$cmd-string)"/>
</xsl:template>
</xsl:stylesheet>
I have not tried it outside Oxygen. And also, I was not successful getting this to execute a bash script. Perl may pose a similar problem.
Here's a link to the original attempt at this.
I have a xml something likethis
<root>
<testxml>
<details name="test" url="http://www.test.com/test.aspx?val=100&val2=200" />
</testxml>
<root>
When i transform this xml using xslt to another xml
<xsl:output method="html" indent="yes" encoding="UTF-8" />
<xsl:template match="root/testxml/details">
<convert>
<xsl:attribute name="url">
<xsl:value-of select="#url"/>
</xsl:attribute>
</convert>
I get the result output as this
<convert url="http://www.test.com/test.aspx?val=100&val2=200">
instead of
<convert url="http://www.test.com/test.aspx?val=100&val2=200">
issue here is: & in url is getting changed to & amp; how can i avoid this ,i want & in url as &.(not & amp;)
i tried <xsl:value-of disable-output-escaping="yes" select="#url" />
also but of not use.
could anyone please help me in this..
I get the result output as this
instead of
issue here is: & in url is getting
changed to & amp;
There is no issue and the URL is not changed at all:
To verify this use a transformation like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:value-of select="#url"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<convert url="http://www.test.com/test.aspx?val=100&val2=200"/>
The result is:
http://www.test.com/test.aspx?val=100&val2=200
So, the URL hasn't been changed in any way and there is still only a single & character in it.
What you observe is the mandatory escaping of some special characters (typically < and &) in XML, as dictated by the XML Spec.
The escaping of some special characters never alters the content of the string that is escaped -- only how it looks like when it is a part of an XML document.
how can i avoid this ,i want & in url
as &.(not & amp;)
You cannot, and as shown above, there is nothing to avoid.
& has to be escaped as & in a URL in an XML document. You can't have an unescaped ampersand like that.
Dimitre is quite correct - an ampersand in XML must always be escaped, and it's not clear why you're trying so hard to prevent it.
I'm puzzled though - you say you're generating XML, but you use the HTML output method, but you are generating a <convert> element which isn't defined in HTML. So I fear you are a little confused by something.
I'm writing XSL and I want to make comments throughout the code that will be stripped when it's processed, like PHP, however I'm not sure how.
I'm aware of the comment object, but it prints out an HTML comment when processed. :\
<xsl:comment>comment</xsl:comment>
You use standard XML comments:
<!-- Comment -->
These are not processed by the XSLT transformer.
Just make sure that you put your <!-- comments --> AFTER the opening XML declaration (if you use one, which you really don't need):
BREAKS:
<!-- a comment -->
<?xml version="1.0"?>
WORKS:
<?xml version="1.0"?>
<!-- a comment -->
I scratched my head on this same issue for a bit while debugging someone else's XSLT... seems obvious, but easily overlooked.
Note that white space on either side of the comments can end up in the output stream, depending on your XSLT processor and its settings for handling white-space. If this is an issue for your output, make sure the comment is bracketed by xslt tags.
EG
<xsl:for-each select="someTag">
<xsl:text>"</xsl:text>
<!-- output the id -->
<xsl:value-of select="#id"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
Will output " someTagID" (the indent tab/spaces in front of the comment tag are output).
To remove, either unindent it flush with left margin, or bracket it like
<xsl:text>"</xsl:text><!-- output the id --><xsl:value-of select="#id"/>
This is the way to do it in order to create a comment node that won't be displayed in html
<xsl:comment>
<!-- Content:template -->
</xsl:comment>
Sure. Read http://www.w3.org/TR/xslt#built-in-rule and then it should be apparent why this simple stylesheet will (well, should) do what you want:
<?xml version="1.0"?>
<xsl:stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="comment()">
<xsl:copy/>
</xsl:template>
<xsl:template match="text()|#*"/>
</xsl:stylesheet>
Try :
<xsl:template match="/">
<xsl:for-each select="//comment()">
<SRC_COMMENT>
<xsl:value-of select="."/>
</SRC_COMMENT>
</xsl:for-each>
</xsl:template>
or use a <xsl:comment ...> instruction for a more literal duplication of the source document content in place of my <SRC_COMMENT> tag.
Hi I had performed a transformation which drops a tag if it is null.
I wanted to check whether my transformation is working fine, so instead of checking it manually, I wrote one more XSLT code which just checks the presence of that particular tag in the OUTPUT XML, if it is null, then the second XSLT should output a text "FOUND". (I don't actually need some XML kind of output but I am just using XSLT for searching.)
When I tried with this XSL code ::
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
</xsl:stylesheet>
It outputs all the TEXT DATA that is present in the XML file,
to avoid that, I had to write this code::
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
why did the former code outputs TEXT, why should I insist XSL to ignore all other text? is that the behavior of all XML parsers or only of my own (I am using msxml parser).
why did the former code outputs TEXT,
why should I insist XSL to ignore all
other text? is that the behavior of
all XML parsers or only of my own
You are discovering one of the most fundamental XSLT features as specified in the Specification: the built-in templates of XSLT.
From the Spec:
There is a built-in template rule to
allow recursive processing to continue
in the absence of a successful pattern
match by an explicit template rule in
the stylesheet. This template rule
applies to both element nodes and the
root node. The following shows the
equivalent of the built-in template
rule:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
There is also a built-in template rule
for each mode, which allows recursive
processing to continue in the same
mode in the absence of a successful
pattern match by an explicit template
rule in the stylesheet. This template
rule applies to both element nodes and
the root node. The following shows the
equivalent of the built-in template
rule for mode m.
<xsl:template match="*|/" mode="m">
<xsl:apply-templates mode="m"/>
</xsl:template>
There is also a built-in template rule
for text and attribute nodes that
copies text through:
<xsl:template match="text()|#*">
<xsl:value-of select="."/>
</xsl:template>
The built-in template rule for
processing instructions and comments
is to do nothing.
<xsl:template match="processing-instruction()|comment()"/>
The built-in template rule for
namespace nodes is also to do nothing.
There is no pattern that can match a
namespace node; so, the built-in
template rule is the only template
rule that is applied for namespace
nodes.
The built-in template rules are
treated as if they were imported
implicitly before the stylesheet and
so have lower import precedence than
all other template rules. Thus, the
author can override a built-in
template rule by including an explicit
template rule.
So, the reported behavior is the result of the application of the built-in templates -- the 1st and 2nd of all three of them.
It is a good XSLT design pattern to override the built-in templates with your own that will issue an error message whenever called so that the programmer immediately knows his transformation is "leaking":
For example, if there is this XML document:
<a>
<b>
<c>Don't want to see this</c>
</b>
</a>
and it is processed with 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:template match="a|b">
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the result is:
<a name="a">
<b name="b">Don't want to see this</b>
</a>
and the programmer will be greatly confused how the unwanted text appeared.
However, just adding this catch-all template helps avoid any such confusion and catch errors immediately:
<xsl:template match="*">
<xsl:message terminate="no">
WARNING: Unmatched element: <xsl:value-of select="name()"/>
</xsl:message>
<xsl:apply-templates/>
</xsl:template>
Now, besides the confusing output the programmer gets a warning that explains the problem immediately:
WARNING: Unmatched element: c
Later Addition by Michael Kay for XSLT 3.0
In XSLT 3.0, rather than adding a catch-all template rule, you can specify the fallback behaviour on an xsl:mode declaration. For example, <xsl:mode on-no-match="shallow-skip"/> causes all nodes that are not matched (including text nodes) to be skipped, while <xsl:mode on-no-match="fail"/> treats a no-match as an error, and <xsl:mode warning-on-no-match="true"/> results in a warning.
There are several built in template rules in XSL, one of which is this:
<xsl:template match="text()|#*">
<xsl:value-of select="."/>
</xsl:template>
It outputs text.
I am trying to learn XSLT. I am simply getting crazy. Variables should be declared within xsl:variables entity and instantiated with their names having the $ symbol just before them (like perl variables), right? Why on earth this code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="color" select="'red'" />
<p>$color</p>
</xsl:template>
</xsl:stylesheet>
results in the literal string: "$color" being written parsing a simple non empty xml document using the msxsl parser? Many thanks
Use <xsl:value-of select="$color"/> instead of writing $color directly to the document.
See also this question.
Also, within attributes you can get to the values directly like this:
<span style="color:{$color}" />
Why on earth this code: ...
<xsl:variable name="color"
select="'red'" />
<p>$color</p>
results in the literal string:
"$color" being written
Because this code means: output the string $color as the text node child of the <p> element.
To output the value of the $color xsl:variable use one of these:
<xsl:value-of select="$color"/>
<xsl:copy-of select="$color"/>
A good rule of thumb for xslt: if it's not in an <xsl:foo> tag, it's not code. It's output.