XSLT functions problem?

2,091 views
Skip to first unread message

watou

unread,
Mar 18, 2015, 6:51:49 AM3/18/15
to ope...@googlegroups.com
Hello XML/XSL people,

I am trying to create a proper DateTime item from an epoch value (number of seconds since 1/1/1970) in an XML input, and the following works perfectly with an online XSLT tester, but fails in OpenHAB.  I am trying to determine what is different about the XSLT processor in OpenHAB that complains that "Cannot convert data-type 'void' to 'real'."

Here is the XML:

<response>
<current_observation>
<observation_time>Last Updated on March 17, 5:00 AM EDT</observation_time>
<observation_time_rfc822>Tue, 17 Mar 2015 05:00:00 -0400</observation_time_rfc822>
<observation_epoch>1426582800</observation_epoch>
<local_time_rfc822>Tue, 17 Mar 2015 05:09:40 -0400</local_time_rfc822>
<local_epoch>1426583380</local_epoch>
<local_tz_short>EDT</local_tz_short>
<local_tz_long>America/New_York</local_tz_long>
<local_tz_offset>-0400</local_tz_offset>
</current_observation>
</response>

Here is the XSLT:

<?xml version="1.0"?>
<xsl:stylesheet  version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xsl:output indent="yes" method="xml" encoding="UTF-8" omit-xml-declaration="yes" />
        <xsl:template match="/">
                <xsl:value-of select='xs:dateTime("1970-01-01T00:00:00") + //current_observation/observation_epoch * xs:dayTimeDuration("PT1S")'/>
        </xsl:template>
</xsl:stylesheet>

The online XSLT tester returns what I'm looking for:

2015-03-17T09:00:00

But OpenHAB instead throws an exception into the log:
2015-03-18 08:09:29.520 [ERROR] [.i.s.XsltTransformationService] - transformation throws exception
javax.xml.transform.TransformerConfigurationException: Cannot convert data-type 'void' to 'real'.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:992) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:766) ~[na:1.8.0_33]
at org.openhab.core.transform.internal.service.XsltTransformationService.transform(XsltTransformationService.java:82) ~[na:na]
at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:179) [bundlefile:na]
at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:156) [org.openhab.core_1.6.2.jar:na]
at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:173) [org.openhab.core_1.6.2.jar:na]
Caused by: com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError: Cannot convert data-type 'void' to 'real'.
at com.sun.org.apache.xalan.internal.xsltc.compiler.CastExpr.typeCheck(CastExpr.java:188) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.CastExpr.<init>(CastExpr.java:143) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.BinOpExpr.typeCheck(BinOpExpr.java:94) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.BinOpExpr.typeCheck(BinOpExpr.java:83) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.ValueOf.typeCheck(ValueOf.java:68) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.SyntaxTreeNode.typeCheckContents(SyntaxTreeNode.java:493) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.Template.typeCheck(Template.java:295) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.SyntaxTreeNode.typeCheckContents(SyntaxTreeNode.java:493) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.Stylesheet.typeCheck(Stylesheet.java:657) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.Parser.createAST(Parser.java:411) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC.compile(XSLTC.java:427) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC.compile(XSLTC.java:512) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:951) ~[na:1.8.0_33]
... 5 common frames omitted
I believe that none of the string representations is suitable for creating a proper DateTime item, so I'm trying to use the epoch value to produce an ISO8601-format date/time string.

Any ideas?  Thanks!

watou

cal

unread,
Mar 18, 2015, 6:59:37 AM3/18/15
to ope...@googlegroups.com

watou

unread,
Mar 18, 2015, 7:43:13 AM3/18/15
to ope...@googlegroups.com
Thanks very much for that.  Unfortunately, while this works perfectly in the online tester I linked earlier:

<?xml version="1.0"?>
<xsl:stylesheet  version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:fn="http://whatever">

    <xsl:output indent="yes" method="xml" encoding="UTF-8" omit-xml-declaration="yes" />
    <xsl:function name="fn:epochToDate">
        <xsl:param name="epoch"/>
        <xsl:variable name="dayTimeDuration" select="concat('PT',$epoch,'S')"/>
        <xsl:value-of select="xs:dateTime('1970-01-01T00:00:00') + xs:dayTimeDuration($dayTimeDuration)"/>
    </xsl:function>
    <xsl:template match="/">
        <xsl:value-of select='fn:epochToDate(//current_observation/observation_epoch)'/>
    </xsl:template>
