xsl number()-function cannot convert - xslt

I am using fop 1.0 in a .NET application.
My stylesheet looks like
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet ... version="1.0" ...>
...
<xsl:param name="fromPerson" select="'1'"/>
<xsl:param name="toPerson" select="'1'"/>
...
<xsl:template match="*[local-name()='Person']">
<xsl:if test="(position() >= number($fromPerson))>
...
</xsl:if>
</xsl:template>
The problem is that the function number() fails with:
Zeilennummer221; Spaltennummer267; #UNKNOWN (cli.System.Int32) kann nicht in eine Zahl
konvertiert werden!
(Position des Fehlers unbekannt)org.apache.fop.fo.ValidationException: "fo:root"
is missing child elements. Required content model: (layout-master-set, declarations?,
bookmark-tree?, (page-sequence|fox:external-document)+) (Keine Kontextinformationen
verf³gbar)
Important:
#UNKNOWN (cli.System.Int32) cannot be converted into an integer
btw: I tested it by printing out the value with <xsl:message>
Any idea why this brings out the error?

The types of value that can be passed to global stylesheet parameters depend on the API of the processor. I guess you are using a processor whose API does not allow values of type cli.System.Int32.
Indeed, the types accepted by the Microsoft API are listed here:
http://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltargumentlist.addparam.aspx

