Read service response(json format) inside xslt 2.0 - xslt

Need to read a service response inside xslt which is of format :
servicedata={"statusCode":200,"loginMessage":"Welcome User"}
its key value pair, where i can get the value of 'servicedata' but further need to get the status code value for some condition checking.
Using version 2.0 for the xslt
read few questions which suggested to use parse-json(), json-to-xml with 3.0 version of xslt, but didn't help.
Question: first using version 2.0 only can I retrieve the value for the 'statusCode' and how, if not guide me how to achieve it.

If you can move to Saxon 9.7 HE then you could use json-to-xml as follows for instance:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:template match="data">
<xsl:value-of select="json-to-xml(substring-after(., 'servicedata='))//*[#key = 'statusCode']" xpath-default-namespace="http://www.w3.org/2005/xpath-functions"/>
</xsl:template>
</xsl:stylesheet>
which for the input
<data>servicedata={"statusCode":200,"loginMessage":"Welcome User"}</data>
outputs 200.
I have not checked whether earlier versions of Saxon 9 also support that.

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.

Why is my xsl processing instruction missing a question mark?

I want to create a html document with a php block (just for learning purposes) from an xsl transformation of a xml document. I am using the <xsl:processing-instruction> tag.
&ltxsl:stylesheet version="1.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"&gt
&ltxsl:template match="/"&gt
&ltxsl:processing-instruction name="php"&gt
&ltxsl:text&gt
setcookie("cookiename", "cookievalue");
echo "";
&lt/xsl:text&gt
&lt/xsl:processing-instruction&gt
&lthtml&gt
&lthead&gt
&ltmeta charset="utf-8" /&gt
&lt/head&gt
&ltbody&gt
&ltxsl:apply-templates /&gt
&lt/body&gt
&lt/html&gt
&lt/xsl:template&gt
&ltxsl:template match="pagina"&gt
&ltxsl:for-each select="paragraf"&gt
&ltp&gt
&ltxsl:value-of select="."/&gt
&lt/p&gt
&lt/xsl:for-each&gt
&lt/xsl:template&gt
&lt/xsl:stylesheet&gt
The result is:
&lt?php
setcookie("ceva", "textceva");
echo "";&gt
&lthtml&gt
&lthead&gt
&ltmeta http-equiv="Content-Type" content="text/html; charset=UTF-8"&gt
&ltmeta charset="utf-8"&gt
&lt/head&gt
&ltbody&gt
&ltp&gt
text 1
&lt/p&gt
&ltp&gt
text 2
&lt/p&gt
&lt/body&gt
&lt/html&gt
Why is the second question mark missing? I was expecting something like <?php setcookie(...).. ?> .
It's because your pi (processing instruction) is an SGML processing instruction (HTML is SGML). Normally the default output for XSLT is XML, but whatever processor that you're using must be defaulting to HTML (or you omitted something in your XSLT example). Another clue pointing to this is that your meta elements aren't closed in the output.
Example (note the method="html"):
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="html"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<xsl:processing-instruction name="test">pi</xsl:processing-instruction>
</html>
</xsl:template>
</xsl:stylesheet>
Output (using the XSLT as the input (or any XML file))
<html><?test pi></html>
To force an XML pi, add the xsl:output:
<xsl:output indent="yes" method="xml"/>
It's my understanding that the correct representation of a processing instruction in HTML is (or was, at the relevant point in time) to omit the question mark, and the specification for XSLT serialization says that this is what should be done by the HTML output method. Sorry, I don't have time to consult the specs just now to confirm this.
Of course, you are trying to generate stuff which is defined in the PHP specification rather than the HTML specification, and the XSLT serialization spec knows nothing of PHP.

WSO2 ESB 4.0.3 and XSLT 2.0 support