</xsl:stylesheet>

OpenHAB now throws this different exception into the log:

org.openhab.core.transform.TransformationException: transformation throws exception
at org.openhab.core.transform.internal.service.XsltTransformationService.transform(XsltTransformationService.java:86) ~[na:na]
at org.openhab.binding.http.internal.HttpBinding.execute(HttpBinding.java:179) ~[na:na]
at org.openhab.core.binding.AbstractActiveBinding$BindingActiveService.execute(AbstractActiveBinding.java:156) [org.openhab.core_1.6.2.jar:na]
at org.openhab.core.service.AbstractActiveService$RefreshThread.run(AbstractActiveService.java:173) [org.openhab.core_1.6.2.jar:na]
Caused by: javax.xml.transform.TransformerConfigurationException: The first argument to the non-static Java function 'epochToDate' is not a valid object reference.
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:994) ~[na:1.8.0_33]
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:766) ~[na:1.8.0_33]
at org.openhab.core.transform.internal.service.XsltTransformationService.transform(XsltTransformationService.java:82) ~[na:na]
... 3 common frames omitted

Does OpenHAB use some non-standard "dialect" of XSL (would seem really unlikely to me, but I don't know where to find the specific docs).

Thanks very much for your help, in any case.

watou

cal

unread,
Mar 18, 2015, 8:05:41 AM3/18/15
to ope...@googlegroups.com
Oh, maybe xalan is XSLT 1.0 only.

Can that be the problem, that you specify version 2.0?
Ans also you specify xml as output but produce text only?


What about
<?xml version="1.0"?>
    <xsl:stylesheet  version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">

        <xsl:output indent="yes" method="text" encoding="UTF-8"/>
        <xsl:variable name="dayTimeDuration" select="concat('PT',//current_observation/observation_epoch,'S')"/>
        <xsl:template match="/">
           <xsl:value-of select="xs:dateTime('1970-01-01T00:00:00') + xs:dayTimeDuration($dayTimeDuration)"/>
        </xsl:template>
    </xsl:stylesheet>

watou

unread,
Mar 18, 2015, 8:31:34 AM3/18/15
to ope...@googlegroups.com
Thanks for looking at it further.  I suspect user-defined functions are handled differently in the XSL with have in OH1.x.  I'm going to abandon this effort for now since I can't find a way to make a proper DateTime item with the XML values I have to work with.  Hopefully OH2 / ESH has a more capable XSLT processor.

Regards,
watou

Mark

unread,
Mar 18, 2015, 1:58:06 PM3/18/15
to ope...@googlegroups.com

watou,
You can push the conversion logic into openHAB Rules, esp if their XSLT processor isn't able to handle XSLT 2 constructs (not even xsltproc can do that)

It'll look like the following:


Item Declarations:

Number   TestSourceDate "Source Data [%d]"
DateTime TestTargetDate "Date [%s]"


Rule Declaration:

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.openhab.core.persistence.*

import java.util.Calendar

rule
"Convert dates"
when
       
Item TestSourceDate changed
then
       
var Calendar t = Calendar::getInstance
        t
.setTimeInMillis((TestSourceDate.state as Number).longValue * 1000)

       
TestTargetDate.postUpdate(new DateTimeType(t))
end


and then your XSLT just needs to be mod'd to extract the Epoch, instead of trying to do all the conversions (etc), and put the value into the TestSourceDate Item (presumably via a better Bind declaration than I have above)

I used a shell line to simulate that input:

wget --method=PUT \
     
--verbose \
     
--body-data="`date +%s`" \
     
--header="Content-Type: text/plain"
     http
://localhost:8080/rest/items/TestSourceDate/state


BTW: The XML block looks familiar ;)    Any reason you've got partial WUI data/streams outside of the native Binding?

watou

unread,
Mar 18, 2015, 5:45:33 PM3/18/15
to ope...@googlegroups.com
Thanks for the suggestions, Mark.  My goal was to familiarise myself with the XSLT transform, and to keep the mechanism as simple as possible.  I also wanted control over which specific weather stations I am pulling data from in wunderground; I think I might be setting one up more locally than what is currently available.
Reply all
Reply to author
Forward
0 new messages