Project

Profile

Help

Unexpected results when executing an ExtensionFunction returning a set of nodes

Added by John Weber over 5 years ago

Greetings,

I could use some help with a behavior I'm not understanding with an ExternalFunction which returns a list of nodes.

I've boiled it down to this example.

My Java code looks like this:

public class Test 
{
	private static ExtensionFunction example = new ExtensionFunction() {
		
		public QName getName() {
			return new QName("http://seastreet.com", "test");
		}

		public SequenceType getResultType() {
			return SequenceType.makeSequenceType(ItemType.ELEMENT_NODE, OccurrenceIndicator.ZERO_OR_MORE);
		}

		public SequenceType[] getArgumentTypes() {
			return new SequenceType[] {
			};
		}

		public XdmValue call(XdmValue[] arguments) throws SaxonApiException {
			StringBuffer strXml = new StringBuffer();
			strXml.append("<root>");
			strXml.append("<a>");
			strXml.append("<x>x value 1</x>");
			strXml.append("<y>y value 1</y>");
			strXml.append("<z>z value 1</z>");
			strXml.append("</a>");
			strXml.append("<a>");
			strXml.append("<x>x value 2</x>");
			strXml.append("<y>y value 2</y>");
			strXml.append("<z>z value 2</z>");
			strXml.append("</a>");
			strXml.append("</root>");

		    Processor proc = new Processor(false);
		    DocumentBuilder builder = proc.newDocumentBuilder();

		    // Load the XML document.
		    StringReader reader = new StringReader(strXml.toString());
		    XdmNode doc;
			try {
				doc = builder.build(new StreamSource(reader));
				XdmNode root = doc.children("root").iterator().next();
				Iterable<XdmNode> i = root.children();
				return new XdmValue(i);
			} catch (SaxonApiException e) {
				System.err.println("Error processing document: " + e.getMessage());
				System.err.println(strXml);
				return XdmEmptySequence.getInstance();
			}
		}
	};
	
    public static void main( String[] args ) throws SaxonApiException
    {
		Processor processor = new Processor(false);
		processor.registerExtensionFunction(example);
		XsltCompiler compiler = processor.newXsltCompiler();
		XsltExecutable stylesheet = compiler.compile(new StreamSource(new File("resources/test.xsl")));
		Serializer out = processor.newSerializer(System.out);
		out.setOutputProperty(Serializer.Property.METHOD, "xml");
		out.setOutputProperty(Serializer.Property.INDENT, "yes");
		Xslt30Transformer trans = stylesheet.load30();
		trans.transform(new StreamSource(new StringReader("<root/>")), out);
    }
}

My XSL looks like this:

<xsl:stylesheet version="1.0" 
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:sst="http://seastreet.com">
	<xsl:template match="/">
OUTPUT:
<xsl:for-each select="sst:test()">
<xsl:text>&#10;</xsl:text>
**************************
copy-of for item
<xsl:copy-of select="current()"/>
**************************
name(for item): <xsl:value-of select="name(.)"/>
**************************
for-each child:
<xsl:for-each select="./*">
<xsl:value-of select="name(.)" />: <xsl:value-of select="."/><xsl:text>&#10;</xsl:text>
</xsl:for-each>
**************************
./x: <xsl:value-of select="./x"/>
./y: <xsl:value-of select="./y"/>
./z: <xsl:value-of select="./z"/>
</xsl:for-each>
**************************
</xsl:template>
</xsl:stylesheet>
</pre>

And my output looks like this:

OUTPUT:


**************************
copy-of for item
<a>
   <x>x value 1</x>
   <y>y value 1</y>
   <z>z value 1</z>
</a>
**************************
name(for item): a
**************************
for-each child:
x: x value 1
y: y value 1
z: z value 1

**************************
./x: 
./y: 
./z: x value 1

**************************
copy-of for item
<a>
   <x>x value 2</x>
   <y>y value 2</y>
   <z>z value 2</z>
</a>
**************************
name(for item): a
**************************
for-each child:
x: x value 2
y: y value 2
z: z value 2

**************************
./x: 
./y: 
./z: x value 2
**************************

The problem is accessing the elements of the XML using xpath. Note that when I iterate over all children of the node, I see each child element and its value as I expect. When I try to obtain the value directly with xpath expressions selecting the child nodes I do not get the values I expect. Note that ./x and ./y both appear empty and ./z appears to have the value I would expect for ./x

I must be doing something basically wrong, but I can't figure out what it is.

Thanks for any help you can offer.


Replies (3)

Please register to reply

RE: Unexpected results when executing an ExtensionFunction returning a set of nodes - Added by John Weber over 5 years ago

P.S. Poking around on the forum a bit more I got the bright idea to try

./x: <xsl:value-of select="./*[local-name() = 'x']"/>
./y: <xsl:value-of select="./*[local-name() = 'y']"/>
./z: <xsl:value-of select="./*[local-name() = 'z']"/>

which returns the expected values. I still don't understand why ./x, ./y, and ./z don't however.

I probably should have mentioned I'm using Saxon-HE 9.9.1-2

Thanks again

RE: Unexpected results when executing an ExtensionFunction returning a set of nodes - Added by Michael Kay over 5 years ago

The problem is that the nodes built using the extension function are constructed with a different Processor, and hence a different name pool, from the one used to compile the stylesheet; so the integer codes used for names in the document are different from the integer codes used for the same names in the stylesheet.

Saxon generally does checks when a value is passed to a stylesheet (for example, as a stylesheet parameter), that the name pool used for the nodes in the value is the same as the name pool used for the stylesheet. It seems these checks are being done for reflexive extension functions, but not for integrated extension functions. I'll raise an issue on this.

To fix the problem, you should avoid creating a new Processor within the extension function, and instead use the one created by the containing application.

RE: Unexpected results when executing an ExtensionFunction returning a set of nodes - Added by John Weber over 5 years ago

Excellent. Thank solved my problem. Thank you very much.

    (1-3/3)

    Please register to reply