This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 16184 - [FO30] fn:path() should support fragments as well as documents
Summary: [FO30] fn:path() should support fragments as well as documents
Status: CLOSED FIXED
Alias: None
Product: XPath / XQuery / XSLT
Classification: Unclassified
Component: Functions and Operators 3.0 (show other bugs)
Version: Working drafts
Hardware: All All
: P2 normal
Target Milestone: ---
Assignee: Michael Kay
QA Contact: Mailing list for public feedback on specs from XSL and XML Query WGs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-03-01 19:15 UTC by Eric van der Vlist
Modified: 2012-07-04 05:58 UTC (History)
2 users (show)

See Also:


Attachments

Description Eric van der Vlist 2012-03-01 19:15:16 UTC
For the fn:path() function the spec says that "An error is raised [err:FODC0001] if $arg, or the context item if the second argument is absent, is a node in a tree whose root is not a document node."

This distinction makes that function difficult to use on a node set variable because you don't always know if it comes from a document or a fragment.

I reckon that the XPath expression is more concise when the node comes from a document, but couldn't it still be constructed when the node comes from a fragment by using "ancestor-or-self::node())[1]" (or the root() function) to access the root node and adding the relative XPath from the root to the current node?

Thanks,

Eric
Comment 1 Michael Kay 2012-03-20 18:35:18 UTC
Preliminary discussion on 20 March 2012 reached no conclusion; members want to give it more thought.
Comment 2 Michael Kay 2012-03-27 17:38:48 UTC
I was asked to put together a proposal for the detailed rules. Here is the proposal:

Change the paragraph that reads:

<old>
Otherwise, the function constructs a string that consists of a sequence of steps, one for each ancestor-or-self of $arg other than the document node. Each step consists of the character "/" followed by a string whose form depends on the kind of node selected by that step, as follows:
</old>

to:

<new>
Otherwise, the function constructs a string that consists of a sequence of steps, one for each ancestor-or-self of $arg other than the root node. This string is prefixed by "." if the root node is not a document node. Each step consists of the character "/" followed by a string whose form depends on the kind of node selected by that step, as follows:
</new>

Delete the error condition.

Add a note:

<note>
Note that if $arg is node that has neither a parent nor children (for example, a parentless attribute node) then the result of fn:path() will be the string ".". If the root node is an element node, then the root will be represented in the path by a first step of ".", without any indication of the element name.
</note>

Add examples of use with trees whose root is other than a document node.

