You are viewing a plain text version of this content. The canonical link for it is here.
Posted to j-users@xalan.apache.org by bp...@sneakemail.com on 2006/01/06 18:58:00 UTC

Xalan ignores DocumentFragment returned by extension function

Hello,

I'm currently working on an extension class for use in an XSL file.

The transformation I want to perform is the following:

Input fragment:
<floatlist>0 1 2 3 4 5 6 7 8</floatlist>

Output fragment:
<vec3 value="0 1 2"/>
<vec3 value="3 4 5"/>
<vec3 value="6 7 8"/>

As to my knowledge there is no way to get this working in XSLT directly 
(and because for the project behind it there is some more processing 
required than shown above anyway), I wrote an extension function to do 
this, and invoke it with this XSL fragment:

<xsl:for-each select="floatlist">
    <xsl:value-of value="ext:makevec3s(.)"/>
</xsl:for-each>

So the extension function is called for each <floatlist/> element, takes 
it's contents as a string, and creates a number of <vec3/> elements in a 
DocumentFragment instance.

However, although the function itself seems works fine, it appears as if 
Xalan simply discards the returned DocumentFragment.

I've included the source code and XML/XSL files at the end of this email

I'd be gratetful for any clues :)

Cheers,

Uwe


---- input.xml ----

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <floatlist>0 1 2 3 4 5 6 7 8</floatlist>
    <floatlist>9 10 11 12 13 14</floatlist>
</root>


---- exttest.xsl ----

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="xalanexttest.Ext" version="1.0">
    <xsl:template match="/">
        <vectors>
            <xsl:for-each select="root/floatlist">
                <xsl:value-of select="ext:makevec3s(.)"/>
            </xsl:for-each>
        </vectors>
    </xsl:template>
</xsl:stylesheet>


---- Ext.java ----

package xalanexttest;

import org.w3c.dom.*;
import org.w3c.dom.bootstrap.*;

public class Ext {

    static DOMImplementation domImpl;
    static Document doc;
    static {
        try{
            DOMImplementationRegistry reg = 
DOMImplementationRegistry.newInstance();
            domImpl = reg.getDOMImplementation("XML 1.0");
            doc = 
domImpl.createDocument("http://pachler.name/sibengine", "foo", null);
        } catch(ClassNotFoundException ex){
        } catch(InstantiationException ex){
        } catch(IllegalAccessException ex){
        }
    }
   
    /** Creates a new instance of Ext */
    public Ext() {
    }
   
    /**
     * @param args the command line arguments
     */
    public static void main(String[] argv){
        org.apache.xalan.xslt.Process.main(argv);
    }
   
    public DocumentFragment makevec3s(String in){
        DocumentFragment dfrag = doc.createDocumentFragment();
       
        // test float array, no need to show parsing code here
        float[] floats = {0, 1, 2, 3, 4, 5, 6, 7, 8};
       
        for(int i=2; i<floats.length; i+=3){
            Element v3Element = doc.createElement("vec3");
            String value = ""+floats[i-2]+' '+floats[i-1]+' '+floats[i];
            v3Element.setAttribute("value", value);
            dfrag.appendChild(v3Element);
        }
       
        return dfrag;
    }
   
}


---- output.xml - the output that is produced by Xalan-J ----

<?xml version="1.0" encoding="UTF-8"?>
<vectors xmlns:ext="xalanexttest.Ext"/>


Re: Xalan ignores DocumentFragment returned by extension function

Posted by David Bertoni <db...@apache.org>.
bpezpn502@sneakemail.com wrote:
> Hello,
> 
> I'm currently working on an extension class for use in an XSL file.
> 
> The transformation I want to perform is the following:
> 
> Input fragment:
> <floatlist>0 1 2 3 4 5 6 7 8</floatlist>
> 
> Output fragment:
> <vec3 value="0 1 2"/>
> <vec3 value="3 4 5"/>
> <vec3 value="6 7 8"/>
> 
> As to my knowledge there is no way to get this working in XSLT directly 
> (and because for the project behind it there is some more processing 
> required than shown above anyway), I wrote an extension function to do 
> this, and invoke it with this XSL fragment:
> 
> <xsl:for-each select="floatlist">
>    <xsl:value-of value="ext:makevec3s(.)"/>
> </xsl:for-each>
> 

