better way to convert the uppercase to lowercase - xslt

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.

Related

Can we encode URL in .xsl file?

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

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" />

XSLT: Test if node exists regardless if it's a child or grandchild of current node

I'm working on some xslt transformations and I've just found out that there might or might not be an extra node between my current parent and it's clildren, depending on external factors. So now I have to change my xslt code in order to deal with both of these scenarios:
scenario 1:
<parent>
<child/>
<child/>
<parent>
scenario 2:
<parent>
<nuisance>
<child/>
<child/>
</nuisance>
<parent>
I have situations in which I test="parent/child" or otherwise use this format of accessing a parent/node.
I need something like test="parent/magic(* or none)/child"
They only way I know of that can solve this problem is to use:
<xsl:choose>
<xsl:when test="parent/child">
<!-- select="parent/child"-->
</xsl:when>
<xsl:otherwise>
<!-- select="parent/*/child"-->
</xsl:otherwise>
</xsl:choose>
But this will triple my code in size and will be a lot of manual labour...
Help much appreciated!
Why not simply select the union of the two?
<xsl:apply-templates select="parent/child|parent/*/child"/>
This will select the correct nodes in both cases.
I have situations in which I
test="parent/child" or otherwise use
this format of accessing a
parent/node.
I need something like
test="parent/magic(* or none)/child"
This expression may be faster:
parent/child or parent/*/child
than the expression:
parent/child|parent/*/child
Almost any XPath engine will immediately stop the evaluation at the first occurence of parent/child or at the first occurence of parent/someElement/child
On the other side, the second expression selects the union of all parent/child and parent/*/child elements and there may be many such elements.
Even worse is:
<xsl:apply-templates select="parent/child|parent/*/child"/>
A test, as the original question needs, is very different from applying templates on all nodes that match this test. Just testing for a condition can be significantly more efficient. The OP hasn't indicated in any way that the test is in any way connected to applying templates.

need to display char in xslt

Hi all
I am using xslt 1.0. I have the char code as FOA7 which has to displayed as a corresponding character. My input is
<w:sym w:font="Wingdings" w:char="F0A7"/>
my xslt template is
<xsl:template match="w:sym">
<xsl:variable name="char" select="#w:char"/>
<span font-family="{#w:fonts}">
<xsl:value-of select="concat('&#x',$char,';')"/>
</span>
</xsl:template>
It showing the error as ERROR: 'A decimal representation must immediately follow the "&#" in a character reference.'
Please help me in fixing this..Thanks in advance...
This isn't possible in (reasonable) XSLT. You can work around it.
Your solution with concat is invalid: XSLT is not just a fancy string-concatenator, it really transforms the conceptual tree. An encoded character such as  is a single character - if you were to somehow include the letters & # x f 0 a 7 ; then the XSLT processor would be required to include these letters in the XML data - not the string! So that means it will escape them.
There's no feature in XSLT 1.0 that permits converting from a number to a character with that codepoint.
In XSLT 2.0, as Michael Kay points out, you can use codepoints-to-string() to achieve this.
There are two solutions. Firstly, you could use disable-output-escaping. This is rather nasty and not portable. Avoid this at all costs if you can - but it will probably work in your transformer, and it's probably the only general, simple solution, so you may not be able to avoid this.
The second solution would be to hardcode matches for each individual character. That's a mess generally, but quite possible if you're dealing with a limited set of possibilities - that depends on your specific problem.
Finally, I'd recommend not solving this problem in XSLT - this is typically something you can do in pre/post processing in another programming environment more appropriately. Most likely, you've an in-memory representation of the XML document to be able to use XSLT in the first place, in which case this won't even take much CPU time.
<span font-family="{#w:font}">
<xsl:value-of select="concat('&#x', #w:char, ';')"
disable-output-escaping="yes"/>
</span>
Though check #Eamon Nerbonne's answer, why you shouldn't do it at all.
If you were using XSLT 2.0 (which you aren't), you could write a function to convert hex to decimal, and then use codepoints-to-string() on the result.
use '&' for '&' in output:
<xsl:value-of select="concat('&#x',$char,';')"/>

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.