#47 for-each and Java extension returning NodeList

closed
nobody
None
5
2014-11-25
2006-08-04
Libor
No

Java extension returning org.w3c.dom.NodeList
and loop in stylesheet
<xsl:for-each select="xje:asNodeList($contribs)">
<xsl:apply-templates select="name/surname"/>
</xsl:for-each>

Fails with an error:

[junit] Error on line 3446 of file:///...Abstract.xsl:
[junit]   XPTY0020: Axis step child::element(name)

cannot be used here: the context item is an atomic value
[junit]
javax.xml.transform.TransformerConfigurationException:
Failed to compile stylesheet. 1 error detected.
[junit] at
net.sf.saxon.PreparedStylesheet.prepare(PreparedStylesheet.java:140)
[junit] at
net.sf.saxon.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:135)
[junit] at
com.atypon.publish.TestXslSaxon.checkXSLT(TestXslSaxon.java:59)

This code worked fine using Xalan bundled with JDK 1.5,
fails with Saxon 8.7.3

Discussion

  • Michael Kay
    Michael Kay
    2006-08-04

    Logged In: YES
    user_id=251681

    First, please note that there's no intrinsic reason why an
    extension function that works with one processor should work
    in the same way with another. Extension functions are very
    much implementation-defined.

    To use DOM nodes with Saxon, the main precondition is that
    you must have saxon8-dom.jar on your classpath. Without
    this, DOM objects will simply not be recognized as such, and
    I think this might be what is happening in your case.

    This particular failure is occurring at compile time, so
    another possibility is that the type checking for extension
    functions is getting things wrong. From looking at the code,
    it seems DOM's NodeList is recognized specially at run-time
    but not at compile time (every other object model uses
    regular Java collection objects...) Try calling the
    extension function and assigning the result to a variable:

    <xsl:variable name="nodes" select="ext:nodelist()" as="node()*"/>
    <xsl:for-each select="$nodes">

    Finally: although Saxon tries hard to coexist with DOM, it's
    not an easy marriage. There are all sorts of places where
    the differences between the two data models hit you, and
    performance is not particularly good. If there's a different
    way of designing your application, use it.

     
  • Logged In: NO

    I need to use both Xalan and Saxon at least for some
    transitional time.

    I worked around this problem by using recursive template
    call instead of for-each loop. I guess it brings access to
    the NodeList outside of scope for compile time
    optimalizations/checks.

    Another issue I hit was that
    net.sf.saxon.om.FastStringBuffer does not override equals()
    and hashCode() so using string() or normalize-space() as key
    for map does not work as one would expect, but I can deal
    with it.

    Also Xalan report error in compile time when there is no
    method matching the extension function. With Saxon I can set
    configuration.setTraceExternalFunctions(true) and grep
    stderr for it, but it will be nice to have some API so it is
    possible to catch such errors in the compile time.

    Anyway, thanks for the quick response, thats another reason
    why to switch to Saxon.

     
  • Michael Kay
    Michael Kay
    2006-08-04

    Logged In: YES
    user_id=251681

    I worked around this problem by using recursive template
    call instead of for-each loop.

    As a matter of interest, did you try the other approach I
    suggested of using a variable with a declared type?

    Another issue I hit was that
    net.sf.saxon.om.FastStringBuffer does not override equals()
    and hashCode()

    Unfortunately part of the specification of the Java
    interface CharSequence is that different implementations of
    CharSequence can't be compared using equals(). In fact,
    Saxon never compares strings for equality using the Java
    semantics: the XPath semantics require use of a collation.
    And FastSringBuffer is designed only for internal use.

    Also Xalan report error in compile time when there is no
    method matching the extension function.

    The XSLT 1.0 specification says it's not an compile-time
    error to have a reference to a function that doesn't exist:
    see 14.2 "An XSLT processor must not signal an error merely
    because an expression contains an extension function for
    which no implementation is available.". In XSLT 2.0, this
    becomes a compile-time error unless the stylesheet specifies
    version="1.0", in which case backwards compatibility comes
    into force: see J1.3 rule 6 "It is normally a static error
    if an XPath expression contains a call to an unknown
    function. But when backwards compatible behavior is enabled,
    this is a non-recoverable dynamic error, which occurs only
    if the function call is actually evaluated.". This suggests
    (a) your stylesheet specifies version="1.0", and (b) Xalan
    is not implementing the XSLT 1.0 specification correctly.
    I'd suggest changing to version="2.0".

     
  • Libor
    Libor
    2006-08-04

    Logged In: YES
    user_id=1568328

    I tried your suggestion of using a variable with a declared
    type, I see warnings in logs

    Warning: on line 3440
    Required item type of value of variable $contribs is
    node(); supplied value has item type
    java:org.w3c.dom.NodeList. The expression can succeed only
    if the supplied value is an
    empty sequence.
    Warning: on line 3440 of
    file:///C:/deploy/HEAD/webapps/avma/templates/xsl/_midtier/_avma/runtime_Abstract.xsl:
    Warning: the only value that can pass type-checking is an
    empty sequence. Required item
    type of value of variable $contribs is node(); supplied
    value has item type
    java:org.w3c.dom.NodeList

    Despite warninigs code seems to work for Saxon, but Xalan
    outputs only first item in the loop. I have inside the loop
    <xsl:if test="position()!=last()">
    <xsl:text>, </xsl:text>
    </xsl:if>
    I can see comma after the first item, but there is no second
    pass through the loop, grrr, I don't even want to know why.

    Unfortunately part of the specification of the Java
    interface CharSequence is that different implementations
    of CharSequence can't be compared using equals()
    Well, there is only one implementation I was dealing with -
    FastSringBuffer, 2 FastSringBuffers instances are not equal
    even if they contain same text.

    In XSLT 2.0, function that doesn't exist becomes a
    compile-time error
    That's good to know, it's better to catch errors sooner than
    later. We do have xsl compile tests that save us trouble
    some times.

    We are abandoning Xalan for mainly for it's bugginess.
    Complexity and deficiency of xsl 1 leads to many java
    extension hacks and maintenance headache.

     


Anonymous


Cancel   Add attachments