I think you need an <xsl:variable>, not an <xsl:param>. Parameters are subelements of the <xsl:template> element (or in XSLT 2 of an <xsl:function> element.

Related

Unknown function saxon:parse-html when compiling stylesheet

I am working on an XSL transformation on Oxygen using the Saxon-EE 10.3 transformer. I want to use the compiled stylesheet (sef.json) later on my website with Saxon-JS 2.
Inside of the XSL transformation I am using the saxon:parse-html function with the saxon namespace declared as following:
<xsl:stylesheet xmlns:prop="http://saxonica.com/ns/html-property"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:style="http://saxonica.com/ns/html-style-property"
xmlns:saxon="http://saxon.sf.net/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT"
xmlns:js="http://saxonica.com/ns/globalJS"
exclude-result-prefixes="xs prop ixsl js style saxon xhtml"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xpath-default-namespace="http://www.tei-c.org/ns/1.0"
xmlns="http://www.tei-c.org/ns/1.0">
and the function is called this way:
<xsl:call-template name="nameTemplate">
<xsl:with-param name="html">
<xsl:copy-of select="saxon:parse-html(var)"></xsl:copy-of>
</xsl:with-param>
</xsl:call-template>
I tried to compile the stylesheet through this command:
xslt3 -xsl:test.xsl -export:test.sef.json -t
but I encounter the following error:
Failed to compile stylesheet: Static error in XPath on line 147 in Oxygen/Test.xsl {saxon:parse-html(?Text)}: Unknown function Q{http://saxon.sf.net/}parse-html()
Error Q{http://www.w3.org/2005/xqt-errors}XPST0017 at xpath.xsl#963
Failed to compile stylesheet
Error Q{http://www.w3.org/2005/xqt-errors}XPST0017 at xpath.xsl#963
Static error in XPath on line 147 in Oxygen/Test.xsl {saxon:parse-html(?Text)}: Unknown function Q{http://saxon.sf.net/}parse-html()
The transformation works without problem inside Oxygen though.
You might need to call into JavaScript e.g. set up a script element
<script>
function parseHTML(html) { return new DOMParser().parseFromString(html, 'text/html'); }
</script>
in your HTML document and then inside of XSLT with Saxon JS 2 in the browser you should be able to use e.g.
ixsl:window() => ixsl:get('parseHTML') => ixsl:apply([var])
instead of saxon:parse-html(var), with a namespace declaration of xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT" in your XSLT.
Another way to not require you to set up the script code in addition to the XSLT code is to use ixsl:eval to run the JavaScript directly from XSLT in Saxon-JS 2; I have set up an example at https://martin-honnen.github.io/saxon-js-parse-html-test/html/test-saxon-parse-html2.html which basically uses an implementation
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
xmlns:ixsl="http://saxonica.com/ns/interactiveXSLT"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:function name="saxon:parse-html" as="document-node()" use-when="system-property('xsl:product-name') = 'Saxon-JS'">
<xsl:param name="html" as="xs:string"/>
<xsl:sequence select="ixsl:eval('new DOMParser()') => ixsl:call('parseFromString', [$html, 'text/html'])"/>
</xsl:function>
</xsl:stylesheet>
of the XSLT 3 module https://github.com/martin-honnen/saxon-js-parse-html-test/blob/master/xslt/override-saxon-parse-html2.xsl.
You can xsl:import that in your other XSLT code, as done in https://github.com/martin-honnen/saxon-js-parse-html-test/blob/master/xslt/test-override-saxon-parse.xsl with e.g. <xsl:import href="override-saxon-parse-html2.xsl"/> and call e.g. saxon:parse-html(.).
I managed to compile that code to an SEF file with the settings xslt3 -xsl:test-override-saxon-parse.xsl -nogo -export:test-override-saxon-parse. -sef.json -ns:"##html5" and that way the HTML page https://martin-honnen.github.io/saxon-js-parse-html-test/html/test-saxon-parse-html2.html can simply run that XSLT with
SaxonJS.transform({
stylesheetLocation: '../xslt/test-override-saxon-parse.sef.json',
sourceLocation: '../xml/sample2.xml',
destination: 'appendToBody'
}, 'async')
As an alternative, you could import the pure XSLT 2 HTML parser that David Carlisle has somewhere on GitHub into your XSLT code.

calling one xslt file from base xslt - xslt1.0

I went through many other similar questions and answers in stackoverflow. But still not able to resolve the issue. If anyone can help me with it that would be really great.I am using call template to call one small xslt file from my larger xslt
My small xslt(WorkOrders.xsl) is very simple. Below is the part of my xslt:
<xsl:template match="GetWorkOrder">
<tns:Work>
<tns:description>
<xsl:value-of select="//ns0:WORKORDERS_ITEM/ns0:DESCRIPTION"/>
</tns:description>
<tns:workOrderNumber>
<xsl:value-of select="//ns0:WORKORDERS_ITEM/ns0:WORKORDER"/>
</tns:workOrderNumber>
</tns:Work>
</xsl:template>
I want to call WorkOrder.xsl from my base xslt. i am using the import statement
part of my base xslt. (i have got rid of the extra xml definitions to shorten the xslt for this question)
<xsl:stylesheet version="1.0" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java">
<xsl:import href="../Transformation/WorkOrders.xsl"/>
<oracle-xsl-mapper:schema>
<!--SPECIFICATION OF MAP SOURCES AND TARGETS, DO NOT MODIFY.-->
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="XSD">
<oracle-xsl-mapper:schema location="../Schema/Sample.xsd"/>
<oracle-xsl-mapper:rootElement name="OutputParameters"
namespace="****"/>
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:mapTargets>
<oracle-xsl-mapper:target type="XSD">
<oracle-xsl-mapper:schema location="../Schema/Sample1.xsd"/>
<oracle-xsl-mapper:rootElement name="GetResponse" namespace="*****"/>
</oracle-xsl-mapper:target>
</oracle-xsl-mapper:mapTargets>
<!--GENERATED BY ORACLE XSL MAPPER 12.1.3.0.0(XSLT Build 140529.0700.0211) AT [THU SEP 26 14:08:57 EDT 2019].-->
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE-->
<xsl:template match="/">
<tns:GetResponse>
<tns:Response>
<Work>
<xsl:call-template name="GetWorkOrder"></xsl:call-template>
</Work>
</tns:Response>
</tns:GetResponse>
</xsl:template>
</xsl:stylesheet>
I receive an error message saying GetWorkOrder template is been called but not defied. Not sure what i am missing
Your template isn't named GridWalkOrder, you've defined it as matching an element of that name rather than naming the template. Use
<xsl:template name="GetWorkOrder">
instead.

Parameterize path to import a xslt from other xslt

I am trying to parametrize a path to include a xslt file into other, I have been trying with the way described here:
<xsl:param name="basedir" />
<xsl:include href="{$basedir}/team-menu.xsl" />
and call to the xslt doing:
xsltproc --stringparam basedir style example.xslt example.xml
But no way. I am not abel to do it work. It seems like if the xsl:output element was related because the only way I could make it "work" was this:
<xsl:include href="the/path/to/file/team-menu.xsl" />
<xsl:output method="xml" indent="yes"/>
<xsl:param name="basedir" />
I mean... putting the param after the output and the include before. Big problem: I can´t use the variable basedir.
Any way to do this??
Thank you in advance.
In XSLT 3.0 you can do this provided the parameters are declared as static, which means the values have to be supplied at compile time. You also need to prefix the attribute with "_":
<xsl:param name="basedir" static="yes"/>
<xsl:include _href="{$basedir}/team-menu.xsl" />
The reason it doesn't work with ordinary variables should be fairly obvious: variable values aren't known until run-time, and you can't start execution until you have found all the source code making up the stylesheet.
What you can do with earlier releases of XSLT, depending on the processor, is to redirect xs:include/xs:import URIs from the API level, for example (on Java) by using a user-supplied URIResolver.

Value-of select in <a href=> (XSLT)

I try to concstruct link with
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="concat('file:///', substring-before('%RolesPath%', 'roles'),'Flores.chm')"/>
</xsl:attribute>
Help
</xsl:element>
but I get error:
File file:///Flores.chm not found
I'm pretty sure, that variable %RolesPath% works fine. I'm using it in code normally. And if I use in code only
<xsl:value-of select="concat('file:///', substring-before('%RolesPath%', 'roles'),'Flores.chm')"/>
I get
file:///C:\Flores\Flores.chm
which is right path. Where I'm doing mistake please?
edit. %RolesPath% stores path to specify folder of program, which works with this code. In my case %RolesPath% stores "C:\Flores\roles\".
To specify my problem. I need open file(Flores.chm) in root folder of program. Program can be install everywhere in PC and prapably only way, how I can get the path is via %RolesPath%.
What you are passing to substring-before() is just a string ('%RolesPath%'). It appears that you are trying to use a Windows environment variable. This isn't going to work the way you're using it.
I think you have 2 options:
Option 1
Pass the value of the environment variable as an xsl:param when you call the stylesheet. This would work in either XSLT 1.0 or 2.0.
You would need the xsl:param:
<xsl:param name="RolesPath"/>
and this is how you would reference it:
<a href="{concat('file:///', substring-before($RolesPath, 'roles'),'Flores.chm')}"/>
Option 2
Use the environment-variable() function. This would only work with an XSLT 3.0 processor, such as Saxon-PE or EE.
Example:
<a href="{concat('file:///', substring-before(environment-variable('RolesPath'), 'roles'),'Flores.chm')}"/>
Here's another example of environment-variable() to show the function actually working:
XSLT 3.0
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<environment-variable name="TEMP" value="{environment-variable('TEMP')}"/>
</xsl:template>
</xsl:stylesheet>
Output (when applied to any well-formed XML)
<environment-variable name="TEMP" value="C:\Users\dhaley\AppData\Local\Temp"/>
Use this shorter expression:
<a href="file:///{substring-before($RolesPath, 'roles')}Flores.chm"/>
where $RolesPath is passed as an external, global parameter to the transformation.
How exactly to pass an external parameter to the transformation varies from one XSLT processor to another -- read your XSLT processor documentation. Some XSLT processors also allow string-typed parameters to be passed to the transformation from a command-line execution utility.

Xslt transform on special characters

I have an XML document that needs to pass text inside an element with an '&' in it.
This is called from .NET to a Web Service and comes over the wire with the correct encoding &
e.g.
T&O
I then need to use XSLT to create a transform but need to query SQL server through a SP without the encoding on the Ampersand e.g T&O would go to the DB.
(Note this all has to be done through XSLT, I do have the choice to use .NET encoding at this point)
Anyone have any idea how to do this from XSLT?
Note my XSLT knowledge isn’t the best to say the least!
Cheers
<xsl:text disable-output-escaping="yes">&<!--&--></xsl:text>
More info at: http://www.w3schools.com/xsl/el_text.asp
If you have the choice to use .NET you can convert between an HTML-encoded and regular string using (this code requires a reference to System.Web):
string htmlEncodedText = System.Web.HttpUtility.HtmlEncode("T&O");
string text = System.Web.HttpUtility.HtmlDecode(htmlEncodedText);
Update
Since you need to do this in plain XSLT you can use xsl:value-of to decode the HTML encoding:
<xsl:variable name="test">
<xsl:value-of select="'T&O'"/>
</xsl:variable>
The variable string($test) will have the value T&O. You can pass this variable as an argument to your extension function then.
Supposing your XML looks like this:
<root>T&O</root>
you can use this XSLT snippet to get the text out of it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="root"> <!-- Select the root element... -->
<xsl:value-of select="." /> <!-- ...and extract all text from it -->
</xsl:template>
</xsl:stylesheet>
Output (from Saxon 9, that is):
T&O
The point is the <xsl:output/> element. The defauklt would be to output XML, where the ampersand would still be encoded.