Abstract
This document describes XPath extensions supported by Unicorn ECMAScript Interpreter (UESI).
Status of this document
This document forms part of the Unicorn ECMAScript Interpreter (UESI) Reference Manual.
Comments on this document may be sent to [email protected]
Table of contents
Appendices
1 Introduction
This document describes XPath extensions supported by Unicorn ECMAScript Interpreter (UESI).
2 Overview
XPath extensions provide built-in ECMAScript objects that support XPath expressions and node-sets. XPath extensions are built on the top of XML extensions and DOM extensions implemented by UESI.
NodeSet objects represent XPath node-sets.
Expr objects represent XPath expressions.
3 Conventions
Concepts and notation of the ECMA-262 Standard (ECMAScript Language Specification) are used in this document.
This document relies also on the concepts introduced in "Unicorn ECMAScript Interpreter Reference Manual. XML Extensions" and "Unicorn ECMAScript Interpreter Reference Manual. DOM Extensions".
4 XPath Objects
There are certain built-in XPath extension objects available whenever UESI begins execution of a program. One, the XPath object, is accessible as an initial property of the global object. Others are accessible as initial properties of the XPath object.
All XPath extension objects implement the semantics of native ECMAScript objects as specified in ECMA-262.
In every case, the length property of a built-in Function object described in this section has the attributes { DontEnum, DontDelete, ReadOnly } (and no others). Every other property described in this section has the attributes { DontEnum, DontDelete } (and no others) unless otherwise specified.
4.1 The XPath Object
The XPath object does not have a [[Construct]] property; it is not possible to use the XPath object as a constructor with the new operator.
The XPath object does not have a [[Call]] property; it is not possible to invoke the XPath object as a function.
The value of the internal [[Prototype]] property of the XPath object is the Object prototype. The value of the internal [[Class]] property of the XPath object is "XPath".
4.1.1 Constructor Properties of the XPath Object
4.1.1.1 NodeSet(...)
See "The NodeSet Constructor Called As Function" and "The NodeSet Constructor" .
4.1.1.2 Expr(...)
See "The Expr Constructor Called As Function" and "The Expr Constructor" .
4.2 NodeSet Objects
NodeSet objects represent XPath node-sets. Furthermore, each NodeSet instance provides also functionality of node-set iterator. For every NodeSet instance, current position and current node are available as object properties.
4.2.1 The NodeSet Constructor Called as a Function
Not supported in the current release of UESI. Reserved for the future.
4.2.1.1 XPath.NodeSet(...)
Not supported in the current release of UESI. Reserved for the future.
4.2.2 The NodeSet Constructor
When XPath.NodeSet is called as part of a new expression, it is a constructor: it initializes the newly created NodeSet instance.
4.2.2.1 new XPath.NodeSet([item1 [, item2 ...]])
If the NodeSet constructor is called without arguments, the empty node-set is assigned to the newly created NodeSet instance.
Otherwise let
be number of arguments. Let be -th argument. For each , 1 <= <= , create a node-set according to the following rules.If [[Class]] property is "XPath.NodeSet"), let be this node-set.
is a NodeSet instance (itsIf
is a DOM Node (it contains the DOM Node prototype in its prototype chain), let be a node-set that consists of this single node.If
is a DOM NodeList (it contains the DOM NodeList prototype in its prototype chain), let be a node-set that consists of all nodes that are contained in this node list.If
is a DOM NamedNodeMap (it contains the DOM NamedNodeMap prototype in its prototype chain), let be a node-set that consists of all nodes that are contained in this named node map.Otherwise the runtime error is generated.
Let
be the union of node-sets , 1 <= <= . Assign the node-set to the newly created NodeSet instance.If the result node-set is empty, set position property to 0 and current property to null.
Otherwise, set position property to 1 and current property to the DOM Node object that represents the first node in the node-set.
4.2.3 Properties of the NodeSet Constructor
The value of the internal [[Prototype]] property of the NodeSet constructor is the Function prototype object.
Besides the internal properties and the length property (whose value is 1), the NodeSet constructor has the following properties.
4.2.3.1 XPath.NodeSet.prototype
The initial value of the XPath.NodeSet.prototype is the NodeSet prototype object.
This property has the attributes { DontEnum, DontDelete, ReadOnly }.
4.2.4 Properties of the NodeSet Prototype Object
The NodeSet prototype object is itself a NodeSet object (its [[Class]] is "XPath.NodeSet"). It represents the empty node-set (contains no nodes).
The value of the internal [[Prototype]] property of the NodeSet prototype object is the Object prototype.
4.2.4.1 XPath.NodeSet.prototype.constructor
The initial value of XPath.NodeSet.prototype.constructor is the built-in NodeSet constructor.
4.2.4.2 XPath.NodeSet.prototype.reset()
This function resets the internal node-set iterator of this NodeSet instance.
If the result node-set is empty, set position property to 0 and current property to null.
Otherwise, set position property to 1 and current property to the DOM Node object that represents the first node in the node-set.
The function returns undefined value.
4.2.4.3 XPath.NodeSet.prototype.next()
This function selects advances the internal node-set iterator of this NodeSet instance.
If the result node-set is empty or the current node of the node-set is its last node, set position property to 0 and current property to null.
Otherwise, increase position property by 1 and set current property to the DOM Node object that represents the node in the node-set which is following the current node.
The function returns undefined value.
4.2.4.4 XPath.NodeSet.prototype.toString()
This function calculates and returns the XPath string value of the first node in the node-set specified by this NodeSet instance, or the empty string if the node-set is empty.
4.2.5 Properties of the NodeSet Instances
The value of the internal [[Prototype]] property of the NodeSet instance is the NodeSet prototype object.
The value of the internal [[Class]] property of the NodeSet instance is "XPath.NodeSet".
NodeSet instances inherit properties from their [[Prototype]] object, and also have the following propetrties.
4.2.5.1 current
This property references the DOM Node object that corresponds to the current node of the internal node-set iterator or null if the node-set is empty or iterator had reached end of the node-set.
This property has the attributes { DontDelete, DontEnum, ReadOnly }.
4.2.5.2 position
This number property contains the position number (started with 1) of the current node of the internal node-set iterator or 0 if the node-set is empty or iterator had reached end of the node-set.
This property has the attributes { DontDelete, DontEnum, ReadOnly }.
4.2.5.3 count
This number property contains number of nodes in the node-set associated with this NodeSet instance.
This property has the attributes { DontDelete, DontEnum, ReadOnly }.
4.3 Expr Objects
Expr objects represent XPath expressions.
4.3.1 The Expr Constructor Called as a Function
Not supported in the current release of UESI. Reserved for the future.
4.3.1.1 XPath.Expr(...)
Not supported in the current release of UESI. Reserved for the future.
4.3.2 The Expr Constructor
When XPath.Expr is called as part of a new expression, it is a constructor: it initializes the newly created Expr instance.
4.3.2.1 new XPath.Expr(source)
Let ToString( ). If is a valid XPath expression assign it to the newly created Expr instance. (For performance reasons, UESI compiles XPath expressions into internal code every time the new Expr instance is created). Otherwise, generate the runtime error.
be a string value computed by4.3.3 Properties of the Expr Constructor
The value of the internal [[Prototype]] property of the Expr constructor is the Function prototype object.
Besides the internal properties and the length property (whose value is 1), the Expr constructor has the following properties.
4.3.3.1 XPath.Expr.prototype
The initial value of the XPath.Expr.prototype is the Expr prototype object.
This property has the attributes { DontEnum, DontDelete, ReadOnly }.
4.3.4 Properties of the Expr Prototype Object
The Expr prototype object is itself a Expr object (its [[Class]] is "XPath.Expr"). The XPath expression "" (one that evaluates to the empty string) is associated with the Expr prototype.
The value of the internal [[Prototype]] property of the Expr prototype object is the Object prototype.
4.3.4.1 XPath.Expr.prototype.constructor
The initial value of XPath.Expr.prototype.constructor is the built-in Expr constructor.
4.3.4.2 XPath.Expr.prototype.eval(nodeSet)
This function evaluates the XPath expression.
If [[Class]] property is "XPath.NodeSet"), let be this node-set. The current position in the internal node-set iterator remains unchanged.
is a NodeSet instance (itsIf 1.
is a DOM Node (it contains the DOM Node prototype in its prototype chain), let be a node-set that consists of this single node. Set the current position in the internal node-set iterator toIf 1 if the node-set is not empty or to 0 otherwise.
is a DOM NodeList (it contains the DOM NodeList prototype in its prototype chain), let be a node-set that consists of all nodes that are contained in this node list. Set the current position in the internal node-set iterator toIf 1 if the node-set is not empty or to 0 otherwise.
is a DOM NamedNodeMap (it contains the DOM NamedNodeMap prototype in its prototype chain), let be a node-set that consists of all nodes that are contained in this named node map. Set the current position in the internal node-set iterator toOtherwise the runtime error is generated.
If the node-set
is empty, generate the runtime error.Otherwise, set the expression context as follows.
Set the context node to the current node of the internal iterator of
.Set the context position to the current position of the internal iterator of
.Set the context size to the number of nodes in
.Set the variable bindings to the empty set.
Set the function library to XPath core function library.
Use namespace declarations in scope on the context node (i.e., the current node of the internal iterator of
) as the set of namespace declarationsEvaluate the XPath expression associated with this Expr instance using the expression context defined above. Let
be the result of evaluation.If
is XPath boolean, return the equivalent ECMAScript boolean value.If
is XPath number, return the equivalent ECMAScript number value.If
is XPath string, return the equivalent ECMAScript string value.Otherwise position property to 0 and current property to null. Otherwise, set position property to 1 and current property to the DOM Node object that represents the first node in the node-set. Return the newly created NodeSet object.
is XPath node-set. Create a new NodeSet instance and assign this node-set to it. If the node-set is empty, set4.3.4.3 XPath.Expr.prototype.toString()
This function returns the string that contains a valid XPath expression equivalent to the XPath expression associated with this Expr instance.
4.3.5 Properties of the Expr Instances
The value of the internal [[Prototype]] property of the Expr instance is the Expr prototype object.
The value of the internal [[Class]] property of the Expr instance is "XPath.Expr".
Expr instances inherit properties from their [[Prototype]] object, and also have the following propetrties.
4.3.5.1 source
This property is a string value that contains a valid XPath expression equivalent to the XPath expression associated with this Expr instance.
This property has the attributes { DontDelete, DontEnum, ReadOnly }.
A References
B Examples
The following ECMAScript program tests various XPath expressions, using examples from XPath Recommendation. The pattern matching facility provided by XSLT extensions is demonstrated as well.
var sourceURI = "file://localhost/d/demo/uesi/xpath01.xml"; var d = parseDocument(sourceURI); var tests = new Array(); addTest(tests, "chapter", "child::para"); addTest(tests, "chapter", "para"); addTest(tests, "chapter", "attribute::name"); addTest(tests, "chapter", "@name"); addTest(tests, "chapter", "attribute::*"); addTest(tests, "chapter", "@*"); addTest(tests, "chapter", "descendant::para"); addTest(tests, "chapter", ".//para"); addTest(tests, "figure", "ancestor::para"); addTest(tests, "para", "ancestor-or-self::para"); addTest(tests, "para", "descendant-or-self::para"); addTest(tests, "para", "self::para"); addTest(tests, "para", "."); addTest(tests, "book", "child::chapter/descendant::para"); addTest(tests, "book", "chapter//para"); addTest(tests, "book", "child::*/child::para"); addTest(tests, "book", "*/para"); addTest(tests, "chapter", "/descendant::para"); addTest(tests, "chapter", "//para"); addTest(tests, "book", "/descendant::para/child::figure"); addTest(tests, "book", "//para/figure"); addTest(tests, "book", "descendant::para/child::figure"); addTest(tests, "chapter", "child::para[position()=1]"); addTest(tests, "chapter", "para[1]"); addTest(tests, "chapter", "child::para[position()=last()]"); addTest(tests, "chapter", "para[last()]"); addTest(tests, "chapter", "child::para[position()=last()-1]"); addTest(tests, "chapter", "child::para[position()>1]"); addTest(tests, "chapter", "following-sibling::chapter[position()=1]"); addTest(tests, "chapter", "preceding-sibling::chapter[position()=1]"); addTest(tests, "book", "/descendant::figure[position()=2]"); addTest(tests, "book", "/child::book/child::chapter[position()=3]/child::section[position()=2]"); addTest(tests, "book", "/book/chapter[3]/section[2]"); addTest(tests, "chapter", "child::para[attribute::type='warning']"); addTest(tests, "chapter", "para[@type='warning']"); addTest(tests, "chapter", "para[@type='warning']"); addTest(tests, "chapter", "child::para[attribute::type='warning'][position()=1]"); addTest(tests, "chapter", "para[@type='warning'][1]"); addTest(tests, "chapter", "para[1][@type='warning']"); addTest(tests, "chapter", "child::para[position()=1][attribute::type='warning']"); addTest(tests, "book", "child::chapter[child::title='Introduction']"); addTest(tests, "book", "chapter[title='Introduction']"); addTest(tests, "book", "child::chapter[child::title]"); addTest(tests, "book", "chapter[title]"); addTest(tests, "book", "child::chapter[child::title[self::*='Introduction']]"); addTest(tests, "book", "chapter[title[.='Introduction']]"); addTest(tests, "book", "child::*[self::chapter or self::appendix]"); addTest(tests, "book", "child::*[self::chapter or self::appendix][position()=last()]"); addTest(tests, "book", "para[@name and @type]"); addTest(tests, "para", ".."); addTest(tests, "para", "../@name"); addTest(tests, "book", "descendant::chapter/descendant::para/descendant::figure"); addTest(tests, "book", "..//chapter//para//figure"); addTest(tests, "book", "descendant::chapter/descendant::para"); addTest(tests, "book", "..//chapter//para"); addTest(tests, "book", "descendant::para/ancestor::chapter"); addTest(tests, "para", "preceding::*"); addTest(tests, "para", "following::*"); addTest(tests, "chapter", "preceding-sibling::*"); addTest(tests, "chapter", "following-sibling::*"); addTest(tests, "chapter", "descendant-or-self::*"); runTests(tests, d); function parseDocument(URI) { var d = new DOM.Document; var wd = new DOM.Writer(d); var xr = new XML.Reader(); xr.contentHandler = wd; xr.parse(URI); return d; } function addTest(tests, match, select) { var index = tests.length; var t = new Object(); t.match = new XSLT.Pattern(match); t.select = new XPath.Expr(select); tests[index] = t; } function runTests(tests, d) { for (var i = 0; i < tests.length; i++) { var match = tests[i].match; var select = tests[i].select; print("Match: \""+match+"\", select: \""+select+"\""); walk(match, select, d); print(""); } } function walk(match, select, node) { if (match.match(node)) evalExpr(select, node); var type = node.nodeType; if (type == DOM.Node.ELEMENT_NODE) { var attrMap = node.attributes; var length = attrMap.length; for (var i = 0; i < length; i++) walk(match, select, attrMap.item(i)); } if (type == DOM.Node.DOCUMENT_NODE || type == DOM.Node.ELEMENT_NODE) { for (var child = node.firstChild; child != null; child = child.nextSibling) walk(match, select, child); } } function evalExpr(expr, node) { dumpNode(" Context: ", node); // note implicit type cast of Node to NodeSet: var nodeSet = expr.eval(node); while (nodeSet.current != null) { dumpNode(" Node: ", nodeSet.current); nodeSet.next(); } } function dumpNode(prefix, node) { var type; var value; if (node.nodeType == DOM.Node.ELEMENT_NODE) { type = "element"; // // Variant 1: Use named node map // // var attrMap = node.attributes; // var attr = attrMap.getNamedItem("name"); // value = (attr != null) ? attr.nodeValue : null; // // // Variant 2: Call Element constructor as function // to perform type cast // var element = DOM.Element(node); value = element.getAttribute("name"); } else if (node.nodeType == DOM.Node.ATTRIBUTE_NODE) { type = "attribute"; value = node.nodeValue; } else { type = "other"; value = null; } print(prefix+ "type: "+type+ ", name: "+node.nodeName+ ", value: "+value); }
The following XML document can be used as input for this program.
<?xml version="1.0"?> <book> <chapter name="1" id="id-1"> <title>Preface</title> <title>Introduction</title> <para name="1.1"> Text begin of paragraph 1.1 <para name="1.1.1"> Text of paragraph 1.1.1 <figure name="fig-1.1.1-A"/> </para> <para name="1.1.2"> Text of paragraph 1.1.2 </para> Text end of paragraph 1.1 <figure name="fig-1.1-Z"/> </para> <para name="1.2" type="warning"> Text begin of paragraph 1.2 <para name="1.2.1"> Text of paragraph 1.2.1 </para> <para name="1.2.2"> Text of paragraph 1.2.2 </para> Text end of paragraph 1.2 </para> </chapter> <chapter name="2" id="id-2"> <para name="2.1" type="warning"> Text begin of paragraph 2.1 <para name="2.1.1"> Text of paragraph 2.1.1 </para> <para name="2.1.2"> Text of paragraph 2.1.2 </para> Text end of paragraph 2.1 </para> <para name="2.2"> Text begin of paragraph 2.2 <para name="2.2.1"> Text of paragraph 2.2.1 </para> <para name="2.2.2"> Text of paragraph 2.2.2 </para> Text end of paragraph 2.2 </para> </chapter> <appendix name="appendix-1"/> <chapter name="3" id="id-3"> <title>Introduction</title> <section name="section-1"/> <section name="section-2"/> <section name="section-3"/> </chapter> <appendix name="appendix-2"/> </book>