Project

Profile

Help

ChildEnumeration doesn't update position

Added by Anonymous almost 15 years ago

Legacy ID: #7488203 Legacy Poster: Meelis Saluvee (dominioon)

The class NodeWrapper#ChildEnumeration extends AxisIteratorImpl, which must maintain property named position, but the ChildEnumeration class never updates it. As a result, when running XSL transformations using DOMSource, XSLT position() function doesn't work correctly. How to fix: remove property ix from ChildEnumeration and use position instead.


Replies (7)

Please register to reply

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7488266 Legacy Poster: Michael Kay (mhkay)

Thanks, you are quite correct. The problem seems to affect the corresponding iterators in all the external object models (DOM, XOM, JDOM etc). Your fix is apparently incorrect, however: ix represents the position among the DOM children, which is not the same as position(), because of the problem of handling adjacent text nodes in the DOM (which appear as a single node at the NodeInfo level). I'll write some test cases and publish a fix in due course.

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7488438 Legacy Poster: Michael Kay (mhkay)

I have not been able to reproduce the problem. Although ChildEnumeration does not maintain position, it is always wrapped in a Navigator.AxisFilter or Navigator.EmptyTextFilter which takes care of this. Can you supply a repro please?

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7492219 Legacy Poster: Meelis Saluvee (dominioon)

Hi! The code similar to the following one doesn't work in our system, the transformation result is <table><tr p="0"/><tr p="0"/><tr p="0"/></table> . import org.w3c.dom.Document; import junit.framework.TestCase; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.stream.StreamResult; import javax.xml.parsers.DocumentBuilderFactory; import java.io.StringReader; import java.io.StringWriter; public class PositionBug extends TestCase { private static final String XSL_1 = "<xsl:stylesheet version='1.0' " + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" + " <xsl:output method='xml' omit-xml-declaration='yes'/>" + " <xsl:template match='/'>" + " <tab>" + " <xsl:for-each select='//xmlItem'>" + " <row/>" + " </xsl:for-each>" + " </tab>" + " </xsl:template>" + "</xsl:stylesheet>"; private static final String XSL_2 = "<xsl:stylesheet version='1.0' " + " xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" + " <xsl:output method='xml' omit-xml-declaration='yes'/>" + " <xsl:template match='tab'>" + " <table>" + " <xsl:apply-templates/>" + " </table>" + " </xsl:template>" + " <xsl:template match='row'>" + " <tr>" + " <xsl:attribute name=&quot;p&quot;><xsl:value-of select=&quot;position()&quot;/></xsl:attribute>" + " </tr>" + " </xsl:template>" + "</xsl:stylesheet>"; private Document transformToDOM() throws Exception { Transformer transformer = createTransformer(XSL_1); StreamSource xmlSource = createSource(); Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); DOMResult result = new DOMResult(doc); transformer.transform(xmlSource, result); return doc; } private String secondTransform(Document dom) throws Exception { Transformer transformer = createTransformer(XSL_2); StringWriter out = new StringWriter(); StreamResult result = new StreamResult(out); transformer.transform(new DOMSource(dom), result); return out.toString(); } private Transformer createTransformer(String xsl) throws TransformerConfigurationException { StreamSource xslSource = new StreamSource(new StringReader(xsl)); System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl"); TransformerFactory transformerFactory = TransformerFactory.newInstance(); return transformerFactory.newTransformer(xslSource); } private StreamSource createSource() { return new StreamSource(new StringReader("<root>" + " <xmlItem/>" + " <xmlItem/>" + " <xmlItem/>" + "</root>")); } public void testTransformation() throws Exception { Document doc = transformToDOM(); String result = secondTransform(doc); assertEquals("<table><tr p=&quot;1&quot;/><tr p=&quot;2&quot;/><tr p=&quot;3&quot;/></table>", result); } }

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7492382 Legacy Poster: Michael Kay (mhkay)

Thanks for this. I'll investigate and get back to you.

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7493124 Legacy Poster: Michael Kay (mhkay)

It seems I fixed this in my development branch "by accident", i.e. by a change to the code for an unrelated reason. I'll raise a patch for the 9.1 branch. I have a feeling ChildEnumeration is not the only iterator affected by the problem.

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7493498 Legacy Poster: Meelis Saluvee (dominioon)

Hi! Thanks for the quick fix :)! I briefly checked classes extending AxisIteratorImpl and they all seemed to update position property. But of course there are more iterators :P.

RE: ChildEnumeration doesn't update position - Added by Anonymous almost 15 years ago

Legacy ID: #7493609 Legacy Poster: Michael Kay (mhkay)

I don't think all iterators extending AxisIteratorImpl do maintain position - for example Navigator.AncestorEnumeration doesn't. But I haven't found any cases where such iterators are used without being wrapped in a Navigator.AxisFilter. So the code isn't very robust, but I haven't found any more bugs. I think it would be better if Navigator.BaseEnumeration took responsibility for maintaining position().

    (1-7/7)

    Please register to reply