Can we encode URL in .xsl file? - xslt

Can we encode URL in .xsl file? If yes, then how we can do that?
I have used below code:
Prompt type="label" pointer="abc.asp?mynumber={my-number}&myname={my-name}"
It works fine for other name, but if name contains &, then it is breaking.
Could someone help me to solve it?

In my experience browsers may treat & and & the same you're likely to end up with a link that doesn't work correctly anyway.
If you're not certain of what the my-name node might contain then it might be better to create a variable from it first. Then you can make sure that any ampersands are removed first.
Actually, the first thing you should try is to agree that the my-name node never contains an ampersand in the first place. But I know that sort of request is often ignored so there is a solution.
If you use a variable, you can include a find and replace to remove/replace the &. There isn't a function for this in xslt 1 but you can use the translate function instead
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/Test">
<xsl:variable name="safe-name" select="translate(my-name, '&', '|')"/>
MyName - <xsl:value-of select="$safe-name"/>
</xsl:template>
</xsl:stylesheet>
I've given this a quick test and it works with several & in the node (you can never be too careful). Hope that helps

Related

Dynamic Namespace for Input XML

I have searched many posts on dynamically setting namespaces but they all seem to refer to setting the namespace of the output XML.
The issue I have is that the namespace (defined at root and same for all child nodes) of the input XML differs, and the same stylesheet needs to be able to handle both inputs.
For example, one input XML is:
<root xmlns="aaa">
<body>xxx</body>
</root>
And the other input XML is:
<root xmlns="bbb">
<body>yyy</body>
</root>
In the stylesheet, my XPath obviously needs to use the defined namespace, which is declared with a prefix, i.e.:
xmlns:one="aaa"
But as soon as the second input XML is being transformed, it of course fails to work.
I could define another namespace, e.g.
xmlns:two="bbb"
But the only way to use that namespace at the right time is to duplicate all the XSLT code and have the other namespace as the prefix for all the XPath (even then I would still need to identify which set of XPath to use which may be fun..)
My stylesheet currently uses the following XPath:
%lt;SOMETHING>
<xsl:value-of select="one:body" />
%lt;/SOMETHING>
As you can see it uses the "one" namespace prefix. Is there any way to just get the value of either "body" tag, regardless of namespace? As mentioned in a comment below, although I appreciate they are different elements based on namespace, I know that the information in each will be the same so I can treat them as such.
I have seen posts on using xsl:element with a namespace attribute but from what I can tell that just defines the namespace of the output XML, not the input. (To make matters worse, what I am outputting is actually escaped XML, e.g. %lt;SOMETHING> so I couldn't use xsl:element anyway).
My current solution (since posting this) is to have two extra stylesheets included in the main stylesheet. Each one is specific to either namespace "one" or namespace "two", each line of XPath uses the relevant namespace prefix.
I am hoping there is a way to avoid having two separate stylesheets that are almost identical except for the namespace prefix.
Thanks in advance.
If I get you right, you want to process the XML ignoring the elements' namespaces. Actually, the sense of namespaces is to distinct between elements from different contexts. So from an XML point of view, <one:body> has absolutely nothing to do with <two:body>, besides the fact that they happen to have the same name.
If you want to do it anyway, instead of:
<xsl:template match="one:body">
<xsl:template match="two:body">
you should match on the elements' local name only:
<xsl:template match="*[local-name()='body']">
In order to give a little more background: If you say
<xsl:template match="one:body">
then this is only a short notation of
<xsl:template match="*[namespace-uri()='aaa'][local-name()='body']">
(i.e. "match any element whose namespace is 'aaa' and whose name is 'body'")
Thus, ignoring the namespace by leaving away the
[namespace-uri()='aaa']
makes it
<xsl:template match="*[local-name()='body']">
Instead, you had better say
<xsl:template match="*[namespace-uri()='aaa' or namespace-uri()='bbb'][local-name()='body']">
or
<xsl:template match="*[namespace-uri()='aaa' or namespace-uri()='bbb' or namespace-uri()='ccc'][local-name()='body']">
and so on. If, as dret states, you know all possible namespaces in advance.
I would suggest you define both namespaces, then use paths such as:
one:body | two:body
to address the elements in the source XML.
For example, instead of:
<xsl:value-of select="one:body" />
use:
<xsl:value-of select="one:body | two:body" />
As I already wrote! Instead of
<xsl:value-of select="one:body" />
you can write
<xsl:value-of select="*[local-name()='body']" />
Or, if you have XPath 2.0, then
<xsl:value-of select="*:body" />

better way to convert the uppercase to lowercase

I am developing an xsl in which I am getting an id and I am converting it in lower case as shown below
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:if test="translate( ./Id ,
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz')
= 'good'
please let me know is there any other better way also to achieve the same amy function which xslt 1.0 supports.
Not in pure XSLT 1.0, no, its string manipulation facilities are rather limited. Depending on the processor you might be able to call an extension function (e.g. Xalan lets you call into Java static methods from XPath) but you're probably better off sticking to the native translate approach. If you're doing lots of these conversions you can make it more succinct by declaring a couple of global variables
<xsl:variable name="uc" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:variable name="lc" select="'abcdefghijklmnopqrstuvwxyz'" />
which would let you say translate(Id, $uc, $lc) instead of spelling the alphabet out in full every time.

Can XSLT be used to form a plain txt file, not just html?

Lately I have become a huge fan of XSL, XPath and XML, but I've only used it to format outputted html documents, with a head and body sections.
I was wondering if its possible to use good of XSLT to format other types of documents, like plain txt?
Yes of course - just use
<xsl:output method="text" indent="yes"/>
instead of
<xsl:output method="html" indent="yes"/>
Marc
UPDATE: whitespace and formatting text exactly as needed are always a bit tricky in XSLT. Check out some of those references:
XML.com: controlling whitespace
XSL Primer (part 5 has a note about whitespace)

XSLT encoding problem, questionmarks in result

I'm trying to run an XSLT transformation, but characters like ëöï are replaced by a literal '?' in the output (I checked with an hex editor). The source file has the correct characters, and the stylesheet has:
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
What else am I missing?
I'm using saxon as the transformer, if that matters.
The problem is most likely in the way you call the transformer. My guess is it will work fine if you call it using java -jar saxon.jar ...
In general, when you use XML tools which take InputStream/OutputStream, then the tools will make sure that the encoding is correct.
When you use a mixture of Streams and Writers, you will have to make sure that the encoding when going from one to the other matches what you told the XSLT processor to produce. Always set encodings explicitly. There may be defaults, but when it comes to encodings, they are wrong more often than not.

Automatically converting escaped characters to string literals

I am working on an XSLT transformation to re-arrange XML blocks to validate NewsML files. Some of these files contains encoded characters (such as & " etc...). The problem is the XSLT transformation is converting these characters to their literal string (ie "and", "'"). This is causing problems. I do not want this to happen.
I have experimented with various techniques (uses of <xsl:text>, <xsl:value-of> and the disable-output-escaping flag, <xsl:output method='xml|html|xhtml|text'>) to no avail. These methods either, convert the characters, or simply leave them out.
eg, a string which starts with "stars on PM&apos;s cards" can end up as
stars on PM's cards
stars on PMs cards
I am using the Saxonica (http://www.saxonica.com/) processing app.
The basic XSLT I am using is provided below. (There are other things but the problem exists even with this simplest stylesheet)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Any ideas on how to prevent this conversion would be most appreciated. The requirement is to keep the original text as it appears.
I think you need to do both the disable-output-escaping="yes" and set the document to HTML at the same time.
FROM W3C (emphasis mine):
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.
The disable-output-escaping attribute may be used with the html output method as well as with the xml output method. The text output method ignores the disable-output-escaping attribute, since it does not perform any output escaping.
An XSLT processor will only be able to disable output escaping if it controls how the result tree is output. This may not always be the case. For example, the result tree may be used as the source tree for another XSLT transformation instead of being output. An XSLT processor is not required to support disabling output escaping. If an xsl:value-of or xsl:text specifies that output escaping should be disabled and the XSLT processor does not support this, the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.
If output escaping is disabled for a character that is not representable in the encoding that the XSLT processor is using for output, then the XSLT processor may signal an error; if it does not signal an error, it must recover by not disabling output escaping.
Since disabling output escaping may not work with all XSLT processors and can result in XML that is not well-formed, it should be used only when there is no alternative.
These are entities. Usually they get mapped to a unicode representation of that entity. The final stream will just contain the characters. If you output the stream it's up to the serializer to escape the characters depending on the output type (which is what you can disable with disable-output-escaping). So a proper serializer should turn this
<xsl:output method="html" encoding="UTF-8"/>
<xsl:text>some test</xsl:text>
into
some test
See section 5 on this article.
So I would check that with your XSLT processor first.