RxPath Specification Proposal

Authors
Adam Souzis - asouzis@users.sf.net
Status
Initial Draft - Last Revised Dec 12, 2004
Notice
This document is the inital draft of a proposal, its goal is to get feedback on overall approach and specific issues.
Abstract
This specification defines RxPath, a mapping between the RDF Abstract Syntax to the XPath Data Model.

Table of Contents


1 Introduction
    1.1 RxPath By Example
    1.2 Conventions and Terminology
2 Requirements
3 Data Model
    3.1 Subject Element
    3.2 Blank Nodes
    3.3 Predicate Elements
    3.4 Object Nodes
    3.5 Recursive Nodes
    3.6 RDF Containers and Collections
    3.7 Namespaces and QNames
    3.8 Modifications to the Data Model
4 RxPath Expression Semantics
    4.1 Circular References
    4.2 Name Tests
    4.3 String Value
    4.4 Axes
    4.5 Node identity
    4.6 Core Functions
5 RxSLT
    5.1 Patterns
    5.2 xsl:copy-of
6 RxUpdate
    7 xupdate:if
    7.1 xupdate:message

Appendices

A Open Issues
B Normative References
C Other References
D Commentary
    D.1 deviation from XPath semantics
        D.1.1 descendant axis
    D.2 Special handling of RDF
        D.2.1 containers and collections
    D.3 Miscellaneous


Introduction

RxPath is a language for addressing parts of a RDF model. It is syntactically identical to XPath 1.0 and is very similar semantically. Each Step in a RxPath expression corresponds to navigating the node and edge in a graph representing a collection of RDF statements. This is achieved by mapping RDF's abstract syntax to XPath's Data Model. This is done by mapping a collection of RDF statements (a RDF model) into a tree where the top-level nodes represent all the resources in the model, their children all the predicates and all the objects as the predicates' children.

There have been other attempts at mapping RDF to the XPath data model (see references below for some). Generally, these mappings have been either syntactic, such as transformations of RDF/XML that yield to consistent querying, or semantic, such as building a new shared model for representing both XML and RDF. The approach here is essentially syntactic but the transformation is of the abstract RDF syntax, not the RDF/XML serialization, and the result can be an impossible structure (i.e. an infinitely deep tree), so any implementation of RxPath must take into account the semantics of the RDF model for that and other reasons.

RxPath By Example

