Re: Formal syntax of XPointer

Christopher R. Maden <crism@lexica.net> wrote:
>
> XPointer modifies the XPath grammar to have
> 
> NodeType ::= 'comment'
>               | 'text'
>               | 'processing-instruction'
>               | 'node'
>               | 'point'
>               | 'range'
> 
> However, it does not change the NodeTest definition:
> 
> [7] NodeTest ::= NameTest
>                   | NodeType '(' ')'
>                   | 'processing-instruction' '(' Literal ')'
> 
> So as far as I can tell, point() is legal, but there's really no way of
> saying *which* point you want to refer to.

There isn't supposed to be. It merely tests whether the context location
is a point location (any point location). This is the same as in XPath,
where "comment()" tests whether the context node is a comment node,
"text()" tests whether it's a text node, etc.

However, you raise an interesting issue: how *do* you refer to a
particular point location? Specifically, given point location P defined by
container node C and index I, how do you construct an XPointer that yields
P? It sounds like a simple matter, and one that could easily arise in
applications, but I don't think there's a complete solution. Here are the
bits that I came up with.

    Let c denote an Expr that yields C, and i an Expr that evaluates to I.
    Construct p, an Expr that yields P.

    If P is a character-point:
        p1 = start-point(string-range(c,"",i+1,0))
    where the "0" is actually arbitrary.

    If P is a node-point, this almost works:
        p2 = start-point(range(c/node()[i+1]))
    but fails when P is the "last" point within C (I = #children of C).
    For that, you could use:
        p2 = end-point(range(c/node()[i]))
    which fails when P is the "first" point within C (I = 0).
    Combining those (fairly redundantly):
        p2 = (start-point(range(c/node()[i+1])) |
                end-point(range(c/node()[i  ])) )

    But can we combine those two cases (character-point and node-point)
    into a single expression? We can't just take the union:
        p = p1 | p2
    because when P is a node-point, p1 can yield a character-point != P.
    [Conversely, when P is a character-point, p2 will not yield anything,
    because the container node of a character-point cannot have children.]
    So we need an expression like:
        p = p1[if c isn't an element node or a root node] | p2
    But I don't think there's a predicate that fails exactly when a
    location is an element or root node. This:
        [not(self::* or .=/)]
    is close, except that "=" actually operates on string-values, so
    the predicate fails in a few cases where it shouldn't.

So that's as far as I got. The problem would be a lot easier to solve if
we were to define a new axis "points" which contains all the point
locations within the context node (i.e., all the point locations whose
container node is the context node). Then
    p = c/points[i+1]
would be the general solution.  But it may be too late to add something
that significant to the XPointer spec.

-Michael Dyck

Received on Saturday, 16 September 2000 19:08:51 UTC