summaryrefslogtreecommitdiffstats
path: root/LayoutTests/fast/xpath/py-dom-xpath
diff options
context:
space:
mode:
Diffstat (limited to 'LayoutTests/fast/xpath/py-dom-xpath')
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/abbreviations-expected.txt26
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/abbreviations.html182
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/axes-expected.txt33
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/axes.html126
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/data-expected.txt29
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/data.html62
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/expressions-expected.txt63
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/expressions.html148
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/functions-expected.txt86
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/functions.html198
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/nodetests-expected.txt19
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/nodetests.html98
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/paths-expected.txt35
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/paths.html261
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/predicates-expected.txt15
-rw-r--r--LayoutTests/fast/xpath/py-dom-xpath/predicates.html55
16 files changed, 1436 insertions, 0 deletions
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/abbreviations-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/abbreviations-expected.txt
new file mode 100644
index 0000000..2d664fa
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/abbreviations-expected.txt
@@ -0,0 +1,26 @@
+PASS para
+PASS *
+PASS text()
+PASS @name
+PASS @*
+PASS para[1]
+PASS para[last()]
+PASS */para
+PASS /doc/chapter[5]/section[2]
+PASS chapter//para
+PASS //para
+PASS //olist/item
+PASS .
+PASS ./para
+PASS ..
+PASS ../@lang
+PASS para[@type="warning"]
+PASS para[@type="warning"][5]
+PASS para[5][@type="warning"]
+PASS chapter[title='Introduction']
+PASS chapter[title]
+PASS employee[@secretary and @assistant]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/abbreviations.html b/LayoutTests/fast/xpath/py-dom-xpath/abbreviations.html
new file mode 100644
index 0000000..090e2e9
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/abbreviations.html
@@ -0,0 +1,182 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <para id="1" />' +
+ ' <div id="2" />' +
+ ' <para id="3" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "para", [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1]]);
+test(doc, doc.documentElement, "*", [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("div")[0], doc.getElementsByTagName("para")[1]]);
+
+doc = (new DOMParser).parseFromString('<doc>This is <i>some</i> text.</doc>', 'application/xml');
+test(doc, doc.documentElement, "text()", [doc.documentElement.firstChild, doc.documentElement.lastChild]);
+
+doc = (new DOMParser).parseFromString('<doc name="foo" value="bar" />', 'application/xml');
+test(doc, doc.documentElement, "@name", [doc.documentElement.getAttributeNode("name")]);
+test(doc, doc.documentElement, "@*", [doc.documentElement.getAttributeNode("name"), doc.documentElement.getAttributeNode("value")]);
+
+doc = (new DOMParser).parseFromString('<doc><para id="1" /><para id="2" /><para id="3" /></doc>', 'application/xml');
+test(doc, doc.documentElement, "para[1]", [doc.getElementsByTagName("para")[0]]);
+test(doc, doc.documentElement, "para[last()]", [doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <chapter><para id="1" /><para id="2" /></chapter>' +
+ ' <section><para id="3" /><sub><para id="4" /></sub></section>' +
+ ' <para id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "*/para", [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <chapter id="1" /><chapter id="2" /><chapter id="3" />' +
+ ' <chapter id="4">' +
+ ' <section id="4.1" /><section id="4.2" /><section id="4.3" />' +
+ ' </chapter>' +
+ ' <chapter id="5">' +
+ ' <section id="5.1" /><section id="5.2" /><section id="5.3" />' +
+ ' </chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "/doc/chapter[5]/section[2]", [doc.getElementsByTagName("section")[4]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <chapter><para id="1" /><para id="2" /></chapter>' +
+ ' <chapter><section><para id="3" /></section></chapter>' +
+ ' <para id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "chapter//para", [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<para id="0">' +
+ ' <div id="1" />' +
+ ' <para id="2">' +
+ ' <para id="3" />' +
+ ' </para>' +
+ '</para>',
+ 'application/xml');
+test(doc, '//para[@id="2"]', '//para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <item id="1">' +
+ ' <context />' +
+ ' <olist><item id="2" /></olist>' +
+ ' </item>' +
+ ' <olist><item id="3" /></olist>' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//context', '//olist/item', [doc.getElementsByTagName("item")[1], doc.getElementsByTagName("item")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ ' <para id="1"/>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, '.', [doc.documentElement]);
+
+doc = (new DOMParser).parseFromString(
+ '<para id="0">' +
+ ' <div id="1" />' +
+ ' <para id="2">' +
+ ' <para id="3" />' +
+ ' </para>' +
+ '</para>',
+ 'application/xml');
+test(doc, '//para[@id="2"]', './para', [doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ ' <chapter id="1">' +
+ ' <item id="2" />' +
+ ' <item id="3"><subitem id="4" /></item>' +
+ ' </chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//item[@id="3"]', '..', [doc.getElementsByTagName("chapter")[0]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ ' <chapter id="1" lang="en">' +
+ ' <item id="2" />' +
+ ' <item id="3"><subitem id="4" /></item>' +
+ ' </chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//item[@id="3"]', '../@lang', [doc.getElementsByTagName("chapter")[0].getAttributeNode("lang")]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <para id="1" type="info" />' +
+ ' <para id="2" type="warning" />' +
+ ' <para id="3" type="warning" />' +
+ ' <para id="4" type="error" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'para[@type="warning"]', [doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <para id="1" type="info" />' +
+ ' <para id="2" type="warning" />' +
+ ' <para id="3" type="warning" />' +
+ ' <para id="4" type="warning" />' +
+ ' <para id="5" type="error" />' +
+ ' <para id="6" type="warning" />' +
+ ' <para id="7" type="warning" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'para[@type="warning"][5]', [doc.getElementsByTagName("para")[6]]);
+test(doc, doc.documentElement, 'para[5][@type="warning"]', []);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <chapter id="1" />' +
+ ' <chapter id="2"><title>Introduction</title></chapter>' +
+ ' <chapter id="3"><title>Body</title></chapter>' +
+ ' <chapter id="4">' +
+ ' <title>Another</title>' +
+ ' <title>Introduction</title>' +
+ ' </chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "chapter[title='Introduction']", [doc.getElementsByTagName("chapter")[1], doc.getElementsByTagName("chapter")[3]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <chapter id="1" />' +
+ ' <chapter id="2"><title /></chapter>' +
+ ' <chapter id="3"><title /><title /></chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "chapter[title]", [doc.getElementsByTagName("chapter")[1], doc.getElementsByTagName("chapter")[2]]);
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <employee name="Alice" />' +
+ ' <employee name="Bob" secretary="Cathy" />' +
+ ' <employee name="Dianne" secretary="Edward" assistant="Fran" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "employee[@secretary and @assistant]", [doc.getElementsByTagName("employee")[2]]);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/axes-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/axes-expected.txt
new file mode 100644
index 0000000..daba780
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/axes-expected.txt
@@ -0,0 +1,33 @@
+PASS //*[@id="2"]/child::*
+PASS //*[@id="2.2"]/parent::*
+PASS //*[@id="2.2"]/ancestor::*
+PASS //*[@id="2.2"]/following-sibling::*
+PASS //*[@id="2.2"]/preceding-sibling::*
+PASS //*[@id="2.2"]/following::*
+PASS //*[@id="2.2"]/preceding::*
+PASS //*[@id="2.2"]/attribute::*
+PASS //*[@id="2.2"]/self::*
+PASS //*[@id="1"]/descendant-or-self::*
+PASS //*[@id="2.2"]/ancestor-or-self::*
+Test that the ancestor, descendant, following, preceding, and self axes partition the document
+PASS nodeCount is 16
+PASS 0
+PASS 1
+PASS 1.1
+PASS 1.1.1
+PASS 2
+PASS 2.1
+PASS 2.1.1
+PASS 2.2
+PASS 2.2.1
+PASS 2.2.2
+PASS 2.2.3
+PASS 2.3
+PASS 2.3.1
+PASS 3
+PASS 3.1
+PASS 3.1.1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/axes.html b/LayoutTests/fast/xpath/py-dom-xpath/axes.html
new file mode 100644
index 0000000..1417c7e
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/axes.html
@@ -0,0 +1,126 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+function arraysAreEqual(array1, array2) {
+ var temp = new Array();
+ if ( (!array1[0]) || (!array2[0]) ) { // If either is not an array
+ return false;
+ }
+ if (array1.length != array2.length) {
+ return false;
+ }
+ // Put all the elements from array1 into a "tagged" array
+ for (var i = 0; i < array1.length; i++) {
+ key = (typeof array1[i]) + "~" + array1[i];
+ // Use "typeof" so a number 1 isn't equal to a string "1".
+ if (temp[key]) { temp[key]++; } else { temp[key] = 1; }
+ // temp[key] = # of occurrences of the value (so an element could appear multiple times)
+ }
+ // Go through array2 - if same tag missing in "tagged" array, not equal
+ for (var i = 0; i < array2.length; i++) {
+ key = (typeof array2[i]) + "~" + array2[i];
+ if (temp[key]) {
+ if (temp[key] == 0) { return false; } else { temp[key]--; }
+ // Subtract to keep track of # of appearances in array2
+ } else { // Key didn't appear in array1, arrays are not equal.
+ return false;
+ }
+ }
+ // If we get to this point, then every generated key in array1 showed up the exact same
+ // number of times in array2, so the arrays are equal.
+ return true;
+}
+
+
+var doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ '<chapter id="1">' +
+ '<section id="1.1">' +
+ '<item id="1.1.1" />' +
+ '</section>' +
+ '</chapter>' +
+ '<chapter id="2">' +
+ '<section id="2.1">' +
+ '<item id="2.1.1" />' +
+ '</section>' +
+ '<section id="2.2">' +
+ '<item id="2.2.1" /><item id="2.2.2" /><item id="2.2.3" />' +
+ '</section>' +
+ '<section id="2.3">' +
+ '<item id="2.3.1" />' +
+ '</section>' +
+ '</chapter>' +
+ '<chapter id="3">' +
+ '<section id="3.1">' +
+ '<item id="3.1.1" />' +
+ '</section>' +
+ '</chapter>' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var CHAPTER1 = ROOT.firstChild;
+var CHAPTER2 = CHAPTER1.nextSibling;
+var CHAPTER3 = CHAPTER2.nextSibling;
+var SECTION11 = CHAPTER1.firstChild;
+var SECTION21 = CHAPTER2.firstChild;
+var SECTION22 = SECTION21.nextSibling;
+var SECTION23 = SECTION22.nextSibling;
+var SECTION31 = CHAPTER3.firstChild;
+var ITEM111 = SECTION11.firstChild;
+var ITEM211 = SECTION21.firstChild;
+var ITEM221 = SECTION22.firstChild;
+var ITEM222 = ITEM221.nextSibling;
+var ITEM223 = ITEM222.nextSibling;
+var ITEM231 = SECTION23.firstChild;
+var ITEM311 = SECTION31.firstChild;
+
+test(doc, doc.documentElement, '//*[@id="2"]/child::*', [SECTION21, SECTION22, SECTION23]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/parent::*', [CHAPTER2]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/ancestor::*', [ROOT, CHAPTER2]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/following-sibling::*', [SECTION23]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/preceding-sibling::*', [SECTION21]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/following::*', [SECTION23, ITEM231, CHAPTER3, SECTION31, ITEM311]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/preceding::*', [CHAPTER1, SECTION11, ITEM111, SECTION21, ITEM211]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/attribute::*', [SECTION22.getAttributeNode("id")]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/self::*', [SECTION22]);
+test(doc, doc.documentElement, '//*[@id="1"]/descendant-or-self::*', [CHAPTER1, SECTION11, ITEM111]);
+test(doc, doc.documentElement, '//*[@id="2.2"]/ancestor-or-self::*', [ROOT, CHAPTER2, SECTION22]);
+
+debug("Test that the ancestor, descendant, following, preceding, and self axes partition the document");
+var nodeCount = doc.evaluate("count(//*)", doc.documentElement, null, XPathResult.ANY_TYPE, null).numberValue;
+shouldBe('nodeCount', '16');
+var allNodes = doc.evaluate("//*", doc.documentElement, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
+var allNodesSet = []
+for (i = 0; i < allNodes.snapshotLength; ++i) {
+ allNodesSet.push(allNodes.snapshotItem(i));
+}
+for (i = 0; i < allNodes.snapshotLength; ++i) {
+ var node = allNodes.snapshotItem(i);
+ var resultNodes = [];
+ var axes = ['ancestor','descendant','following','preceding','self'];
+ for (axis in axes) {
+ var res = doc.evaluate(axes[axis] + "::*", node, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
+ while (n = res.iterateNext()) {
+ resultNodes.push(n);
+ }
+ }
+ if (arraysAreEqual(resultNodes, allNodesSet))
+ testPassed(node.getAttribute("id"));
+ else
+ testFailed(node.getAttribute("id"));
+}
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/data-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/data-expected.txt
new file mode 100644
index 0000000..bb91568
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/data-expected.txt
@@ -0,0 +1,29 @@
+PASS normalize-space(/)
+PASS name(/)
+PASS local-name(/)
+PASS namespace-uri(/)
+PASS normalize-space(/doc)
+PASS string(//a:item)
+PASS name(//a:item)
+PASS local-name(//a:item)
+PASS namespace-uri(//a:item)
+PASS string(//@attribute)
+PASS name(//@a:attribute)
+PASS local-name(//@a:attribute)
+PASS namespace-uri(//@a:attribute)
+PASS string(//processing-instruction())
+PASS name(//processing-instruction())
+PASS local-name(//processing-instruction())
+PASS namespace-uri(//processing-instruction())
+PASS string(//comment())
+PASS name(//comment())
+PASS local-name(//comment())
+PASS namespace-uri(//comment())
+PASS string(//element/text())
+PASS name(//element/text())
+PASS local-name(//element/text())
+PASS namespace-uri(//element/text())
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/data.html b/LayoutTests/fast/xpath/py-dom-xpath/data.html
new file mode 100644
index 0000000..bb8df6d
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/data.html
@@ -0,0 +1,62 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc xmlns:a="http://www.example.com/a">' +
+ ' <element attribute="&quot;value&quot;">&lt;text&gt;</element>' +
+ ' followed' +
+ ' <?processing instruction ?>' +
+ ' by' +
+ ' <!-- comment -->' +
+ ' more text' +
+ ' <a:item attribute="1" a:attribute="2" />' +
+ '</doc>',
+ 'application/xml');
+var nsResolver = doc.createNSResolver(doc.documentElement);
+
+test(doc, doc.documentElement, 'normalize-space(/)', "<text> followed by more text", nsResolver);
+test(doc, doc.documentElement, 'name(/)', "", nsResolver);
+test(doc, doc.documentElement, 'local-name(/)', "", nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(/)', "", nsResolver);
+
+test(doc, doc.documentElement, 'normalize-space(/doc)', "<text> followed by more text", nsResolver);
+
+test(doc, doc.documentElement, 'string(//a:item)', "", nsResolver);
+test(doc, doc.documentElement, 'name(//a:item)', "a:item", nsResolver);
+test(doc, doc.documentElement, 'local-name(//a:item)', "item", nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(//a:item)', "http://www.example.com/a", nsResolver);
+
+test(doc, doc.documentElement, 'string(//@attribute)', '\"value\"', nsResolver);
+test(doc, doc.documentElement, 'name(//@a:attribute)', 'a:attribute', nsResolver);
+test(doc, doc.documentElement, 'local-name(//@a:attribute)', 'attribute', nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(//@a:attribute)', 'http://www.example.com/a', nsResolver);
+
+test(doc, doc.documentElement, 'string(//processing-instruction())', 'instruction ', nsResolver);
+test(doc, doc.documentElement, 'name(//processing-instruction())', 'processing', nsResolver);
+test(doc, doc.documentElement, 'local-name(//processing-instruction())', 'processing', nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(//processing-instruction())', '', nsResolver);
+
+test(doc, doc.documentElement, 'string(//comment())', ' comment ', nsResolver);
+test(doc, doc.documentElement, 'name(//comment())', '', nsResolver);
+test(doc, doc.documentElement, 'local-name(//comment())', '', nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(//comment())', '', nsResolver);
+
+test(doc, doc.documentElement, 'string(//element/text())', '<text>', nsResolver);
+test(doc, doc.documentElement, 'name(//element/text())', '', nsResolver);
+test(doc, doc.documentElement, 'local-name(//element/text())', '', nsResolver);
+test(doc, doc.documentElement, 'namespace-uri(//element/text())', '', nsResolver);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/expressions-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/expressions-expected.txt
new file mode 100644
index 0000000..ccc478a
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/expressions-expected.txt
@@ -0,0 +1,63 @@
+PASS //item[@id >= 2 and @id <= "4"]
+PASS //item[@id >= 2 and @id <= 3]
+PASS doc.evaluate("position(1)", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate("not()", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS string-length(100)
+PASS doc.evaluate("count(100)", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate("adumbrate()", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS //item[@id mod 2 = 0] | //item[@id mod 3 = 0]
+PASS doc.evaluate("//item | 42", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate("/doc/(item[@id = 2] | item[@id = 6])/@id", doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate('"monty"/anaconda', doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate('/doc/string(item[@id = 2])/@id', doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS doc.evaluate('(1)[1]', doc.documentElement, null, XPathResult.ANY_TYPE, null) threw exception Error: INVALID_EXPRESSION_ERR: DOM XPath Exception 51.
+PASS (1)
+PASS ((1 + 1))
+PASS 1 or 1
+PASS 1 or 0
+PASS 0 or 1
+PASS 0 or 0
+PASS 1 and 1
+PASS 1 and 0
+PASS 0 and 1
+PASS 0 and 0
+PASS (//set[@id=1]/*) = (//set[@id=3]/*)
+PASS (//set[@id=1]/*) = (//set[@id=2]/*)
+PASS (//set[@id=1]/*) != (//set[@id=1]/*)
+PASS (//set[@id=4]/*) != (//set[@id=4]/*)
+PASS (//set[@id=1]/*) <= (//set[@id=2]/*)
+PASS (//set[@id=2]/*) <= (//set[@id=1]/*)
+PASS (//set[@id=1]/*) < (//set[@id=2]/*)
+PASS (//set[@id=2]/*) < (//set[@id=1]/*)
+PASS (//set[@id=2]/*) > (//set[@id=1]/*)
+PASS (//set[@id=1]/*) > (//set[@id=2]/*)
+PASS (//set[@id=2]/*) >= (//set[@id=1]/*)
+PASS (//set[@id=1]/*) >= (//set[@id=2]/*)
+PASS (//set[@id=4]/*) = (1 = 1)
+PASS (//set[@id=4]/*) = (1 = 0)
+PASS (//set[@id=4]/*) != (1 = 0)
+PASS (//set[@id=4]/*) != (1 = 1)
+PASS (//set[@id=4]/*) = 42
+PASS (//set[@id=4]/*) = 43
+PASS (//set[@id=4]/*) != 43
+PASS (//set[@id=4]/*) != 42
+PASS (//set[@id=4]/*) = "42.0"
+PASS (//set[@id=4]/*) = "42"
+PASS (//set[@id=4]/*) != "42"
+PASS (//set[@id=4]/*) != "42.0"
+PASS "a" <= "a"
+PASS "a" <= "b"
+PASS "a" >= "a"
+PASS "b" > "a"
+PASS 1 <= 1
+PASS 2 <= 1
+PASS 1 < 2
+PASS 1 < 1
+PASS 1 >= 1
+PASS 1 >= 2
+PASS 2 > 1
+PASS 1 > 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/expressions.html b/LayoutTests/fast/xpath/py-dom-xpath/expressions.html
new file mode 100644
index 0000000..cee4468
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/expressions.html
@@ -0,0 +1,148 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<item id="1" />' +
+ '<item id="2" />' +
+ '<item id="3" />' +
+ '<item id="4" />' +
+ '<item id="5" />' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var ITEM1 = ROOT.firstChild;
+var ITEM2 = ITEM1.nextSibling;
+var ITEM3 = ITEM2.nextSibling;
+var ITEM4 = ITEM3.nextSibling;
+
+test(doc, doc.documentElement, '//item[@id >= 2 and @id <= "4"]', [ITEM2, ITEM3, ITEM4]);
+test(doc, doc.documentElement, '//item[@id >= 2 and @id <= 3]', [ITEM2, ITEM3]);
+shouldThrow('doc.evaluate("position(1)", doc.documentElement, null, XPathResult.ANY_TYPE, null)');
+shouldThrow('doc.evaluate("not()", doc.documentElement, null, XPathResult.ANY_TYPE, null)');
+test(doc, doc, "string-length(100)", 3);
+shouldThrow('doc.evaluate("count(100)", doc.documentElement, null, XPathResult.ANY_TYPE, null)');
+shouldThrow('doc.evaluate("adumbrate()", doc.documentElement, null, XPathResult.ANY_TYPE, null)');
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<item id="1" />' +
+ '<item id="2" />' +
+ '<item id="3" />' +
+ '<item id="4" />' +
+ '<item id="5" />' +
+ '<item id="6" />' +
+ '<item id="7" />' +
+ '<item id="8" />' +
+ '<item id="9" />' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var ITEM1 = ROOT.firstChild;
+var ITEM2 = ITEM1.nextSibling;
+var ITEM3 = ITEM2.nextSibling;
+var ITEM4 = ITEM3.nextSibling;
+var ITEM5 = ITEM4.nextSibling;
+var ITEM6 = ITEM5.nextSibling;
+var ITEM7 = ITEM6.nextSibling;
+var ITEM8 = ITEM7.nextSibling;
+var ITEM9 = ITEM8.nextSibling;
+
+test(doc, doc.documentElement, '//item[@id mod 2 = 0] | //item[@id mod 3 = 0]', [ITEM2, ITEM3, ITEM4, ITEM6, ITEM8, ITEM9]);
+shouldThrow('doc.evaluate("//item | 42", doc.documentElement, null, XPathResult.ANY_TYPE, null)');
+shouldThrow('doc.evaluate("/doc/(item[@id = 2] | item[@id = 6])/@id", doc.documentElement, null, XPathResult.ANY_TYPE, null)'); // This test doesn't throw in py-dom-path, which is a bug.
+shouldThrow("doc.evaluate('\"monty\"/anaconda', doc.documentElement, null, XPathResult.ANY_TYPE, null)");
+shouldThrow("doc.evaluate('/doc/string(item[@id = 2])/@id', doc.documentElement, null, XPathResult.ANY_TYPE, null)");
+shouldThrow("doc.evaluate('(1)[1]', doc.documentElement, null, XPathResult.ANY_TYPE, null)");
+
+// Added for WebKit.
+test(doc, doc.documentElement, '(1)', 1);
+test(doc, doc.documentElement, '((1 + 1))', 2);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ ' <set id="1">' +
+ ' <item>1</item>' +
+ ' <item>2</item>' +
+ ' <item>3</item>' +
+ ' <item>4</item>' +
+ ' </set>' +
+ ' <set id="2">' +
+ ' <item>5</item>' +
+ ' <item>6</item>' +
+ ' <item>7</item>' +
+ ' <item>8</item>' +
+ ' </set>' +
+ ' <set id="3">' +
+ ' <item>0</item>' +
+ ' <item>3</item>' +
+ ' <item>6</item>' +
+ ' <item>9</item>' +
+ ' </set>' +
+ ' <set id="4">' +
+ ' <item>42.0</item>' +
+ ' </set>' +
+ '</doc>',
+ 'application/xml');
+
+test(doc, doc.documentElement, '1 or 1', true);
+test(doc, doc.documentElement, '1 or 0', true);
+test(doc, doc.documentElement, '0 or 1', true);
+test(doc, doc.documentElement, '0 or 0', false);
+test(doc, doc.documentElement, '1 and 1', true);
+test(doc, doc.documentElement, '1 and 0', false);
+test(doc, doc.documentElement, '0 and 1', false);
+test(doc, doc.documentElement, '0 and 0', false);
+test(doc, doc.documentElement, '(//set[@id=1]/*) = (//set[@id=3]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=1]/*) = (//set[@id=2]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=1]/*) != (//set[@id=1]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != (//set[@id=4]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=1]/*) <= (//set[@id=2]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=2]/*) <= (//set[@id=1]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=1]/*) < (//set[@id=2]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=2]/*) < (//set[@id=1]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=2]/*) > (//set[@id=1]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=1]/*) > (//set[@id=2]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=2]/*) >= (//set[@id=1]/*)', true);
+test(doc, doc.documentElement, '(//set[@id=1]/*) >= (//set[@id=2]/*)', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = (1 = 1)', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = (1 = 0)', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != (1 = 0)', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != (1 = 1)', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = 42', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = 43', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != 43', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != 42', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = "42.0"', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) = "42"', false);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != "42"', true);
+test(doc, doc.documentElement, '(//set[@id=4]/*) != "42.0"', false);
+test(doc, doc.documentElement, '"a" <= "a"', false);
+test(doc, doc.documentElement, '"a" <= "b"', false);
+test(doc, doc.documentElement, '"a" >= "a"', false);
+test(doc, doc.documentElement, '"b" > "a"', false);
+test(doc, doc.documentElement, '1 <= 1', true);
+test(doc, doc.documentElement, '2 <= 1', false);
+test(doc, doc.documentElement, '1 < 2', true);
+test(doc, doc.documentElement, '1 < 1', false);
+test(doc, doc.documentElement, '1 >= 1', true);
+test(doc, doc.documentElement, '1 >= 2', false);
+test(doc, doc.documentElement, '2 > 1', true);
+test(doc, doc.documentElement, '1 > 1', false);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/functions-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/functions-expected.txt
new file mode 100644
index 0000000..b70f566
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/functions-expected.txt
@@ -0,0 +1,86 @@
+PASS //item[@id=last()]
+PASS //item[position()=3]
+PASS count(//item)
+FAIL id("c") incorrect length (expected 1, actual 0)
+FAIL id(//reference) incorrect length (expected 3, actual 0)
+PASS local-name(//self::node()[@id=7])
+PASS number(//self::node()[@id=7]/attribute::*[local-name()="value"])
+PASS local-name(/absent)
+PASS namespace-uri(//self::node()[@id>5])
+PASS //self::node()[@id and namespace-uri()="http://www.example.com/b"]
+PASS namespace-uri(/absent)
+PASS name(//self::node()[@id=7])
+PASS //self::node()[name()="b:item"]
+PASS name(/absent)
+PASS string(//para)
+PASS string(//inconceivable)
+PASS string(0 div 0)
+PASS string(1 div 0)
+PASS string(-1 div 0)
+PASS string(2.5 * 2)
+PASS string(1 div -2)
+PASS string(1 = 2)
+PASS string("string")
+PASS //para[string()="Two"]
+PASS concat(//para, ":", //para[2])
+PASS starts-with("foo-bar", "foo")
+PASS starts-with("foo-bar", "bar")
+PASS contains("foo-bar", "o-b")
+PASS contains("foo-bar", "b-o")
+PASS substring-before("foo::bar", "::")
+PASS substring-before("foo::bar", "--")
+PASS substring-after("foo::bar", "::")
+PASS substring-after("foo::bar", "--")
+PASS substring("12345", 2)
+PASS substring("12345", 2, 3)
+PASS substring("12345", 1.5, 2.6)
+PASS substring("12345", 0, 3)
+PASS substring("12345", 0 div 0, 3)
+PASS substring("12345", 1, 0 div 0)
+PASS substring("12345", -42, 1 div 0)
+PASS substring("12345", -1 div 0, 1 div 0)
+PASS substring("12345", 6, 1)
+PASS substring("12345", 1, 0)
+PASS string-length("12345")
+PASS //para[string-length()=5]
+PASS normalize-space(" one two ")
+PASS //para[normalize-space() = "Four"]
+PASS translate("abcdef", "abcde", "xyz")
+PASS boolean(1)
+PASS boolean(0)
+PASS boolean(0 div 0)
+PASS boolean(cod)
+PASS boolean(doc)
+PASS boolean("")
+PASS boolean("foo")
+PASS not(1 = 1)
+PASS true()
+PASS false()
+PASS //*[lang("en")]
+PASS //*[lang("EN-US")]
+PASS normalize-space((//text()[lang("jp")])[normalize-space()])
+PASS string(number("-1e5"))
+PASS number(true())
+PASS number(false())
+PASS number(//item)
+PASS string(//item[number()=4 div 2])
+PASS sum(//item)
+PASS floor(1.99)
+PASS floor(-1.99)
+PASS ceiling(1.99)
+PASS ceiling(-1.99)
+PASS round(1.5)
+PASS round(-1.5)
+PASS string(round(0 div 0))
+PASS round(1 div 0)
+PASS round(-1 div 0)
+PASS number(".1")
+PASS number("1.")
+PASS string(number(".1."))
+PASS string(number("..1"))
+PASS string(number("1.."))
+PASS string(number(".-1"))
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/functions.html b/LayoutTests/fast/xpath/py-dom-xpath/functions.html
new file mode 100644
index 0000000..90183e3
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/functions.html
@@ -0,0 +1,198 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<!DOCTYPE doc [<!ATTLIST item identifier ID #IMPLIED>]>' +
+ '<doc>' +
+ '<item id="1" identifier="a" />' +
+ '<item id="2" identifier="b" />' +
+ '<item id="3" identifier="c" />' +
+ '<item id="4" identifier="d" />' +
+ '<item id="5" identifier="e" />' +
+ '<reference>a</reference>' +
+ '<reference>c</reference>' +
+ '<reference>e</reference>' +
+ '<namespace xmlns="http://www.example.com/a" xmlns:b="http://www.example.com/b">' +
+ '<item id="6" />' +
+ '<b:item id="7" b:value="42" />' +
+ '</namespace>' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var ITEM1 = ROOT.firstChild;
+var ITEM2 = ITEM1.nextSibling;
+var ITEM3 = ITEM2.nextSibling;
+var ITEM4 = ITEM3.nextSibling;
+var ITEM5 = ITEM4.nextSibling;
+var REFA = ITEM5.nextSibling;
+var REFC = REFA.nextSibling;
+var REFE = REFC.nextSibling;
+var NAMESPACE = REFE.nextSibling;
+var ITEM6 = NAMESPACE.firstChild;
+var ITEM7 = ITEM6.nextSibling;
+
+test(doc, ROOT, '//item[@id=last()]', [ITEM5]);
+test(doc, ROOT, '//item[position()=3]', [ITEM3]);
+test(doc, ROOT, 'count(//item)', 5);
+test(doc, ROOT, 'id("c")', [ITEM3]);
+test(doc, ROOT, 'id(//reference)', [ITEM1, ITEM3, ITEM5]);
+// The below test is wrong, it has an invalid expression.
+//test(doc, ROOT, '//reference/id("a")', [ITEM1]);
+// Several tests below originally used predicates with an abbreviated step, which is formally invalid, see <https://bugs.webkit.org/show_bug.cgi?id=12632>.
+test(doc, ROOT, 'local-name(//self::node()[@id=7])', 'item');
+test(doc, ROOT, 'number(//self::node()[@id=7]/attribute::*[local-name()="value"])', 42);
+test(doc, ROOT, 'local-name(/absent)', '');
+test(doc, ROOT, 'namespace-uri(//self::node()[@id>5])', 'http://www.example.com/a');
+test(doc, ROOT, '//self::node()[@id and namespace-uri()="http://www.example.com/b"]', [ITEM7]);
+test(doc, ROOT, 'namespace-uri(/absent)', '');
+test(doc, ROOT, 'name(//self::node()[@id=7])', 'b:item');
+test(doc, ROOT, '//self::node()[name()="b:item"]', [ITEM7]);
+test(doc, ROOT, 'name(/absent)', '');
+
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1">One</para>' +
+ '<para id="2">Two</para>' +
+ '<para id="3">Three</para>' +
+ '<para id="4">' +
+ 'Four' +
+ '</para>' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var PARA1 = ROOT.firstChild;
+var PARA2 = PARA1.nextSibling;
+var PARA3 = PARA2.nextSibling;
+var PARA4 = PARA3.nextSibling;
+
+test(doc, doc, 'string(//para)', 'One');
+test(doc, doc, 'string(//inconceivable)', '');
+test(doc, doc, 'string(0 div 0)', 'NaN');
+test(doc, doc, 'string(1 div 0)', 'Infinity');
+test(doc, doc, 'string(-1 div 0)', '-Infinity');
+test(doc, doc, 'string(2.5 * 2)', '5');
+test(doc, doc, 'string(1 div -2)', '-0.5');
+test(doc, doc, 'string(1 = 2)', 'false');
+test(doc, doc, 'string("string")', 'string');
+test(doc, doc, '//para[string()="Two"]', [PARA2]);
+test(doc, doc, 'concat(//para, ":", //para[2])', 'One:Two');
+test(doc, doc, 'starts-with("foo-bar", "foo")', true);
+test(doc, doc, 'starts-with("foo-bar", "bar")', false);
+test(doc, doc, 'contains("foo-bar", "o-b")', true);
+test(doc, doc, 'contains("foo-bar", "b-o")', false);
+test(doc, doc, 'substring-before("foo::bar", "::")', 'foo');
+test(doc, doc, 'substring-before("foo::bar", "--")', '');
+test(doc, doc, 'substring-after("foo::bar", "::")', 'bar');
+test(doc, doc, 'substring-after("foo::bar", "--")', '');
+test(doc, doc, 'substring("12345", 2)', '2345');
+test(doc, doc, 'substring("12345", 2, 3)', '234');
+test(doc, doc, 'substring("12345", 1.5, 2.6)', '234');
+test(doc, doc, 'substring("12345", 0, 3)', '12');
+test(doc, doc, 'substring("12345", 0 div 0, 3)', '');
+test(doc, doc, 'substring("12345", 1, 0 div 0)', '');
+test(doc, doc, 'substring("12345", -42, 1 div 0)', '12345');
+test(doc, doc, 'substring("12345", -1 div 0, 1 div 0)', '');
+test(doc, doc, 'substring("12345", 6, 1)', '');
+test(doc, doc, 'substring("12345", 1, 0)', '');
+test(doc, doc, 'string-length("12345")', 5);
+test(doc, doc, '//para[string-length()=5]', [PARA3]);
+test(doc, doc, 'normalize-space(" one two ")', 'one two');
+test(doc, doc, '//para[normalize-space() = "Four"]', [PARA4]);
+test(doc, doc, 'translate("abcdef", "abcde", "xyz")', 'xyzf');
+
+doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ '<para id="1" />' +
+ '<para id="2" xml:lang="en">' +
+ '<item id="3" />' +
+ 'English' +
+ '<section id="4" xml:lang="jp">' +
+ '<item id="5" />' +
+ 'Nihongo' +
+ '</section>' +
+ '</para>' +
+ '<para id="6" xml:lang="EN">' +
+ 'ENGLISH' +
+ '</para>' +
+ '<para id="7" xml:lang="en-us">' +
+ 'US English' +
+ '</para>' +
+ '<para id="8" xml:lang="EN-UK">' +
+ 'UK English' +
+ '</para>' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var PARA1 = ROOT.firstChild;
+var PARA2 = PARA1.nextSibling;
+var ITEM3 = PARA2.firstChild;
+var SECTION4 = ITEM3.nextSibling.nextSibling;
+var ITEM5 = SECTION4.firstChild;
+var PARA6 = PARA2.nextSibling;
+var PARA7 = PARA6.nextSibling;
+var PARA8 = PARA7.nextSibling;
+
+test(doc, doc, 'boolean(1)', true);
+test(doc, doc, 'boolean(0)', false);
+test(doc, doc, 'boolean(0 div 0)', false);
+test(doc, doc, 'boolean(cod)', false);
+test(doc, doc, 'boolean(doc)', true);
+test(doc, doc, 'boolean("")', false);
+test(doc, doc, 'boolean("foo")', true);
+test(doc, doc, 'not(1 = 1)', false);
+test(doc, doc, 'true()', true);
+test(doc, doc, 'false()', false);
+test(doc, doc, '//*[lang("en")]', [PARA2, ITEM3, PARA6, PARA7, PARA8]);
+test(doc, doc, '//*[lang("EN-US")]', [PARA7]);
+test(doc, doc, 'normalize-space((//text()[lang("jp")])[normalize-space()])', 'Nihongo');
+
+doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<item>1</item>' +
+ '<item>2</item>' +
+ '<item>3</item>' +
+ '</doc>',
+ 'application/xml');
+
+test(doc, doc, 'string(number("-1e5"))', 'NaN'); // This test originally checked for successful parsing, but -1e5 is not a valid XPath number.
+test(doc, doc, 'number(true())', 1);
+test(doc, doc, 'number(false())', 0);
+test(doc, doc, 'number(//item)', 1);
+test(doc, doc, 'string(//item[number()=4 div 2])', '2');
+test(doc, doc, 'sum(//item)', 6);
+test(doc, doc, 'floor(1.99)', 1);
+test(doc, doc, 'floor(-1.99)', -2);
+test(doc, doc, 'ceiling(1.99)', 2);
+test(doc, doc, 'ceiling(-1.99)', -1);
+test(doc, doc, 'round(1.5)', 2);
+test(doc, doc, 'round(-1.5)', -1);
+test(doc, doc, 'string(round(0 div 0))', 'NaN');
+test(doc, doc, 'round(1 div 0)', 1 / 0);
+test(doc, doc, 'round(-1 div 0)', -1 / 0);
+
+// The below tests are added for WebKit to complement the -1e5 test above.
+test(doc, doc, 'number(".1")', 0.1);
+test(doc, doc, 'number("1.")', 1);
+test(doc, doc, 'string(number(".1."))', 'NaN');
+test(doc, doc, 'string(number("..1"))', 'NaN');
+test(doc, doc, 'string(number("1.."))', 'NaN');
+test(doc, doc, 'string(number(".-1"))', 'NaN');
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/nodetests-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/nodetests-expected.txt
new file mode 100644
index 0000000..cd96536
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/nodetests-expected.txt
@@ -0,0 +1,19 @@
+PASS /descendant::item
+PASS /descendant::a:item
+PASS /descendant::b:*
+PASS docns.evaluate("//x:*", docns, nsResolver, XPathResult.ANY_TYPE, null) threw exception Error: NAMESPACE_ERR: DOM Exception 14.
+PASS doc/child::*
+PASS a:doc/child::*
+PASS //attribute::color
+PASS //attribute::color
+PASS //attribute::b:*
+PASS //attribute::*
+PASS count(//attribute::*)
+PASS doc/child::text()
+PASS doc/child::comment()
+PASS doc/child::processing-instruction()
+PASS doc/child::processing-instruction("one")
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/nodetests.html b/LayoutTests/fast/xpath/py-dom-xpath/nodetests.html
new file mode 100644
index 0000000..5f19996
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/nodetests.html
@@ -0,0 +1,98 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<item id="1" color="red" />' +
+ '<chapter id="c1">' +
+ '<item id="2" color="blue" />' +
+ '</chapter>' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var DI1 = ROOT.firstChild;
+var DC1 = DI1.nextSibling;
+var DI2 = DC1.firstChild;
+
+var docns = (new DOMParser).parseFromString(
+ '<doc xmlns="http://a.example.com" xmlns:b="http://b.example.com">' +
+ '<item id="1" color="red"/>' +
+ '<a:item id="2" xmlns:a="http://a.example.com" a:color="orange"/>' +
+ '<b:item id="3" color="yellow" />' +
+ '<item id="4" xmlns="http://a.example.com" color="green"/>' +
+ '<chapter id="c1" xmlns="http://b.example.com">' +
+ '<item id="5" color="blue" />' +
+ '<b:item id="6" b:color="indigo"/>' +
+ '</chapter>' +
+ '<chapter id="c2" xmlns="http://b.example.com" xmlns:b="http://a.example.com">' +
+ '<item id="7" b:color="violet"/>' +
+ '<b:item id="8" a:color="brown" xmlns:a="http://b.example.com"/>' +
+ '</chapter>' +
+ '</doc>',
+ 'application/xml');
+
+var XROOT = docns.firstChild;
+var XI1 = XROOT.firstChild;
+var XI2 = XI1.nextSibling;
+var XI3 = XI2.nextSibling;
+var XI4 = XI3.nextSibling;
+var XC1 = XI4.nextSibling;
+var XI5 = XC1.firstChild;
+var XI6 = XI5.nextSibling;
+var XC2 = XC1.nextSibling;
+var XI7 = XC2.firstChild;
+var XI8 = XI7.nextSibling;
+
+function nsResolver(prefix)
+{
+ if (prefix == "b")
+ return "http://b.example.com";
+ if (prefix == "a")
+ return "http://a.example.com";
+ return null;
+}
+
+// Some of these tests originally used a default namespace, which is not available in JavaScript XPathEvaluator.
+test(doc, doc, '/descendant::item', [DI1, DI2]);
+test(docns, docns, '/descendant::a:item', [XI1, XI2, XI4, XI8], nsResolver);
+test(docns, docns, '/descendant::b:*', [XI3, XC1, XI5, XI6, XC2, XI7], nsResolver);
+shouldThrow('docns.evaluate("//x:*", docns, nsResolver, XPathResult.ANY_TYPE, null)');
+test(doc, doc, 'doc/child::*', [DI1, DC1]);
+test(docns, docns, 'a:doc/child::*', [XI1, XI2, XI3, XI4, XC1, XC2], nsResolver);
+test(doc, doc, '//attribute::color', [DI1.getAttributeNode("color"), DI2.getAttributeNode("color")]);
+test(docns, docns, '//attribute::color', [XI1.getAttributeNode("color"), XI3.getAttributeNode("color"), XI4.getAttributeNode("color"), XI5.getAttributeNode("color")], nsResolver);
+test(docns, docns, '//attribute::b:*', [XI6.getAttributeNodeNS("http://b.example.com", "color"), XI8.getAttributeNodeNS("http://b.example.com", "color")], nsResolver);
+test(doc, doc, '//attribute::*', [DI1.getAttributeNode("id"), DI1.getAttributeNode("color"), DC1.getAttributeNode("id"), DI2.getAttributeNode("id"), DI2.getAttributeNode("color")]);
+test(docns, docns, 'count(//attribute::*)', 18, nsResolver);
+
+
+var doc = (new DOMParser).parseFromString(
+ '<doc><element />text<?one pi?><?two pi?><!--comment--></doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var TEXT = ROOT.firstChild.nextSibling;
+var COMMENT = ROOT.lastChild;
+var PI1 = TEXT.nextSibling;
+var PI2 = PI1.nextSibling;
+
+test(doc, doc, 'doc/child::text()', [TEXT]);
+test(doc, doc, 'doc/child::comment()', [COMMENT]);
+test(doc, doc, 'doc/child::processing-instruction()', [PI1, PI2]);
+test(doc, doc, 'doc/child::processing-instruction("one")', [PI1]);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/paths-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/paths-expected.txt
new file mode 100644
index 0000000..e33ccf4
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/paths-expected.txt
@@ -0,0 +1,35 @@
+PASS child::para
+PASS child::*
+PASS child::text()
+PASS child::node()
+PASS attribute::name
+PASS attribute::*
+PASS descendant::para
+PASS ancestor::div
+PASS ancestor-or-self::div
+PASS descendant-or-self::para
+PASS self::para
+PASS self::para
+PASS child::chapter/descendant::para
+PASS child::*/child::para
+PASS /
+PASS /descendant::para
+PASS /descendant::olist/child::item
+PASS child::para[position()=1]
+PASS child::para[position()=last()]
+PASS child::para[position()=last()-1]
+PASS child::para[position()>1]
+PASS following-sibling::chapter[position()=1]
+PASS preceding-sibling::chapter[position()=1]
+PASS /descendant::figure[position()=42]
+PASS /child::doc/child::chapter[position()=5]/child::section[position()=2]
+PASS child::para[attribute::type="warning"][position()=5]
+PASS child::para[position()=5][attribute::type="warning"]
+PASS child::chapter[child::title='Introduction']
+PASS child::chapter[child::title]
+PASS child::*[self::chapter or self::appendix]
+PASS child::*[self::chapter or self::appendix][position()=last()]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/paths.html b/LayoutTests/fast/xpath/py-dom-xpath/paths.html
new file mode 100644
index 0000000..e65289a
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/paths.html
@@ -0,0 +1,261 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1" />' +
+ '<div id="2" />' +
+ '<para id="3" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1]]);
+test(doc, doc.documentElement, 'child::*', [doc.documentElement.firstChild, doc.documentElement.firstChild.nextSibling, doc.documentElement.lastChild]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>This is <i>some</i> text.</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::text()', [doc.documentElement.firstChild, doc.documentElement.lastChild]);
+test(doc, doc.documentElement, 'child::node()', [doc.documentElement.firstChild, doc.documentElement.firstChild.nextSibling, doc.documentElement.lastChild]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc name="foo" value="bar" />',
+ 'application/xml');
+test(doc, doc.documentElement, 'attribute::name', [doc.documentElement.getAttributeNode("name")]);
+test(doc, doc.documentElement, 'attribute::*', [doc.documentElement.getAttributeNode("name"), doc.documentElement.getAttributeNode("value")]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1">' +
+ '<div id="2" />' +
+ '<para id="3" />' +
+ '</para>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'descendant::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<div id="1">' +
+ '<div id="2">' +
+ '<context />' +
+ '</div>' +
+ '<div id="3" />' +
+ '</div>' +
+ '<div id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//context', 'ancestor::div', [doc.getElementsByTagName("div")[0], doc.getElementsByTagName("div")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<div id="1">' +
+ '<div id="2" />' +
+ '<div id="3" />' +
+ '</div>' +
+ '<div id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//div[@id="3"]', 'ancestor-or-self::div', [doc.getElementsByTagName("div")[0], doc.getElementsByTagName("div")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<para id="0">' +
+ '<div id="1" />' +
+ '<para id="2">' +
+ '<para id="3" />' +
+ '</para>' +
+ '</para>',
+ 'application/xml');
+test(doc, doc.documentElement, 'descendant-or-self::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'self::para', []);
+test(doc, 'para', 'self::para', [doc.documentElement.firstChild]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter><para id="1" /><para id="2" /></chapter>' +
+ '<chapter><section><para id="3" /></section></chapter>' +
+ '<para id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::chapter/descendant::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter><para id="1" /><para id="2" /></chapter>' +
+ '<section><para id="3" /><sub><para id="4" /></sub></section>' +
+ '<para id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::*/child::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc><a><b><context /></b></a></doc>',
+ 'application/xml');
+test(doc, '//context', '/', [doc]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1"><context /></para>' +
+ '<para id="2" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//context', '/descendant::para', [doc.getElementsByTagName("para")[0], doc.getElementsByTagName("para")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<item id="1">' +
+ '<context />' +
+ '<olist><item id="2" /></olist>' +
+ '</item>' +
+ '<olist><item id="3" /></olist>' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//context', '/descendant::olist/child::item', [doc.getElementsByTagName("item")[1], doc.getElementsByTagName("item")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<div id="1" />' +
+ '<para id="2" />' +
+ '<para id="3" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para[position()=1]', [doc.getElementsByTagName("para")[0]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1" />' +
+ '<para id="2" />' +
+ '<div id="3" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para[position()=last()]', [doc.getElementsByTagName("para")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1" />' +
+ '<para id="2" />' +
+ '<para id="3" />' +
+ '<div id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para[position()=last()-1]', [doc.getElementsByTagName("para")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<div id="1" /><para id="2" />' +
+ '<div id="3" /><para id="4" />' +
+ '<div id="5" /><para id="6" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para[position()>1]', [doc.getElementsByTagName("para")[1], doc.getElementsByTagName("para")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" /><chapter id="2" />' +
+ '<context />' +
+ '<chapter id="3" /><chapter id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, '//context', 'following-sibling::chapter[position()=1]', [doc.getElementsByTagName("chapter")[2]]);
+test(doc, '//context', 'preceding-sibling::chapter[position()=1]', [doc.getElementsByTagName("chapter")[1]]);
+
+var xml = "<doc>"
+for (i = 1; i <= 10; ++i) {
+ for (j = 1; j <= 10; ++j)
+ xml += '<figure id="' + ((i*10)+j) + '%d">';
+ for (j = 1; j <= 10; ++j)
+ xml += '</figure>';
+}
+xml += "</doc>"
+var doc = (new DOMParser).parseFromString(xml, 'application/xml');
+test(doc, doc.documentElement, '/descendant::figure[position()=42]', [doc.getElementsByTagName("figure")[41]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" /><chapter id="2" /><chapter id="3" />' +
+ '<chapter id="4">' +
+ '<section id="4.1" /><section id="4.2" /><section id="4.3" />' +
+ '</chapter>' +
+ '<chapter id="5">' +
+ '<section id="5.1" /><section id="5.2" /><section id="5.3" />' +
+ '</chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, '/child::doc/child::chapter[position()=5]/child::section[position()=2]', [doc.getElementsByTagName("section")[4]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<para id="1" type="info" />' +
+ '<para id="2" type="warning" />' +
+ '<para id="3" type="warning" />' +
+ '<para id="4" type="warning" />' +
+ '<para id="5" type="error" />' +
+ '<para id="6" type="warning" />' +
+ '<para id="7" type="warning" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, 'child::para[attribute::type="warning"][position()=5]', [doc.getElementsByTagName("para")[6]]);
+test(doc, doc.documentElement, 'child::para[position()=5][attribute::type="warning"]', []);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" />' +
+ '<chapter id="2"><title>Introduction</title></chapter>' +
+ '<chapter id="3"><title>Body</title></chapter>' +
+ '<chapter id="4">' +
+ '<title>Another</title>' +
+ '<title>Introduction</title>' +
+ '</chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "child::chapter[child::title='Introduction']", [doc.getElementsByTagName("chapter")[1], doc.getElementsByTagName("chapter")[3]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" />' +
+ '<chapter id="2"><title /></chapter>' +
+ '<chapter id="3"><title /><title /></chapter>' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "child::chapter[child::title]", [doc.getElementsByTagName("chapter")[1], doc.getElementsByTagName("chapter")[2]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" />' +
+ '<appendix id="2" />' +
+ '<para id="3" />' +
+ '<chapter id="4" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "child::*[self::chapter or self::appendix]", [doc.getElementsByTagName("chapter")[0], doc.getElementsByTagName("appendix")[0], doc.getElementsByTagName("chapter")[1]]);
+
+var doc = (new DOMParser).parseFromString(
+ '<doc>' +
+ '<chapter id="1" />' +
+ '<appendix id="2" />' +
+ '<para id="3" />' +
+ '<chapter id="4" />' +
+ '<para id="5" />' +
+ '</doc>',
+ 'application/xml');
+test(doc, doc.documentElement, "child::*[self::chapter or self::appendix][position()=last()]", [doc.getElementsByTagName("chapter")[1]]);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/predicates-expected.txt b/LayoutTests/fast/xpath/py-dom-xpath/predicates-expected.txt
new file mode 100644
index 0000000..cc3333d
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/predicates-expected.txt
@@ -0,0 +1,15 @@
+PASS //item[@id >= 2 and @id <= 4]
+PASS /doc/child::item[1]
+PASS //group[@id="g2"]/ancestor::*[1]
+PASS //item[@id="2"]/following-sibling::item[1]
+PASS //item[@id="5"]/preceding-sibling::item[1]
+PASS //group[@id="g2"]/following::item[1]
+PASS //group[@id="g2"]/preceding::item[1]
+PASS //group[@id="g1"]/descendant-or-self::item[1]
+PASS //group[@id="g2"]/ancestor-or-self::*[1]
+PASS //group/descendant::item[number(//choice/@index)*2]
+PASS (//item[@id="5"]/preceding-sibling::item)[1]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/xpath/py-dom-xpath/predicates.html b/LayoutTests/fast/xpath/py-dom-xpath/predicates.html
new file mode 100644
index 0000000..557e6f7
--- /dev/null
+++ b/LayoutTests/fast/xpath/py-dom-xpath/predicates.html
@@ -0,0 +1,55 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+<script src="../xpath-test-pre.js"></script>
+</head>
+<body>
+<div id="console"></div>
+
+<script>
+var doc = (new DOMParser).parseFromString(
+ '<doc id="0">' +
+ '<item id="1" />' +
+ '<group id="g1">' +
+ '<item id="2" />' +
+ '<group id="g2">' +
+ '<item id="3" />' +
+ '</group>' +
+ '<item id="4" />' +
+ '<item id="5" />' +
+ '</group>' +
+ '<item id="6" />' +
+ '<choice index="2" />' +
+ '</doc>',
+ 'application/xml');
+
+var ROOT = doc.documentElement;
+var I1 = ROOT.firstChild;
+var G1 = I1.nextSibling;
+var I2 = G1.firstChild;
+var G2 = I2.nextSibling;
+var I3 = G2.firstChild;
+var I4 = G2.nextSibling;
+var I5 = I4.nextSibling;
+var I6 = G1.nextSibling;
+
+test(doc, doc.documentElement, '//item[@id >= 2 and @id <= 4]', [I2, I3, I4]);
+test(doc, doc.documentElement, '/doc/child::item[1]', [I1]);
+test(doc, doc.documentElement, '//group[@id="g2"]/ancestor::*[1]', [G1]);
+test(doc, doc.documentElement, '//item[@id="2"]/following-sibling::item[1]', [I4]);
+test(doc, doc.documentElement, '//item[@id="5"]/preceding-sibling::item[1]', [I4]);
+test(doc, doc.documentElement, '//group[@id="g2"]/following::item[1]', [I4]);
+test(doc, doc.documentElement, '//group[@id="g2"]/preceding::item[1]', [I2]);
+test(doc, doc.documentElement, '//group[@id="g1"]/descendant-or-self::item[1]', [I2]);
+test(doc, doc.documentElement, '//group[@id="g2"]/ancestor-or-self::*[1]', [G2]);
+test(doc, doc.documentElement, '//group/descendant::item[number(//choice/@index)*2]', [I5]);
+test(doc, doc.documentElement, '(//item[@id="5"]/preceding-sibling::item)[1]', [I2]);
+
+
+var successfullyParsed = true;
+
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
+</html>