The following examples illustrate RxPath. They are based on the example RDF statements found in RDF Syntax, include the namespace prefixes used in those examples.

  • Example 1 - This RxPath expression returns a nodeset of all the resources in the model:
  • /*

  • Example 2 - This RxPath expression returns a nodeset of all the predicates in the model (and therefore all the statements):
  • /*/*

    The next 2 examples demonstrate how Name Test matches the type of a resource or the property name of a predicate:

  • Example 3 - This expression returns all the resource with the rdf:type of class ex:Document:
  • /ex:Document

  • Example 4 - This expression returns the objects of all the property dc:title:
  • /*/dc:title/*

  • Example 5 - This expression finds the full name of all the people that are editors of a resource:
  • /*/ex:editor/*/ex:fullName/*

    Note how the expression is evaluated as if object node has the same children as its equivalent top-level resource node.

    RxPath defines resource elements (subject and object) as having a string value equal to the resource's RDF URI reference (i.e. the value of its rdf:about attribute)

  • Example 6 - Find all objects of the resource with URI reference "http://example.com/example#foo":
  • /*[.="http://example.com/example#foo"]/*/*

  • Example 7 - Find all the statements with a dc:title predicate and an object which a literal equal to "A marvelous thing"
  • /*/dc:title[.="A marvelous thing"]

    Here the string value of the predicate element follows the XPath rule, thus matching the object value (its child)

    Two more similar examples:

  • Example 8 - All resources with a property rdfs:label with value "my label":
  • /*[rdfs:label='my label']

  • Example 9 - Find all the statements with that have the resource "http://example.com/example#bar": as its object:
  • /*/*[.='http://example.com/example#bar']

    RxPath expressions can follow transitive properties by using the descendant axis:

  • Example 10 - Find all the decendant files of a folder named "foldername":
  • /fs:Folder[fs:file-name="foldername"]//fs:has-child/fs:File

    Inverse transitive queries can be done the same way:

  • Example 11 - Find all the ancestor folder(s) of the file named "filename":
  • /fs:Folder[.//fs:has-child/fs:File[fs:file-name="filename"]]

  • Example 12 - A more complicated expression that does the same thing but returns a nodeset ordered by the ancestor relation.
  • (//fs:has-child/fs:File[fs:file-name="filename"])[last()]/ancestor::fs:has-child/parent::fs:Folder


    Conventions and Terminology

    Through out this document anytime a QName appears with the prefix "rdf" it can be assumed that the namespace URI for the QName is "http://www.w3.org/1999/02/22-rdf-syntax-ns#".

    Mentions of XPath always refer to XPath 1.0.

    The uses of "SHOULD", "MAY", and "MUST" are defined in accordance with RFC 2119 - "Key words for use in RFCs to Indicate Requirement Levels".



    Requirements

    The following requirement drove the design described here:

    1. MUST be syntactically identical to XPath.
    2. MUST place no constraints on the underlying RDF Model
    3. All information from the RDF Model MUST be available in the RxPath Data Model
    4. SHOULD enable efficient processing, in particular SQL
    5. SHOULD be conform closely to ones expectations of how a XPath expressions behave and also follow an intuitive picture of navigating an RDF model visualized as a graph.


    Data Model

    This section describes how to map a given an RDF Model to a representation as an abstract XML document as defined by the XPath Data Model. Construct an XML document from a RDF model:

    Subject Element

    For each resource that appears in the RDF model, create an element as a child of the Root node. (This includes resources that appear as either the subject, predicate, or object of the statements in the model.) Each element has an attribute whose namespace URI is "http://www.w3.org/1999/02/22-rdf-syntax-ns#" and local name is "about" and whose value is equal to the resource's RDF Uri Reference. There is one and only one element for each resource and they sibling order is based on sorting their RDF URI References. The name of each element is "rdf:Description" -- however, see section ?? below for special Name Test rules for matching the element name. We refer to these elements as "Subject Elements".


    Blank Nodes

    Each distinct blank node in a RDF model is replaced with an URI reference that is generated by appending a unique identifier to "bnode:". A RxPath processor SHOULD report an error if a RDF model has a resource with a RDF URI reference that begins with this string. Formally, a RxPath processor always operates on a ground RDF graph produced by the Skolemization of the RDF graph.


    Predicate Elements

    For each Subject Element one child element is created for each statement in the RDF model that has the Subject Element's RDF URI reference as the statement's subject. This child element is referred to here as a "Predicate Element". The name of the child element will be QName based on the statement's predicate URI reference (i.e. the property URI). (See section QName mapping). The predicate URI reference will also appear as the value of an attribute named "uri".

    The follow attributes may also appear:

    1. If the object of the statement is a literal the Predicate Element may have rdf:datatype and/or xml:lang attributes.
    2. If the Predicate Element is named rdf:first or rdfs:member, it will have a listID (no namespace URI) attribute whose value is described in the list section below.

    Note

    put listID in a namespace? renamed is to memberID?

    Note

    A model can have more than one resource that reifies the same statement -- in that case, which one should the "rdf:ID" attribute be set to?

    The sibling order of the predicate element is determined by sorting the tuple (element namespace URI, element local name, element string value) except in the special cases "rdfs:member" and "rdf:first" Predicate Element (see below).


    Object Nodes

    Each predicate element will have children nodes based on the object of its corresponding statement:

    1. If the object of the statement is a literal text node, the child will be a text node. If the literal is xml (i.e. its rdf:datatype is http://www.w3.org/2000/01/rdf-schema#XMLLiteral) the string-value of the text node will be within the lexical space defined in RDF Abstract Syntax (see section 5).
    2. If the object of the statement is a resource, the child will be an Recursive Node equivalent to its corresponding Subject Element (see section below).


    Recursive Nodes

    Each Object Element is almost completely equivalent its corresponding Subject Element -- thus if the resource is the subject of a statement, the Object Element will have Predicate Elements as children, which in turn may have Object Element as its children and so on. The only attributes that will be differ are its parent and in the case Object Nodes, its siblings (it will not have any). See the section on "Circular References" below on how to handle circular references of recursive nodes.


    RDF Containers and Collections

    To provide more natural and expressive queries, RxPath provides special case mappings for RDF Collections and Containers.

    A Subject Element whose rdf:type is rdf:Seq, rdf:Bag or rdf:Alt will have Predicate Element children with a URI reference equivalent to rdfs:member, not rdf:_1, rdf:_2, etc. The sibling order of these children will be ordering by the ordinal value implied by the rdf:_n property names. The Predicate Element MUST have a listID attribute whose value is equal to its rdf:_n predicate.

    A Subject Element whose rdf:type is rdf:List will have a child Predicate Element named rdf:first for each item in the list, with the sibling order corresponding to the order of the items in the list. More precisely, the child Predicate Elements are added (in order) by transitively following the rdf:rest predicate of the rdf:List resource, selecting the rdf:first predicate of each rdf:List that is object of the current rdf:rest statement. Only the rdf:List resource at the head list will appear as a Subject Element in a RxPath Document, the other recursive list resources SHOULD NOT, unless other statements in the RDF model refer to it. rdf:rest statements MUST NOT appear in the RxPath Document. A RxPath implementation MUST add a listID attribute to each rdf:first Predicate Element, with the attribute's value equal to the URI reference of the recursive list resource that is the subject of predicate. (Thus the first rdf:first Predicate Element of a list will have listID equal to the Subject Element URI reference.)

    (Note: to express an empty list, you may use the rdf:nil resource in place of the list resource as the object of the predicate -- cf. RDF Syntax 7.2.19.)

    (Note also that the child Object Element can be either text or element nodes (literals are valid rdf:list items despite the fact rdf:parseType="Collection" can not express that).)

    Note

    Should we call the "rdf:first" predicate something else? "rdf:first" matches the RDF spec but is unintuitive for predicate meaning list membership. We could reuse "rdf:li" or add a "rxpath:item".

    If RDF container or collection resource is the subject of statements that don't determine membership (i.e. one whose predicate is not rdf:first or rdf:_n, typically, for example, an rdf:type statement), those statements will appears as child Predicate Elements before the membership Predicate Elements, in the standard order for Predicate Elements as described in that section above.


    Namespaces and QNames

    QNames are converted to URI references by concating the QName's namespace name (the URI) with the local name, unless the local name is a sequence of one or more '_' characters, in which case the local name is substituted with a possibly empty string equal to the local name minus one of the '_'. This rule enables QNames to be created for URIs whose last character of a URI is not an XML NameChar or otherwise can't be transformed into a QName.

    The RxPath processor MUST provide a way to specify a set of prefixes to namespace name (URI) mappings. Those mappings MUST be used for Name Tests (see below) and for Predicate Element names. When an RxPath processor encounters a URI reference that can not be mapped to a QName it SHOULD generate an namespace mapping. As implied by the QName rule above, if the processsor can not find a good point to split the URI, the local name will be '_'; conversely, if a split if found and the characters after the split consist solely of one or more '_', a '_' should be appended to the local name.

    Note

    Should we say anything about where and what Namespace nodes should appear in the data model?


    Modifications to the Data Model

    If a processor allows the data model to modified, e.g. via support for RxUpdate or through a programmatic API such as a XML DOM, the resultant DOM should conform to the constraints on the data model described here -- for example, one could not add comment nodes. If a recursive node is modified referenced node will also be modified.

    Note

    Add a constaint that statements can not be modified only added or deleted?



    RxPath Expression Semantics

    This section describes how XPath Expressions are applied to the RxPath data model. RxPath expressions are evaluated exactly as if they were an XPath expressions being applied to an XML document except for the modifications described in this section.

    Circular References

    We define 2 modes of behavior for handling circular references (where the ancestor element has the same URI reference as the descendant, as in the case where subject of a statement is that same as its object). When the data model is navigated in the first mode, circularity-unchecked, circular references are not checked and therefore appear to generate an infinite number of descendant elements. When navigating in the second mode, circularity-checked, circular references are checked by walking up the element's anscestor axis up to the document root or a given top-most element, and if an Recusive element has an ancestor with the same URI reference at it does, the Recursive element will appear to have no children. Which mode is active depends on the context of the XPath expression -- in short, circularity-checked is active for the descendant, descendant-or-self,following, proceeding and following axes, and circularity-unchecked for all other axes.


    Name Tests

    A Node test that is a QName or of the form NCName:* matches a Subject or Object element when the statement <element URI reference> rdf:type <NodeTest URI reference> holds true, where the NodeTest URI reference is the URI obtained from its QName (as descibed above). If the node is a Predicate element, the Node Test matches when the NodeTest URI reference matches a property URI reference that subsumes the property represented by the element's URI reference. How these assertions are determined is up to the RxPath processor. An RxPath processor SHOULD support RDF Schema. In this case, the match will occur when the statement <element URI reference> rdfs:subPropertyOf <NodeTest URI reference> holds true (see RDFS entailment rule 6).


    String Value

    In RxPath, the string value of a Subject or Object element is its URI reference. The string value of a Document node (the root node) will be a URI that SHOULD represent the RDF model or source document. Otherwise, RxPath follows XPath. Note that a consequence of this rule is that the string-value of a Predicate element will be the string-value of its Object node -- either a literal or its URI reference.


    Axes

    RxPath constrains XPath's descendant axes (descendant, descendant-or-self, following, proceeding) in two ways.

    First, RxPath redefines how a Step that has one of these axis as its AxisSpecifier is evaluated. If a node doesn't match the Step's NodeTest then the node's descendants are not examined for matches. In other words, given a Step with a descendant axis, every ancestor of a matching node (up to the context node) will match NodeTest of the Step.

    Note

    Should this rule be extended to also cover the Step's Predicates in addition to the NodeTest? This would be more consistent and powerful. But we don't do this because it would extremely difficult to figure out the context position and context size for each predicate while evaluating the descendants, and changing the rules about how predicates affect the context would probably be too much of divergence from the XPath spec. So we're left with an inconsistency that can lead to subtle bugs.

    Second, a Step with one of the descendant axes will only examine Predicate Elements for a match, skipping past Subject and Object elements to only examine their children. An equivalent to this constraint also applies to Steps with an ancestor or ancestor-or-self axis (Subject and Object elements are skipped, only their parents is examined).

    When evaluating a Step with a descendant or descendant-or-self axis the RxPath processor MUST enter circularity-checked mode with the top-most ancestor of the circularity check set to the initial context node of the Step. When a Step's axis is following or proceeding, at every point in the document tree that the evaluation begins descending a branch the process must enter circularity-checked mode with the top-most ancestor of the circularity check set to the current node.

    In addition, RxPath changes how AbbreviatedAbsoluteLocationPath, AbbreviatedRelativeLocationPath, and PathExpr are expanded:

    If a RxPath expression contains a // and the AxisSpecifier of the expression's next Step is the child axis, the two steps are combined by replacing them with a Step having an AxisSpecifier of descendant and the second Step's NodeTest and Predicates.

    Informally: In XPath, the expression

    *//*[1]

    is an abbreviation of

    */descendant-or-self::node()/child::*[position()=1]

    In the RxPath, *//*[1] would be an abbreviation for

    */descendant::*[ispredicate()][position()=1]

    Note that an expression like *//previous-sibling::* or *//..

    would not have the descendant step combined with the next one, e.g. it would expand as:

    */descendant-or-self::node()[ispredicate()]/previous-sibling::*

    The combined effect of these rules leaves the descendant axis with a NameTest is equivalent to transitively following a predicate, e.g. *//has-child/* finds all (and only) the descendant children.


    Node identity

    Node identity (as defined in the XPath spec -- used to determine the uniqueness of nodes in a nodeset and by RxSLT's generate-id(), but not node equality) is the same as in XPath -- which implies every recursive node is different each other, even if they refer to same Subject Element.


    Core Functions

    RxPath processors MUST support all the core functions required by XPath. All functions behave the same as specified in XPath except for id(), which behaves the same except that the string tokens are treated as URI references and the look up function finds the Subject Element that match the URI reference.

    In addition a RxPath processor MUST support the following additional functions:

    Note

    should these functions be in an extension namespace?

  • boolean is-predicate(nodeset?) - This function returns true if all the nodes in the argument nodeset are Predicate Elements. If the nodeset is empty it returns false. If the argument is omitted, it defaults to a node-set with the context node as its only member.
  • boolean is-resource(nodeset?) - This function returns true if all the nodes in the argument nodeset are Subject or Object Elements. If the nodeset is empty it returns false. If the argument is omitted, it defaults to a node-set with the context node as its only member.
  • nodeset resource(nodeset?) - For each node in the argument nodeset, return the element that is the "nearest resource" to the node. If the node is a Subject or Object Element return self. If it is a Predicate Element return its parent (which will be a Subject or Object Element). If it is a text node then return is grandparent (a Subject or Object Element since a text node will always be a literal). If it is an attribute node, apply the above rules to its owner element. All other node types are removed from the resulting nodeset. If the argument is omitted, it defaults to a node-set with the context node as its only member.
  • string uri(nodeset?) - This function returns a URI reference computed, using the convertion rule in section ?? above, from the QName of the node in the argument node-set that is first in document order. If the argument node-set is empty or the first node has doesn't have a QName, an empty string is returned. If the argument is a string then the string is treated as a QName. If the argument is omitted, it defaults to a node-set with the context node as its only member.
  • string name-from-uri(string?) - This function returns the QName computed, using the convertion rule in section ?? above, by treating the argument as a URI reference and applying the DOM's current namespace to prefix mappings. If the argument is omitted, it defaults to the context node converted to a string, in other words the string-value of the context node. Calling this function may have the side-effect of updating the DOM's namespace to prefix mappings.
  • string local-name-from-uri(string?) - This function returns the local part of the QName computed, using the convertion rule in section ?? above, by treating the argument as a URI reference and applying the DOM's current namespace to prefix mappings. If the argument is omitted, it defaults to the context node converted to a string, in other words the string-value of the context node. Calling this function may have the side-effect of updating the DOM's namespace to prefix mappings.
  • string namespace-uri-from-uri(string?) - This function returns the namespace URI part of the QName computed, using the convertion rule in section ?? above, by treating the argument as a URI reference and applying the DOM's current namespace to prefix mappings. If the argument is omitted, it defaults to the context node converted to a string, in other words the string-value of the context node. Calling this function may have the side-effect of updating the DOM's namespace to prefix mappings.
  • boolean is-subproperty-of(object,object) - This function returns true if any of the resources specified in the first argument is a subproperty of the any of the property resources specified in the second argument. If the argument is a node-set, each node is converted to its string value, which is treated as the URI reference of a resource. Otherwise the argument is converted to its string value, which is treated as a URI reference. This function SHOULD return the same result as the equivalent Name Test for a Predicate Element. Note that in RDF Schema a property is a subproperty of itself.
  • boolean is-subclass-of(object,object) - This function returns true if any of the class resources specified in the first argument is an subclass of any of the class resources specified in the second argument. If the argument is a node-set, each node is converted to its string value, which is treated as the URI reference of a resource. Otherwise the argument is converted to its string value, which is treated as a URI reference. Note that in RDF Schema a class is a subclass of itself.
  • boolean is-instance-of(object,object) - This function returns true if any of the resources specified in the first argument is an instance of any of the class resources specified in the second argument. If the argument is a node-set, each node is converted to its string value, which is treated as the URI reference of a resource. Otherwise the argument is converted to its string value, which is treated as a URI reference. This function SHOULD return the same result as the equivalent Name Test for a Subject or Object Element.
  • nodeset get-statement-resources(nodeset?) - For each node in the argument nodeset that is a Predicate element, find any Subject elements whose URI reference is a rdf:Statement resource that reifies the Predicate element. Note that while the RDF/XML syntax only can express one reified statement resource per statement (through the rdf:ID attribute) it is possible and valid for a statement to have any number of reified statement resources.
  • nodeset rdfdocument(object, string?, nodeset?) - This function is equivalent to XSLT's document() function except it parses RDF and returns RxPath Document nodes instead of XML Document nodes. The first and third arguments are equivalent to document()'s first and second arguments, respectively, and the second argument is converted to a string that names the format of the RDF being parsed. The format names are implementation dependent but SHOULD include "rdfxml", "ntriples", and "unknown". If this argument is ommitted or "unknown", the implementation SHOULD try to figure out the format or raise an error if it can not. This function MAY only be available in the context of an XSLT or RXSLT processor.


  • RxSLT

    RxSLT is a language for transforming RDF to XML. It is syntactically identical to XSLT 1.0 and behaves as very similarly. A RxSLT processor behaves indentically to a XSLT 1.0 processor transforming a document whose data model conformed to the Data Model mapping described above; with the following exceptions:

    Patterns

    Patterns in RxSLT are identical to RxPath expressions that conform to the XLST pattern syntax, with the additional constraint that all Patterns must be absolute. In other words, we redefine XSLT's LocationPathPattern to:

    LocationPathPattern ::= '/' RelativePathPattern?


    xsl:copy-of

    Since RxSLT transforms RDF to XML, we need to define special behavior for xsl:copy-of to avoid adding Recursive Nodes to the result tree. xsl:copy-of behaves exactly like XSLT 1.0 except when the current node being copied is a Predicate Node (or a Recursive Node aliasing a Predicate Node) and it has a child Object Element node. In this case, instead of copying the child element, an attribute named rdf:resource with the value of the URI reference for the Object Element is added to the result tree.

    Note: xsl:copy behaves the same as in XSLT 1.0.



    RxUpdate

    RxUpdate is a language for updating an RDF model. It is syntactically and semantically identical to XUpdate Working Draft except for the changes described here.

    Note

    Todo! rdf:resource, garbage collection, white space nodes, other constraints, no atomicity requirement?, predicate elements with no children assumed to have an empty literals



    Open Issues

    See the various "note" paragraphs through out the document (denoted with the Note icon). In addition the following issues are still open questions:

    Should we specify anything how inferences and entailments appear in the model? For example, you probably don't want a query like '/*' to trigger an exhaustive inferring of every possible resource that could be inferred from the model (given an engine that can do that sort of thing), at least because that can be infinite (e.g. inferring reification entailments). What about the entailment rules that allocate a blank node for every name, including literals? That would make the results of queries like subject/predicate/* confusing when the object is a literal.


    Normative References

    • [XML] "Extensible Markup Language (XML) 1.0", Tim Bray, Jean Paoli, C. M. Sperberg-McQueen, 10 February 1998
    • [XML-NS] "Extensible Markup Language (XML) 1.0", T. Bray, D. Hollander, A. Layman, 14 January 1999
    • [XPath] "XML Path Language (XPath) Version 1.0", James Clark, Steve DeRose, 16 November 1999
    • [XSLT] "XSL Transformations (XSLT) Version 1.0", James Clark, 16 November 1999
    • [XUpdate] "XUpdate - XML Update Language", Andreas Laux, Lars Martin, 14 September 2000
    • [RDF-Concepts] "Resource Description Framework (RDF): Concepts and Abstract Syntax", Graham Kyle, Jeremy Carroll, 23 January 2003
    • [RDF-SEMANTICS] "RDF Semantics", Pat Hayes, 5 September 2003
    • [RDF-VOCABULARY] "RDF Vocabulary Description Language 1.0: RDF Schema", D. Brickley, R.V. Guha, 5 September 2003
    • [RFC2119] "RFC 2119 - Key words for use in RFCs to Indicate Requirement Levels", S. Bradner, March 1997

    Other References

    • [Syntactic-Web] "The Syntactic Web", Jonathan Robie, 2001
    • [Yin-Yang] "The Yin/Yang Web: XML Syntax and RDF Semantics", Peter Patel-Schneider, Jerome Simeon, 2002

    Commentary

    This section contain informal comments on the why certain approaches were taken.

    deviation from XPath semantics

    descendant axis

    The constraints on the descendant axis enable it to behave like a transitive join, an intuitive behavior for a RDF query language. Perhaps more importantly, the XPath rule would require the processor to exhaustively follow every statement with an resource as an object, a potentially extremely expensive approach. Also, placing the ispredicate() constraint on descendant and ancestor axes enables it to be possible to static analyze an RxPath expression to determine if each step is referring to a subject, predicate, or object. Without this it would be much more difficult efficiently implement many kinds RxPath implementations, for example, an RxPath -> SQL converter.



    Special handling of RDF

    containers and collections

    It would be very tedious to query lists without special mapping rules. For examples, here's an RxPath expression for selecting all the items in a list: /*/predicate/rdf:List//rdf:rest/../rdf:first/*. Compare that with /*/predicate/rdf:List/rdf:first/*. This assumes the descendant axis follows RxPath's rule (or else it would look far uglier!). Worse, there would be no way (as far I can figure) to have a single RxPath expression that selected, say, all the first or last items in the list in case where the predicate matches multiple predicates each with a list, e.g.: /*/predicate/rdf:List/rdf:first/*[1]



    Miscellaneous

    Why have an "uri" attribute on a Predicate Element when this will be the same value as calling the uri core function with a nodeset containing the Predicate Element? Because strings can't be members of nodesets in XPath, certain expressions are hard to do without the uri attribute, such as selecting property resources; e.g. /*[.=uri(/*/*)] won't work, but /*[.=/*/*/@uri] will (or, better, id(/*/*/@uri)).