(Eric, please indicate whether this specification would satisfy the use cases you had in mind.)
Comment 3 Eric van der Vlist 2012-03-27 18:04:58 UTC
(In reply to comment #2)

> <new>
> Otherwise, the function constructs a string that consists of a sequence of
> steps, one for each ancestor-or-self of $arg other than the root node. This
> string is prefixed by "." if the root node is not a document node. Each step
> consists of the character "/" followed by a string whose form depends on the
> kind of node selected by that step, as follows:
> </new>

.../...

> (Eric, please indicate whether this specification would satisfy the use cases
> you had in mind.)

Use cases I had in mind are for variable defined as fragments, for instance in XSLT:

<xsl:variable name="fragment" as="node()">
<foo>
 <bar/>
</foo>
</xsl:variable>

Let's say I call a template or a user defined function on one of its node, let's say the <bar/> element, this template or function may need to call the fn:path function to determine an XPath expression that identifies this element when executed on one of the nodes of the same fragment.

As far as I understand your proposal, the function would return "./foo/bar". This would work if the path is evaluated on the $fragment variable, but in my example the template or function doesn't know about this variable.

Returning "root()/foo/var" would be an option, except that root() being a function you couldn't use that to generate XSLT templates and my preference would be that the fn:path function returns "ancestor-or-self::node())[1]/foo/bar".

This is verbose but should work everywhere. 

The wording could be:

<newer.new>
Otherwise, the function constructs a string that consists of a sequence of
steps, one for each ancestor-or-self of $arg other than the root node. If 
the root node is not a document node, this string is prefixed by 
"ancestor-or-self::node())[1]" . Each step consists of the character "/"
followed by a string whose form depends on the kind of node selected by that step, as follows:
</newer.new>

It seems to me that this would make the result coherent between documents and result trees on one hand and node fragments on the other hand in that the XPath expression that you get from the function can be executed over any of the nodes in the document or fragment to identify one specific node (and that's what I think this function is really useful for).

Does it makes sense?

Eric
Comment 4 Michael Kay 2012-03-28 20:59:13 UTC
> As far as I understand your proposal, the function would return "./foo/bar".
> This would work if the path is evaluated on the $fragment variable, but in my
> example the template or function doesn't know about this variable.
> 
> Returning "root()/foo/var" would be an option, except that root() being a
> function you couldn't use that to generate XSLT templates and my preference
> would be that the fn:path function returns
> "ancestor-or-self::node())[1]/foo/bar".
> 

In your example there should be no "/foo" step, since the foo element is not a child of anything.

I think I can see why you want a path that works regardless where in the tree you are currently positioned, rather than requiring you to be positioned at the root. But I don't understand why ((ancestor-or-self::node())[1] is preferable to root().

Neither of these works as an XSLT pattern. If we want to generate something that works both (a) as a pattern that selects the original node, and only the original node (which is a use case I hadn't thought of), and (b) as a path expresion that selects the original node, and only the original node, starting from an origin anywhere within the tree, then it would have to be something rather clumsy. Perhaps the cleanest would be for us to allow root() at the start of a pattern, and then generate root()[self::foo]/bar[1].
Comment 5 Eric van der Vlist 2012-03-28 21:15:28 UTC
(In reply to comment #4)

> In your example there should be no "/foo" step, since the foo element is not a
> child of anything.

Yes, of course.
 
> I think I can see why you want a path that works regardless where in the tree
> you are currently positioned, rather than requiring you to be positioned at the
> root. But I don't understand why ((ancestor-or-self::node())[1] is preferable
> to root().
> 
> Neither of these works as an XSLT pattern. If we want to generate something
> that works both (a) as a pattern that selects the original node, and only the
> original node (which is a use case I hadn't thought of), and (b) as a path
> expresion that selects the original node, and only the original node, starting
> from an origin anywhere within the tree, then it would have to be something
> rather clumsy. Perhaps the cleanest would be for us to allow root() at the
> start of a pattern, and then generate root()[self::foo]/bar[1].

Agreed. To take my example, returning either "root()" or "root()[self::foo]" (more verbose but more self describing) to identify the <foo/> element and "root()/bar" or "root()[self::foo]/bar" would work for me.

Thanks,

Eric
Comment 6 Michael Kay 2012-05-29 08:21:43 UTC
Herewith a revised proposal.

First, the request talks of "fragments" and "node-set variables" which are not precise terms in our data model. The proposal here will allow fn:path to identify a node uniquely within the tree that contains it, whatever the node kind of the root node of this tree. It does not attempt to allow nodes to be identified relative to a variable whose value is a sequence of nodes: for example if $selectedEvents is a sequence of event nodes, it will not generate a "path" such as $selectedEvents[2]/self::event. The main reason for this is that it's difficult to come up with a function definition that works for this use case, given that the same node may appear multiple times within a sequence.

The proposal is as follows:

Change the paragraph that reads:

<old>
Otherwise, the function constructs a string that consists of a sequence of
steps, one for each ancestor-or-self of $arg other than the document node. Each
step consists of the character "/" followed by a string whose form depends on
the kind of node selected by that step, as follows:
</old>

to:

<new>
Otherwise, the function constructs a string that consists of a sequence of
steps, one for each ancestor-or-self of $arg other than the root node. This
string is prefixed by "root()" if the root node is not a document node. Each step
consists of the character "/" followed by a string whose form depends on the
kind of node selected by that step, as follows:
</new>

Delete the error condition.

Add a note:

<note>
Note that if $arg is a node that has neither a parent nor children (for example,
a parentless attribute node) then the result of fn:path() will be the string
"root()". If the root node is an element node, then the root will be represented in
the path by a first step of "root()", without any indication of the element name.
</note>

Add examples of use with trees whose root is other than a document node.
Comment 7 Andrew Eisenberg 2012-05-29 16:38:29 UTC
I would suggest that root() be expressed as Q{http://www.w3.org/2005/xpath-functions}root().
Comment 8 Michael Kay 2012-05-29 17:04:44 UTC
The WG agreed to adopt the proposal in comment #6 as modified by the proposal in comment #7.

Eric, if you are happy with this resolution please close the bug.
Comment 9 Eric van der Vlist 2012-07-04 05:58:53 UTC
That's perfect, thanks!