Thanks, Jeni. That works great in both Saxon and MarkLogic. And thanks for the explanation. I'm going to contact MarkLogic support about the behavior and see what comes of it.
-James -----Original Message----- From: [email protected] [mailto:[email protected]] On Behalf Of Jeni Tennison Sent: Thursday, January 13, 2011 12:25 PM To: General MarkLogic Developer Discussion Subject: Re: [MarkLogic Dev General] Differing element() & document-node() XSLT behavior in Saxon vs. MarkLogic Hi James, I believe that this is a MarkLogic bug, but you can probably work around it. You have: <xsl:template match="/" name="root"> <xsl:param name="count" select="1"/> <xsl:param name="document-tree"> <xsl:apply-templates select="/" mode="other"/> </xsl:param> ... </xsl:template> The $document-tree parameter should be set to a temporary tree (ie a document node with children determined by whatever you get by the <xsl:apply-templates />). See: http://www.w3.org/TR/xslt20/#temporary-trees which says: "A document node is created implicitly when evaluating an xsl:variable, xsl:param, or xsl:with-param element that has non-empty content and that has no as attribute." It looks as though MarkLogic isn't doing this, but it assigning to $document-tree whatever you get from the <xsl:apply-templates /> (ie an element node) rather than creating the implicit document node. You can probably work around it by explicitly including an as attribute and a xsl:document instruction as follows: <xsl:param name="document-tree" as="document-node()"> <xsl:document> <xsl:apply-templates select="/" mode="other"/> </xsl:document> </xsl:param> (Untested.) Cheers, Jeni On 13 Jan 2011, at 17:54, James Sulak wrote: > Hello, > > I've noticed that MarkLogic is very literal when it comes to the difference > between elements and document nodes in a way that surprised me when it came > to XSLT. A simple example: > > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > version="2.0"> > > <xsl:template match="/"> > <document-node /> > </xsl:template> > > <xsl:template match="/*"> > <root-element /> > </xsl:template> > > </xsl:stylesheet> > > When I call this stylesheet using xdmp:xslt-invoke("test.xslt", > document("test.xml")) I get the result <document-node />. When I call it > using xdmp:xslt-invoke("test.xslt", document("test.xml")/*), I get the result > <root-element />. > > That's fair enough I suppose, since Marklogic is strictly following the type > of the node passed to the XSLT. It makes it annoying to incorporate > already-existing XSLTs into Marklogic queries, since we will have to be very > careful to always pass in a document node to a transform, even when > constructing XML on the fly. This is also different than the behavior I'm > used to in eXist, which treated any XML passed to its transform:transform() > as a document. I like the eXist behavior better, but I can understand > thinking otherwise. > > However, this becomes a more serious problem when trying to incorporate > multi-stage transforms. The behavior in Saxon and MarkLogic differs enough > so that the transform must take into account the differing engines to get > consistent results. For example: > > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > version="2.0"> > > <xsl:template match="/" name="root"> > <xsl:param name="count" select="1"/> > <xsl:param name="document-tree"> > <xsl:apply-templates select="/" mode="other"/> > </xsl:param> > > <xsl:message > select="if ($document-tree instance of document-node()) > then 'document-node()' > else 'element()'"/> > > <xsl:choose> > <xsl:when test="$count lt 2"> > <xsl:call-template name="root"> > <xsl:with-param name="document-tree" > select="$document-tree"/> > <xsl:with-param name="count" select="$count + 1"/> > </xsl:call-template> > </xsl:when> > <xsl:otherwise> > <xsl:choose> > <xsl:when test="$document-tree instance of > document-node()"> > <xsl:message>For Saxon (document-node())</xsl:message> > <xsl:apply-templates select="$document-tree/node()"/> > </xsl:when> > <xsl:otherwise> > <xsl:message>For MarkLogic (element())</xsl:message> > <xsl:apply-templates select="$document-tree"/> > </xsl:otherwise> > </xsl:choose> > </xsl:otherwise> > </xsl:choose> > > </xsl:template> > > <xsl:template match="@*|node()" mode="#all"> > <xsl:copy> > <xsl:apply-templates select="@*|node()" mode="#current"/> > </xsl:copy> > </xsl:template> > > </xsl:stylesheet> > > This transform should recurse once and return the original XML. The specific > test input is unimportant, but I've been using: > > <root> > <child1/> > <child2/> > </root> > > When run in Saxon, I get this as my console output: > > document-node() > document-node() > For Saxon (document-node()) > > When I execute it in Marklogic, passing it a document-node, I get in the log: > > element-node() > element-node() > For MarkLogic (element()) > > If I leave out the xsl:when/xsl:otherwise, I either get infinite looping in > Saxon or lose the root element in MarkLogic, depending on whether I use > $document-tree/node() or $document-tree for the final apply-templates. > > I'm not confident enough in my XSLT/XPath knowledge to know when behavior is > "correct," but it looks to me that the Saxon behavior maintains the type > properly. > > In any case, is this a MarkLogic implementation bug or just a differing > interpretation of the spec? > > Thanks, > > James > > > _______________________________________________ > General mailing list > [email protected] > http://developer.marklogic.com/mailman/listinfo/general > -- Jeni Tennison http://www.jenitennison.com _______________________________________________ General mailing list [email protected] http://developer.marklogic.com/mailman/listinfo/general _______________________________________________ General mailing list [email protected] http://developer.marklogic.com/mailman/listinfo/general