As per following URL I enabled the XSLT 2.0 support how ever the looks like the TryIt service is not working when I do that.
Achala Blog Entry
I get following error when I try to use TryIt service.
[2012-09-10 11:47:03,491] INFO - CarbonAuthenticationUtil 'admin' logged in at [2012-09-10 11:47:03,0491] from IP address 0:0:0:0:0:0:0:1%0
Warning: at xsl:stylesheet on line 32 of :
Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
Warning: on line 286 of :
The attribute axis starting at a namespace() node will never select anything
Error on line 1603 of :
XPTY0004: Required item type of second operand of '|' is node(); supplied value has item
type xs:string
[2012-09-10 11:47:09,515] ERROR - Util Required item type of second operand of '|' is node(); supplied value has item type xs:string
; SystemID: ; Line#: 1603; Column#: -1
net.sf.saxon.trans.DynamicError: Required item type of second operand of '|' is node(); supplied value has item type xs:string
Is there any workaround so that we can use XSLT 2.0 and TryIt both with WSO2 ESB 4.0.3.
Hoping for answer.
thanks
Abhijit
You need to replace the standard XSLT processor by a newer one being able to process XSLT 2.0 like documented in the Blog solution for WSO2 ESB 4.0.3:
Remove xalan-2.7.0.wso2v1.jar in ESB_HOME/lib/endorsed/
Remove saxon-8.9.0.wso2v1.jar from ESB_HOME/repository/components/plugins
Copy the saxon9he.jar to lib/endorsed and start the server.
SAXON 9 you can download here
Be aware that you'll get the SOAP envelope and body also as Input to your XSLT, so maybe you need to have the xsl:template for these elements too:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="/soapenv:Envelope|soapenv:Body">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
...
The latest WSO2 ESB (v4.5.0) supports XSLT 2.0 [1], via Saxson.
[1] http://mail.wso2.org/mailarchive/announce/2012-September/000026.html
Regards,
/Nuwan

XSLT functions and namespaces

I'm kind of new to XSLT, and I've gotten basic transformation done. Next I want to try out date manipulations, since my data will have timestamps. However, I can't seem to get any date functions to work, and it greatly frustrates me. I'm testing using Firefox 3.5, xsltproc 1.1.24, xalan 1.10, and XMLSpy 2009, and they all say that the functions I'm trying to use don't exist.
My xml looks like so:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="datetime.xsl"?>
<watcher>
<event id="1" date="2009-09-04T13:49:10-0500" type="ABCD">This is a test </event>
</watcher>
</code>
My xsl looks like so:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="event[#type='ABCD']">
<!-- Date: <xsl:value-of select="day-from-dateTime(xs:dateTime(#date))"/> -->
<!-- Date: <xsl:value-of select="day-from-dateTime(#date)"/> -->
Date: <xsl:value-of select="fn:day-from-dateTime(#date)"/>
</xsl:template>
</xsl:stylesheet>
If I make the stylesheet version 2, XMLSpy complains that it can't cast my date: XSLT 2.0 Debugging Error: Error in XPath 2.0 expression (Cast failed, invalid lexical value - xs:dateTime '2009-09-04T13:49:10-0500')
If I leave it as version 1, it complains about a different error: XSLT 1.0 Debugging Error: Error in XPath expression (Unknown function - Name and number of arguments do not match any function signature in the static context - 'day-from-dateTime')
Anytime I try to change the XSL to use a namespace, such as fn:day-from-dateTime, it refuses to work at all, with all of my parsers saying that The function number 'http://www.w3.org/2005/02/xpath-functions:day-from-dateTime' is not available and variants thereof. I know from other tests that I can use the substring() function perfectly, without needing any namespace prefix, and I believe it's in the same namespace as day-from-dateTime.
I feel like it's something incredibly easy, since all of the tutorials show functions being used, but something seems to be eluding me. Could someone show me what I'm missing?
Ouch, nasty versions thing going on here. A lot of the issues you're seeing will be because the XSLT processor you're using doesn't support XPath 2.0, which is where that day-from-dateTime function comes from.
I can get what you're trying to do to work, with a Saxon processor - Saxon-B 9.1.0.6 as my processor instead of Xalan. (Xalan appears to support XPath 1.0 only, according to the documentation)
There are a few errors in your documents:
The source document should have the timezone as 05:00, not 0500
<?xml version="1.0" encoding="UTF-8"?>
<watcher>
<event id="1" date="2009-09-04T13:49:10-05:00" type="ABCD">This is a test </event>
</watcher>
The XSLT should cast the string 2009-09-04T13:49:10-05:00 into a xs:dateTime, which is what type the argument of day-from-dateTime needs to be.
Date: <xsl:value-of select="day-from-dateTime(xs:dateTime(#date))"/>
And then it works
<?xml version="1.0" encoding="UTF-8"?>
Date: 4
Hope that helps,