First, you need to understand what xsl:value-of does:

http://www.w3.org/TR/xslt#value-of

"The xsl:value-of element is instantiated to create a text node in the 
result tree. The required select attribute is an expression; this 
expression is evaluated and the resulting object is converted to a 
string as if by a call to the string function."

Next, the string function:

http://www.w3.org/TR/xpath#section-String-Functions

"A node-set is converted to a string by returning the string-value of 
the node in the node-set that is first in document order. If the 
node-set is empty, an empty string is returned."

Next, the string-value of a root node:

http://www.w3.org/TR/xpath#root-node

"The string-value of the root node is the concatenation of the 
string-values of all text node descendants of the root node in document 
order."

Since your extension function doesn't create any text nodes, the 
string-value of the document fragment is an empty string.

However, looking at your expected output, you probably want to use 
xsl:copy-of, since you want to copy the structure of the document 
fragment to the result tree.

...

>      public DocumentFragment makevec3s(String in){
>        DocumentFragment dfrag = doc.createDocumentFragment();
>              // test float array, no need to show parsing code here
>        float[] floats = {0, 1, 2, 3, 4, 5, 6, 7, 8};
>              for(int i=2; i<floats.length; i+=3){
>            Element v3Element = doc.createElement("vec3");

You should be creating a namespace-aware DOM, by using createElementNS() 
and setAttributeNS().

Dave

Re: Xalan ignores DocumentFragment returned by extension function

Posted by Henry Zongaro <zo...@ca.ibm.com>.
Henry Zongaro/Toronto/IBM@IBMCA wrote on 2006-01-06 02:03:25 PM:
> I think you really want something like this, which worked for me:
> 
>    <xsl:for-each select="ext:makevec3s(.)/vec3">
>        <xsl:value-of select="@value"/>
>    </xsl:for-each>

Whoops!  I was thinking you were only interested in the string values 
returned in the attributes.  Of course xsl:copy-of is the right 
instruction to use instead of xsl:value-of, as David Marston and Dave 
Bertoni have already pointed out.

Thanks,

Henry
------------------------------------------------------------------
Henry Zongaro      Xalan development
IBM SWS Toronto Lab   T/L 969-6044;  Phone +1 905 413-6044
mailto:zongaro@ca.ibm.com


Re: Xalan ignores DocumentFragment returned by extension function

Posted by Henry Zongaro <zo...@ca.ibm.com>.
Hi, Uwe.

bpezpn502@sneakemail.com wrote on 2006-01-06 12:58:00 PM:
> Input fragment:
> <floatlist>0 1 2 3 4 5 6 7 8</floatlist>
> 
> Output fragment:
> <vec3 value="0 1 2"/>
> <vec3 value="3 4 5"/>
> <vec3 value="6 7 8"/>
> 
> As to my knowledge there is no way to get this working in XSLT directly 

It might be slightly complicated, but not impossible - but who knows with 
the additional processing you mention below.

> (and because for the project behind it there is some more processing 
> required than shown above anyway), I wrote an extension function to do 
> this, and invoke it with this XSL fragment:
> 
> <xsl:for-each select="floatlist">
>     <xsl:value-of value="ext:makevec3s(.)"/>
> </xsl:for-each>

The xsl:value-of will print the string value of the first node in the node 
set returned by ext:makevec3s(.), which is an empty string in this case. I 
think you really want something like this, which worked for me:

   <xsl:for-each select="ext:makevec3s(.)/vec3">
       <xsl:value-of select="@value"/>
   </xsl:for-each>

Thanks,

Henry
------------------------------------------------------------------
Henry Zongaro      Xalan development
IBM SWS Toronto Lab   T/L 969-6044;  Phone +1 905 413-6044
mailto:zongaro@ca.ibm.com


Re: Xalan ignores DocumentFragment returned by extension function

Posted by da...@us.ibm.com.
Uwe wrote:

>Output fragment:
><vec3 value="0 1 2"/>
>
>...I wrote an extension function to do 
>this, and invoke it with this XSL fragment:
><xsl:value-of value="ext:makevec3s(.)"/>
>...So the extension function...
>creates a number of <vec3/> elements...

The first step is to try xsl:copy-of instead of value-of.
Value-of is designed to emit a text node. Copy-of will emit
a whole sequence of nodes with attributes and children.
.................David Marston