Including a plain text file with XSLT 1.0 - xslt

How can I include the content of a plain text file in a result document from within an XSLT 1.0 stylesheet? I.e., just like document(), but without parsing it:
<xsl:value-of select="magic-method-to-include-plaintext(#xlink_href)" />
I am almost sure, that this doesn't work without extension, because:
there is a special XPath function defined for this in XSLT/XPath 2.0:
<xsl:value-of select="unparsed-text(#xlink:href, 'UTF-8')"/>
the XSLT FAQ only lists a Java extension to achieve this via EXSLT
However, perhaps I missed something?

However, perhaps I missed something?
No, XSLT 1.0 cannot access the content of a non-xml text file without using an extension function.
One way around this is to pass the string as a global parameter to the transformation.

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

xslt passing input document as String to java extension

I am trying to write two XSL files, trying to achieve following goals:
It is supposed to encrypt the input document.
It is supposed to binary encode the XML document.
Example output of 1)
<Response>
<encryptedData>e070dee5cb4688c608ee</encryptedData>
</Response>
Example output of 2)
<Response>
<compressedData>ASCDee5cb4688c608ee</compressedData>
</Response>
For functionality #1, I have a Java extension function that takes a string input and returns an encrypted string. But I don't know how to pass the input document as string to the extension function.
For functionality #2, I am not sure how to convert input to binary XML.
XSLT cannot exactly reproduce the original string representing an XML document -- due to various lexical peculiarities (and substitution of entity referencies) that are not able to reconstruct from the XmlDocument produced by the XML parser -- which is the input that an XSLT processor sees.
You can pass to the extension function the document object (/) and then the Java function can use a method like OuterXml() or InnerXml() to get one possible representation of the XML document.
I can only give an answer to your first question on how to call a java function from an XSLT.
In your stylesheet declaration you have to define a namespace, e.g. xmlns:filecounter="mappings.GenerateSequenceNumber":
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:filecounter="mappings.GenerateSequenceNumber"
exclude-result-prefixes="filecounter" version="1.0">
<xsl:output indent="yes"/>
In this case the java function is in the package "mappings" and the java class is called "GenerateSequenceNumber".
When calling the java function in your stylesheet you do for example:
<xsl:value-of select="filecounter:getSequenceNumber('countit',3)"/>
So you call the method "getSequenceNumber" in your java class and pass any variables that the java function needs in the brackets.
Unfortunately I can't help you with your second question.

XSLT function document() using wildcard

Is there any possibility to use a wildcard for the document() function in XSLT like:
document("*.xml")
This is the same question: http://www.biglist.com/lists/xsl-list/archives/200108/msg00542.html
However this post is from 2001 so there might be any new techniques to solve this. Ideas?
Is there any possibility to use a wildcard for the document() function
No, there aren't any such changes to the behaviour of the document() function.
However, XPath 2.0 (and that means available in XSLT 2.0) offers the standard function collection()
Its behavior is to some extent implementation dependent.
Example (based on Saxon 9):
This XPath expression:
collection('file:///c:/?select=report_*.xml')
selects the document nodes of every XML document that resides in c:\ in a file with name starting with report_ then having a 0 or more characters, then ending with .xml.

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,';')"/>

How to check XML has a node or it is an empty file using XSLT?

Please help on this issue.
I want to check an XML contains a node or not [OR] it is an empty file using XSLT.
My XML is:
<mynode>
<node1>testing</node1>
</mynode>
I want to write XSLT code something like this:
<xsl:choose>
<xsl:when test="document('')/mynode">
file is empty
</xsl:when>
<xsl:otherwise>
file has nodes
</xsl:otherwise>
</xsl:choose>
Please any one can help me on this.....
If the file doesn't contain an element, then it is not an XML file, and XML parsing will therefore fail. Different XSLT 1.0 processors react differently to this (as permitted by the spec). In XSLT 2.0 you can use doc-available() to protect yourself, but this is not available in 1.0. In fact, there's nothing you can do about this in 1.0 without knowing details of your particular XSLT processor.