Can an XSLT insert the current date?

A program we use in my office exports reports by translating a XML file it exports with an XSLT file into XHTML. I'm rewriting the XSLT to change the formatting and to add more information from the source XML File.
I'd like to include the date the file was created in the final report. But the current date/time is not included in the original XML file, nor do I have any control on how the XML file is created. There doesn't seem to be any date functions building into XSLT that will return the current date.
Does anyone have any idea how I might be able to include the current date during my XSLT transformation?
XSLT 2
Date functions are available natively, such as:
<xsl:value-of select="current-dateTime()"/>
There is also current-date() and current-time().
XSLT 1
Use the EXSLT date and times extension package.
Download the date and times package from GitHub.
Extract date.xsl to the location of your XSL files.
Set the stylesheet header.
Import date.xsl.
For example:
<xsl:stylesheet version="1.0"
xmlns:date="http://exslt.org/dates-and-times"
extension-element-prefixes="date"
...>
<xsl:import href="date.xsl" />
<xsl:template match="//root">
<xsl:value-of select="date:date-time()"/>
</xsl:template>
</xsl:stylesheet>
Do you have control over running the transformation? If so, you could pass in the current date to the XSL and use $current-date from inside your XSL. Below is how you declare the incoming parameter, but with knowing how you are running the transformation, I can't tell you how to pass in the value.
<xsl:param name="current-date" />
For example, from the bash script, use:
xsltproc --stringparam current-date `date +%Y-%m-%d` -o output.html path-to.xsl path-to.xml
Then, in the xsl you can use:
<xsl:value-of select="$current-date"/>
For MSXML parser, try this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:my="urn:sample" extension-element-prefixes="msxsl">
<msxsl:script language="JScript" implements-prefix="my">
function today()
{
return new Date();
}
</msxsl:script>
<xsl:template match="/">
Today = <xsl:value-of select="my:today()"/>
</xsl:template>
</xsl:stylesheet>
Also read XSLT Stylesheet Scripting using msxsl:script and Extending XSLT with JScript, C#, and Visual Basic .NET
...
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:local="urn:local" extension-element-prefixes="msxsl">
<msxsl:script language="CSharp" implements-prefix="local">
public string dateTimeNow()
{
return DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ");
}
</msxsl:script>
...
<xsl:value-of select="local:dateTimeNow()"/>
Late answer, but my solution works in Eclipse XSLT. Eclipse uses XSLT 1 at time of this writing. You can install an XSLT 2 engine like Saxon. Or you can use the XSLT 1 solution below to insert current date and time.
<xsl:value-of select="java:util.Date.new()"/>
This will call Java's Data class to output the date. It will not work unless you also put the following "java:" definition in your <xsl:stylesheet> tag.
<xsl:stylesheet [...snip...]
xmlns:java="java"
[...snip...]>
I hope that helps someone. This simple answer was difficult to find for me.
format-date(current-date(), '[M01]/[D01]/[Y0001]') = 09/19/2013
format-time(current-time(), '[H01]:[m01] [z]') = 09:26 GMT+10
format-dateTime(current-dateTime(), '[h1]:[m01] [P] on [MNn] [D].') = 9:26 a.m. on September 19.
reference: Formatting Dates and Times using XSLT 2.0 and XPath