diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/dom | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
654 files changed, 74865 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/META.yml b/testing/web-platform/tests/dom/META.yml new file mode 100644 index 0000000000..6fd5b12664 --- /dev/null +++ b/testing/web-platform/tests/dom/META.yml @@ -0,0 +1,5 @@ +spec: https://dom.spec.whatwg.org/ +suggested_reviewers: + - jdm + - zqzhang + - annevk diff --git a/testing/web-platform/tests/dom/abort/AbortSignal.any.js b/testing/web-platform/tests/dom/abort/AbortSignal.any.js new file mode 100644 index 0000000000..3bbdc11a92 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/AbortSignal.any.js @@ -0,0 +1,40 @@ +test(t => { + const signal = AbortSignal.abort(); + assert_true(signal instanceof AbortSignal, "returned object is an AbortSignal"); + assert_true(signal.aborted, "returned signal is already aborted"); +}, "the AbortSignal.abort() static returns an already aborted signal"); + +async_test(t => { + const s = AbortSignal.abort(); + s.addEventListener("abort", t.unreached_func("abort event listener called")); + s.onabort = t.unreached_func("abort event handler called"); + t.step_timeout(() => { t.done(); }, 2000); +}, "signal returned by AbortSignal.abort() should not fire abort event"); + +test(t => { + const signal = AbortSignal.timeout(0); + assert_true(signal instanceof AbortSignal, "returned object is an AbortSignal"); + assert_false(signal.aborted, "returned signal is not already aborted"); +}, "AbortSignal.timeout() returns a non-aborted signal"); + +async_test(t => { + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func_done(() => { + assert_true(signal.aborted, "signal is aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is a DOMException"); + assert_equals(signal.reason.name, "TimeoutError", "signal.reason is a TimeoutError"); + }); +}, "Signal returned by AbortSignal.timeout() times out"); + +async_test(t => { + let result = ""; + for (const value of ["1", "2", "3"]) { + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func(() => { result += value; }); + } + + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func_done(() => { + assert_equals(result, "123", "Timeout order should be 123"); + }); +}, "AbortSignal timeouts fire in order"); diff --git a/testing/web-platform/tests/dom/abort/abort-signal-any.tentative.any.js b/testing/web-platform/tests/dom/abort/abort-signal-any.tentative.any.js new file mode 100644 index 0000000000..b4abb14c1a --- /dev/null +++ b/testing/web-platform/tests/dom/abort/abort-signal-any.tentative.any.js @@ -0,0 +1,4 @@ +// META: script=./resources/abort-signal-any-tests.js + +abortSignalAnySignalOnlyTests(AbortSignal); +abortSignalAnyTests(AbortSignal, AbortController); diff --git a/testing/web-platform/tests/dom/abort/abort-signal-timeout.html b/testing/web-platform/tests/dom/abort/abort-signal-timeout.html new file mode 100644 index 0000000000..2a9c13d614 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/abort-signal-timeout.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>AbortSignal.timeout frame detach</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="iframe"></iframe> +<script> + async_test(t => { + const signal = iframe.contentWindow.AbortSignal.timeout(5); + signal.onabort = t.unreached_func("abort must not fire"); + + iframe.remove(); + + t.step_timeout(() => { + assert_false(signal.aborted); + t.done(); + }, 10); + }, "Signal returned by AbortSignal.timeout() is not aborted after frame detach"); +</script> diff --git a/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html b/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html new file mode 100644 index 0000000000..ee8544a7f5 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html class="test-wait"> +<meta charset="utf-8"> +<iframe id="iframe"></iframe> +<script> + const srcdoc = ` + <!DOCTYPE html> + <meta charset="utf-8"> + <script> + const xhr = new XMLHttpRequest() + setTimeout(() => { + xhr.open('GET', '/', false) + xhr.send() + AbortSignal.timeout(41.62684667994843) + }, 1) + setTimeout(() => { + location.href = "about:blank" + parent.document.documentElement.classList.remove("test-wait") + }, 0) + </` + "script>"; + iframe.srcdoc = srcdoc; +</script> diff --git a/testing/web-platform/tests/dom/abort/event.any.js b/testing/web-platform/tests/dom/abort/event.any.js new file mode 100644 index 0000000000..bbbe28b233 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/event.any.js @@ -0,0 +1,190 @@ +test(t => { + const c = new AbortController(), + s = c.signal; + let state = "begin"; + + assert_false(s.aborted); + assert_true("reason" in s, "signal has reason property"); + assert_equals(s.reason, undefined, "signal.reason is initially undefined"); + + s.addEventListener("abort", + t.step_func(e => { + assert_equals(state, "begin"); + state = "aborted"; + }) + ); + c.abort(); + + assert_equals(state, "aborted"); + assert_true(s.aborted); + assert_true(s.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(s.reason.name, "AbortError", "signal.reason is AbortError"); + + c.abort(); +}, "AbortController abort() should fire event synchronously"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + assert_equals(controller.signal, signal, + "value of controller.signal should not have changed"); + controller.abort(); + assert_equals(controller.signal, signal, + "value of controller.signal should still not have changed"); +}, "controller.signal should always return the same object"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + let eventCount = 0; + signal.onabort = () => { + ++eventCount; + }; + controller.abort(); + assert_true(signal.aborted); + assert_equals(eventCount, 1, "event handler should have been called once"); + controller.abort(); + assert_true(signal.aborted); + assert_equals(eventCount, 1, + "event handler should not have been called again"); +}, "controller.abort() should do nothing the second time it is called"); + +test(t => { + const controller = new AbortController(); + controller.abort(); + controller.signal.onabort = + t.unreached_func("event handler should not be called"); +}, "event handler should not be called if added after controller.abort()"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + signal.onabort = t.step_func(e => { + assert_equals(e.type, "abort", "event type should be abort"); + assert_equals(e.target, signal, "event target should be signal"); + assert_false(e.bubbles, "event should not bubble"); + assert_true(e.isTrusted, "event should be trusted"); + }); + controller.abort(); +}, "the abort event should have the right properties"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + const reason = Error("hello"); + controller.abort(reason); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, reason, "signal.reason"); +}, "AbortController abort(reason) should set signal.reason"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "aborting AbortController without reason creates an \"AbortError\" DOMException"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(undefined); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "AbortController abort(undefined) creates an \"AbortError\" DOMException"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(null); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, null, "signal.reason"); +}, "AbortController abort(null) should set signal.reason"); + +test(t => { + const signal = AbortSignal.abort(); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "static aborting signal should have right properties"); + +test(t => { + const reason = Error("hello"); + const signal = AbortSignal.abort(reason); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, reason, "signal.reason"); +}, "static aborting signal with reason should set signal.reason"); + +test(t => { + const signal = AbortSignal.abort(); + + assert_true( + signal.reason instanceof DOMException, + "signal.reason is a DOMException" + ); + assert_equals( + signal.reason, + signal.reason, + "signal.reason returns the same DOMException" + ); +}, "AbortSignal.reason returns the same DOMException"); + +test(t => { + const controller = new AbortController(); + controller.abort(); + + assert_true( + controller.signal.reason instanceof DOMException, + "signal.reason is a DOMException" + ); + assert_equals( + controller.signal.reason, + controller.signal.reason, + "signal.reason returns the same DOMException" + ); +}, "AbortController.signal.reason returns the same DOMException"); + +test(t => { + const reason = new Error('boom'); + const signal = AbortSignal.abort(reason); + assert_true(signal.aborted); + assert_throws_exactly(reason, () => signal.throwIfAborted()); +}, "throwIfAborted() should throw abort.reason if signal aborted"); + +test(t => { + const signal = AbortSignal.abort('hello'); + assert_true(signal.aborted); + assert_throws_exactly('hello', () => signal.throwIfAborted()); +}, "throwIfAborted() should throw primitive abort.reason if signal aborted"); + +test(t => { + const controller = new AbortController(); + assert_false(controller.signal.aborted); + controller.signal.throwIfAborted(); +}, "throwIfAborted() should not throw if signal not aborted"); + +done(); diff --git a/testing/web-platform/tests/dom/abort/reason-constructor.html b/testing/web-platform/tests/dom/abort/reason-constructor.html new file mode 100644 index 0000000000..0515165a0f --- /dev/null +++ b/testing/web-platform/tests/dom/abort/reason-constructor.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>AbortSignal.reason constructor</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="iframe"></iframe> +<script> + test(() => { + const aborted = iframe.contentWindow.AbortSignal.abort(); + assert_equals(aborted.reason.constructor, iframe.contentWindow.DOMException, "DOMException is using the correct global"); + }, "AbortSignal.reason.constructor should be from iframe"); +</script> diff --git a/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js b/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js new file mode 100644 index 0000000000..66e4141eac --- /dev/null +++ b/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js @@ -0,0 +1,185 @@ +// Tests for AbortSignal.any() and subclasses that don't use a controller. +function abortSignalAnySignalOnlyTests(signalInterface) { + const desc = `${signalInterface.name}.any()` + + test(t => { + const signal = signalInterface.any([]); + assert_false(signal.aborted); + }, `${desc} works with an empty array of signals`); +} + +// Tests for AbortSignal.any() and subclasses that use a controller. +function abortSignalAnyTests(signalInterface, controllerInterface) { + const suffix = `(using ${controllerInterface.name})`; + const desc = `${signalInterface.name}.any()`; + + test(t => { + const controller = new controllerInterface(); + const signal = controller.signal; + const cloneSignal = signalInterface.any([signal]); + assert_false(cloneSignal.aborted); + assert_true("reason" in cloneSignal, "cloneSignal has reason property"); + assert_equals(cloneSignal.reason, undefined, + "cloneSignal.reason is initially undefined"); + assert_not_equals(signal, cloneSignal, + `${desc} returns a new signal.`); + + let eventFired = false; + cloneSignal.onabort = t.step_func((e) => { + assert_equals(e.target, cloneSignal, + `The event target is the signal returned by ${desc}`); + eventFired = true; + }); + + controller.abort("reason string"); + assert_true(signal.aborted); + assert_true(cloneSignal.aborted); + assert_true(eventFired); + assert_equals(cloneSignal.reason, "reason string", + `${desc} propagates the abort reason`); + }, `${desc} follows a single signal ${suffix}`); + + test(t => { + for (let i = 0; i < 3; ++i) { + const controllers = []; + for (let j = 0; j < 3; ++j) { + controllers.push(new controllerInterface()); + } + const combinedSignal = signalInterface.any(controllers.map(c => c.signal)); + + let eventFired = false; + combinedSignal.onabort = t.step_func((e) => { + assert_equals(e.target, combinedSignal, + `The event target is the signal returned by ${desc}`); + eventFired = true; + }); + + controllers[i].abort(); + assert_true(eventFired); + assert_true(combinedSignal.aborted); + assert_true(combinedSignal.reason instanceof DOMException, + "signal.reason is a DOMException"); + assert_equals(combinedSignal.reason.name, "AbortError", + "signal.reason is a AbortError"); + } + }, `${desc} follows multiple signals ${suffix}`); + + test(t => { + const controllers = []; + for (let i = 0; i < 3; ++i) { + controllers.push(new controllerInterface()); + } + controllers[1].abort("reason 1"); + controllers[2].abort("reason 2"); + + const signal = signalInterface.any(controllers.map(c => c.signal)); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason 1", + "The signal should be aborted with the first reason"); + }, `${desc} returns an aborted signal if passed an aborted signal ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + const signal = signalInterface.any([controller.signal, controller.signal]); + assert_false(signal.aborted); + controller.abort("reason"); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason"); + }, `${desc} can be passed the same signal more than once ${suffix}`); + + test(t => { + const controller1 = new controllerInterface(); + controller1.abort("reason 1"); + const controller2 = new controllerInterface(); + controller2.abort("reason 2"); + + const signal = signalInterface.any([controller1.signal, controller2.signal, controller1.signal]); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason 1"); + }, `${desc} uses the first instance of a duplicate signal ${suffix}`); + + test(t => { + for (let i = 0; i < 3; ++i) { + const controllers = []; + for (let j = 0; j < 3; ++j) { + controllers.push(new controllerInterface()); + } + const combinedSignal1 = + signalInterface.any([controllers[0].signal, controllers[1].signal]); + const combinedSignal2 = + signalInterface.any([combinedSignal1, controllers[2].signal]); + + let eventFired = false; + combinedSignal2.onabort = t.step_func((e) => { + eventFired = true; + }); + + controllers[i].abort(); + assert_true(eventFired); + assert_true(combinedSignal2.aborted); + assert_true(combinedSignal2.reason instanceof DOMException, + "signal.reason is a DOMException"); + assert_equals(combinedSignal2.reason.name, "AbortError", + "signal.reason is a AbortError"); + } + }, `${desc} signals are composable ${suffix}`); + + async_test(t => { + const controller = new controllerInterface(); + const timeoutSignal = AbortSignal.timeout(5); + + const combinedSignal = signalInterface.any([controller.signal, timeoutSignal]); + + combinedSignal.onabort = t.step_func_done(() => { + assert_true(combinedSignal.aborted); + assert_true(combinedSignal.reason instanceof DOMException, + "combinedSignal.reason is a DOMException"); + assert_equals(combinedSignal.reason.name, "TimeoutError", + "combinedSignal.reason is a TimeoutError"); + }); + }, `${desc} works with signals returned by AbortSignal.timeout() ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + let combined = signalInterface.any([controller.signal]); + combined = signalInterface.any([combined]); + combined = signalInterface.any([combined]); + combined = signalInterface.any([combined]); + + let eventFired = false; + combined.onabort = () => { + eventFired = true; + } + + assert_false(eventFired); + assert_false(combined.aborted); + + controller.abort("the reason"); + + assert_true(eventFired); + assert_true(combined.aborted); + assert_equals(combined.reason, "the reason"); + }, `${desc} works with intermediate signals ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + const signals = []; + // The first event should be dispatched on the originating signal. + signals.push(controller.signal); + // All dependents are linked to `controller.signal` (never to another + // composite signal), so this is the order events should fire. + signals.push(signalInterface.any([controller.signal])); + signals.push(signalInterface.any([controller.signal])); + signals.push(signalInterface.any([signals[0]])); + signals.push(signalInterface.any([signals[1]])); + + let result = ""; + for (let i = 0; i < signals.length; i++) { + signals[i].addEventListener('abort', () => { + result += i; + }); + } + controller.abort(); + assert_equals(result, "01234"); + }, `Abort events for ${desc} signals fire in the right order ${suffix}`); +} diff --git a/testing/web-platform/tests/dom/attributes-are-nodes.html b/testing/web-platform/tests/dom/attributes-are-nodes.html new file mode 100644 index 0000000000..54ff4ccaec --- /dev/null +++ b/testing/web-platform/tests/dom/attributes-are-nodes.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Attributes are Nodes but should not be accepted outside of the `attributes` NamedNodeMap</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-core-changes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const attribute = document.createAttribute("newattribute"); + + assert_true(attribute instanceof Node, "attribute instances are instances of Node"); + assert_true(Attr.prototype instanceof Node, "attribute instances are instances of Node"); + +}, "Attrs are subclasses of Nodes"); + +test(() => { + + const parent = document.createElement("p"); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.appendChild(attribute); + }); + +}, "appendChild with an attribute as the child should fail"); + +test(() => { + + const parent = document.createElement("p"); + parent.appendChild(document.createElement("span")); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.replaceChild(attribute, parent.firstChild); + }); + +}, "replaceChild with an attribute as the child should fail"); + +test(() => { + + const parent = document.createElement("p"); + parent.appendChild(document.createElement("span")); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.insertBefore(attribute, parent.firstChild); + }); + +}, "insertBefore with an attribute as the child should fail"); + +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html b/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html new file mode 100644 index 0000000000..d572d35c04 --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-as-prototype.html @@ -0,0 +1,29 @@ +<!doctype html> +<meta charset=utf-8> +<title>Objects whose prototype is an HTMLCollection</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var obj = Object.create(document.getElementsByTagName("script")); + assert_throws_js(TypeError, function() { + obj.length; + }); +}, "HTMLCollection as a prototype should not allow getting .length on the base object") + +test(function() { + var element = document.createElement("p"); + element.id = "named"; + document.body.appendChild(element); + this.add_cleanup(function() { element.remove() }); + + var collection = document.getElementsByTagName("p"); + assert_equals(collection.named, element); + var object = Object.create(collection); + assert_equals(object.named, element); + object.named = "foo"; + assert_equals(object.named, "foo"); + assert_equals(collection.named, element); +}, "HTMLCollection as a prototype and setting own properties") +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html b/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html new file mode 100644 index 0000000000..99420d4319 --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-delete.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset=utf-8> +<title>Deleting properties from HTMLCollection</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<i id=foo></i> +<script> +let c, expected; +setup(() => { + // These might be cached anyway, so explicitly use a single object. + c = document.getElementsByTagName("i"); + expected = document.getElementById("foo"); +}); + +test(() => { + assert_equals(c[0], expected, "before"); + delete c[0]; + assert_equals(c[0], expected, "after"); +}, "Loose id"); + +test(() => { + assert_equals(c[0], expected, "before"); + assert_throws_js(TypeError, function() { + "use strict"; + delete c[0]; + }); + assert_equals(c[0], expected, "after"); +}, "Strict id"); + +test(() => { + assert_equals(c.foo, expected, "before"); + delete c.foo; + assert_equals(c.foo, expected, "after"); +}, "Loose name"); + +test(() => { + assert_equals(c.foo, expected, "before"); + assert_throws_js(TypeError, function() { + "use strict"; + delete c.foo; + }); + assert_equals(c.foo, expected, "after"); +}, "Strict name"); +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html b/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html new file mode 100644 index 0000000000..4fc34db7f5 --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-empty-name.html @@ -0,0 +1,65 @@ +<!doctype html> +<meta charset=utf-8> +<title>HTMLCollection and empty names</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<div id=test> +<div class=a id></div> +<div class=a name></div> +<a class=a name></a> +</div> +<script> +test(function() { + var c = document.getElementsByTagName("*"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Document.getElementsByTagName"); + +test(function() { + var div = document.getElementById("test"); + var c = div.getElementsByTagName("*"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Element.getElementsByTagName"); + +test(function() { + var c = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "a"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Document.getElementsByTagNameNS"); + +test(function() { + var div = document.getElementById("test"); + var c = div.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "a"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Element.getElementsByTagNameNS"); + +test(function() { + var c = document.getElementsByClassName("a"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Document.getElementsByClassName"); + +test(function() { + var div = document.getElementById("test"); + var c = div.getElementsByClassName("a"); + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Element.getElementsByClassName"); + +test(function() { + var div = document.getElementById("test"); + var c = div.children; + assert_false("" in c, "Empty string should not be in the collection."); + assert_equals(c[""], undefined, "Named getter should return undefined for empty string."); + assert_equals(c.namedItem(""), null, "namedItem should return null for empty string."); +}, "Empty string as a name for Element.children"); +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html b/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html new file mode 100644 index 0000000000..6296fd1b2d --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-iterator.html @@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<link rel="help" href="https://dom.spec.whatwg.org/#interface-htmlcollection"> +<link rel="help" href="https://webidl.spec.whatwg.org/#es-iterator"> +<title>HTMLCollection @@iterator Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<p id="1"></p> +<p id="2"></p> +<p id="3"></p> +<p id="4"></p> +<p id="5"></p> +<script> +"use strict"; + +const paragraphs = document.getElementsByTagName("p"); + +test(() => { + assert_true("length" in paragraphs); +}, "HTMLCollection has length method."); + +test(() => { + assert_false("values" in paragraphs); +}, "HTMLCollection does not have iterable's values method."); + +test(() => { + assert_false("entries" in paragraphs); +}, "HTMLCollection does not have iterable's entries method."); + +test(() => { + assert_false("forEach" in paragraphs); +}, "HTMLCollection does not have iterable's forEach method."); + +test(() => { + assert_true(Symbol.iterator in paragraphs); +}, "HTMLCollection has Symbol.iterator."); + +test(() => { + const ids = "12345"; + let idx = 0; + for (const element of paragraphs) { + assert_equals(element.getAttribute("id"), ids[idx++]); + } +}, "HTMLCollection is iterable via for-of loop."); +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js b/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js new file mode 100644 index 0000000000..7dbfc6ccf6 --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-live-mutations.window.js @@ -0,0 +1,93 @@ +function testHTMLCollection(name, hooks) { + test(() => { + const nodes = { + root: document.createElement("div"), + div1: document.createElement("div"), + div2: document.createElement("div"), + p: document.createElement("p") + }; + + nodes.div1.id = "div1"; + nodes.div2.id = "div2"; + + const list = nodes.root.getElementsByTagName("div"); + + hooks.initial(list, nodes); + + nodes.root.appendChild(nodes.div1); + nodes.root.appendChild(nodes.p); + nodes.root.appendChild(nodes.div2); + + hooks.afterInsertion(list, nodes); + + nodes.root.removeChild(nodes.div1); + + hooks.afterRemoval(list, nodes); + }, `HTMLCollection live mutations: ${name}`); +} + +testHTMLCollection("HTMLCollection.length", { + initial(list) { + assert_equals(list.length, 0); + }, + afterInsertion(list) { + assert_equals(list.length, 2); + }, + afterRemoval(list) { + assert_equals(list.length, 1); + } +}); + +testHTMLCollection("HTMLCollection.item(index)", { + initial(list) { + assert_equals(list.item(0), null); + }, + afterInsertion(list, nodes) { + assert_equals(list.item(0), nodes.div1); + assert_equals(list.item(1), nodes.div2); + }, + afterRemoval(list, nodes) { + assert_equals(list.item(0), nodes.div2); + } +}); + +testHTMLCollection("HTMLCollection[index]", { + initial(list) { + assert_equals(list[0], undefined); + }, + afterInsertion(list, nodes) { + assert_equals(list[0], nodes.div1); + assert_equals(list[1], nodes.div2); + }, + afterRemoval(list, nodes) { + assert_equals(list[0], nodes.div2); + } +}); + +testHTMLCollection("HTMLCollection.namedItem(index)", { + initial(list) { + assert_equals(list.namedItem("div1"), null); + assert_equals(list.namedItem("div2"), null); + }, + afterInsertion(list, nodes) { + assert_equals(list.namedItem("div1"), nodes.div1); + assert_equals(list.namedItem("div2"), nodes.div2); + }, + afterRemoval(list, nodes) { + assert_equals(list.namedItem("div1"), null); + assert_equals(list.namedItem("div2"), nodes.div2); + } +}); + +testHTMLCollection("HTMLCollection ownPropertyNames", { + initial(list) { + assert_object_equals(Object.getOwnPropertyNames(list), []); + }, + afterInsertion(list) { + assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1", "div1", "div2"]); + }, + afterRemoval(list) { + assert_object_equals(Object.getOwnPropertyNames(list), ["0", "div2"]); + } +}); + diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html b/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html new file mode 100644 index 0000000000..99dc425dbe --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-own-props.html @@ -0,0 +1,109 @@ +<!doctype html> +<meta charset=utf-8> +<title>HTMLCollection getters and own properties</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +function append(t, tag, name) { + var element = document.createElement(tag); + if (name) { + element.id = name; + } + document.body.appendChild(element); + t.add_cleanup(function() { element.remove(); }); + return element; +} + +test(function() { + var name = "named", tag = "a"; + var c = document.getElementsByTagName(tag); + var element = append(this, tag, name); + assert_equals(c[name], element); + c[name] = "foo"; + assert_equals(c[name], element); +}, "Setting non-array index while named property exists (loose)"); + +test(function() { + "use strict"; + var name = "named", tag = "b"; + var c = document.getElementsByTagName(tag); + var element = append(this, tag, name); + assert_equals(c[name], element); + assert_throws_js(TypeError, function() { + c[name] = "foo"; + }); + assert_equals(c[name], element); +}, "Setting non-array index while named property exists (strict)"); + +test(function() { + var name = "named", tag = "i"; + var c = document.getElementsByTagName(tag); + assert_equals(c[name], undefined); + c[name] = "foo"; + assert_equals(c[name], "foo"); + + var element = append(this, tag, name); + assert_equals(c[name], "foo"); + assert_equals(c.namedItem(name), element); +}, "Setting non-array index while named property doesn't exist (loose)"); + +test(function() { + "use strict"; + var name = "named", tag = "p"; + var c = document.getElementsByTagName(tag); + assert_equals(c[name], undefined); + c[name] = "foo"; + assert_equals(c[name], "foo"); + + var element = append(this, tag, name); + assert_equals(c[name], "foo"); + assert_equals(c.namedItem(name), element); +}, "Setting non-array index while named property doesn't exist (strict)"); + +test(function() { + var tag = "q"; + var c = document.getElementsByTagName(tag); + var element = append(this, tag); + assert_equals(c[0], element); + c[0] = "foo"; + assert_equals(c[0], element); +}, "Setting array index while indexed property exists (loose)"); + +test(function() { + "use strict"; + var tag = "s"; + var c = document.getElementsByTagName(tag); + var element = append(this, tag); + assert_equals(c[0], element); + assert_throws_js(TypeError, function() { + c[0] = "foo"; + }); + assert_equals(c[0], element); +}, "Setting array index while indexed property exists (strict)"); + +test(function() { + var tag = "u"; + var c = document.getElementsByTagName(tag); + assert_equals(c[0], undefined); + c[0] = "foo"; + assert_equals(c[0], undefined); + + var element = append(this, tag); + assert_equals(c[0], element); +}, "Setting array index while indexed property doesn't exist (loose)"); + +test(function() { + "use strict"; + var tag = "u"; + var c = document.getElementsByTagName(tag); + assert_equals(c[0], undefined); + assert_throws_js(TypeError, function() { + c[0] = "foo"; + }); + assert_equals(c[0], undefined); + + var element = append(this, tag); + assert_equals(c[0], element); +}, "Setting array index while indexed property doesn't exist (strict)"); +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html new file mode 100644 index 0000000000..5339ec31ea --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-indices.html @@ -0,0 +1,179 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<!-- We want to use a tag name that will not interact with our test harness, + so just make one up. "foo" is a good one --> + +<!-- Ids that look like negative indices. These should come first, so we can + assert that lookups for nonnegative indices find these by index --> +<foo id="-2"></foo> +<foo id="-1"></foo> + +<!-- Ids that look like nonnegative indices --> +<foo id="0"></foo> +<foo id="1"></foo> + +<!-- Ids that look like nonnegative indices near 2^31 = 2147483648 --> +<foo id="2147483645"></foo> <!-- 2^31 - 3 --> +<foo id="2147483646"></foo> <!-- 2^31 - 2 --> +<foo id="2147483647"></foo> <!-- 2^31 - 1 --> +<foo id="2147483648"></foo> <!-- 2^31 --> +<foo id="2147483649"></foo> <!-- 2^31 + 1 --> + +<!-- Ids that look like nonnegative indices near 2^32 = 4294967296 --> +<foo id="4294967293"></foo> <!-- 2^32 - 3 --> +<foo id="4294967294"></foo> <!-- 2^32 - 2 --> +<foo id="4294967295"></foo> <!-- 2^32 - 1 --> +<foo id="4294967296"></foo> <!-- 2^32 --> +<foo id="4294967297"></foo> <!-- 2^32 + 1 --> + +<script> +test(function() { + var collection = document.getElementsByTagName("foo"); + assert_equals(collection.item(-2), null); + assert_equals(collection.item(-1), null); + assert_equals(collection.namedItem(-2), document.getElementById("-2")); + assert_equals(collection.namedItem(-1), document.getElementById("-1")); + assert_equals(collection[-2], document.getElementById("-2")); + assert_equals(collection[-1], document.getElementById("-1")); +}, "Handling of property names that look like negative integers"); + +test(function() { + var collection = document.getElementsByTagName("foo"); + assert_equals(collection.item(0), document.getElementById("-2")); + assert_equals(collection.item(1), document.getElementById("-1")); + assert_equals(collection.namedItem(0), document.getElementById("0")); + assert_equals(collection.namedItem(1), document.getElementById("1")); + assert_equals(collection[0], document.getElementById("-2")); + assert_equals(collection[1], document.getElementById("-1")); +}, "Handling of property names that look like small nonnegative integers"); + +test(function() { + var collection = document.getElementsByTagName("foo"); + assert_equals(collection.item(2147483645), null); + assert_equals(collection.item(2147483646), null); + assert_equals(collection.item(2147483647), null); + assert_equals(collection.item(2147483648), null); + assert_equals(collection.item(2147483649), null); + assert_equals(collection.namedItem(2147483645), + document.getElementById("2147483645")); + assert_equals(collection.namedItem(2147483646), + document.getElementById("2147483646")); + assert_equals(collection.namedItem(2147483647), + document.getElementById("2147483647")); + assert_equals(collection.namedItem(2147483648), + document.getElementById("2147483648")); + assert_equals(collection.namedItem(2147483649), + document.getElementById("2147483649")); + assert_equals(collection[2147483645], undefined); + assert_equals(collection[2147483646], undefined); + assert_equals(collection[2147483647], undefined); + assert_equals(collection[2147483648], undefined); + assert_equals(collection[2147483649], undefined); +}, "Handling of property names that look like integers around 2^31"); + +test(function() { + var collection = document.getElementsByTagName("foo"); + assert_equals(collection.item(4294967293), null); + assert_equals(collection.item(4294967294), null); + assert_equals(collection.item(4294967295), null); + assert_equals(collection.item(4294967296), document.getElementById("-2")); + assert_equals(collection.item(4294967297), document.getElementById("-1")); + assert_equals(collection.namedItem(4294967293), + document.getElementById("4294967293")); + assert_equals(collection.namedItem(4294967294), + document.getElementById("4294967294")); + assert_equals(collection.namedItem(4294967295), + document.getElementById("4294967295")); + assert_equals(collection.namedItem(4294967296), + document.getElementById("4294967296")); + assert_equals(collection.namedItem(4294967297), + document.getElementById("4294967297")); + assert_equals(collection[4294967293], undefined); + assert_equals(collection[4294967294], undefined); + assert_equals(collection[4294967295], document.getElementById("4294967295")); + assert_equals(collection[4294967296], document.getElementById("4294967296")); + assert_equals(collection[4294967297], document.getElementById("4294967297")); +}, "Handling of property names that look like integers around 2^32"); + +test(function() { + var elements = document.getElementsByTagName("foo"); + var old_item = elements[0]; + var old_desc = Object.getOwnPropertyDescriptor(elements, 0); + assert_equals(old_desc.value, old_item); + assert_true(old_desc.enumerable); + assert_true(old_desc.configurable); + assert_false(old_desc.writable); + + elements[0] = 5; + assert_equals(elements[0], old_item); + assert_throws_js(TypeError, function() { + "use strict"; + elements[0] = 5; + }); + assert_throws_js(TypeError, function() { + Object.defineProperty(elements, 0, { value: 5 }); + }); + + delete elements[0]; + assert_equals(elements[0], old_item); + + assert_throws_js(TypeError, function() { + "use strict"; + delete elements[0]; + }); + assert_equals(elements[0], old_item); +}, 'Trying to set an expando that would shadow an already-existing indexed property'); + +test(function() { + var elements = document.getElementsByTagName("foo"); + var idx = elements.length; + var old_item = elements[idx]; + var old_desc = Object.getOwnPropertyDescriptor(elements, idx); + assert_equals(old_item, undefined); + assert_equals(old_desc, undefined); + + // [[DefineOwnProperty]] will disallow defining an indexed expando. + elements[idx] = 5; + assert_equals(elements[idx], undefined); + assert_throws_js(TypeError, function() { + "use strict"; + elements[idx] = 5; + }); + assert_throws_js(TypeError, function() { + Object.defineProperty(elements, idx, { value: 5 }); + }); + + // Check that deletions out of range do not throw + delete elements[idx]; + (function() { + "use strict"; + delete elements[idx]; + })(); +}, 'Trying to set an expando with an indexed property name past the end of the list'); + +test(function(){ + var elements = document.getElementsByTagName("foo"); + var old_item = elements[0]; + var old_desc = Object.getOwnPropertyDescriptor(elements, 0); + assert_equals(old_desc.value, old_item); + assert_true(old_desc.enumerable); + assert_true(old_desc.configurable); + assert_false(old_desc.writable); + + Object.prototype[0] = 5; + this.add_cleanup(function () { delete Object.prototype[0]; }); + assert_equals(elements[0], old_item); + + delete elements[0]; + assert_equals(elements[0], old_item); + + assert_throws_js(TypeError, function() { + "use strict"; + delete elements[0]; + }); + assert_equals(elements[0], old_item); +}, 'Trying to delete an indexed property name should never work'); +</script> diff --git a/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html new file mode 100644 index 0000000000..3d21e16692 --- /dev/null +++ b/testing/web-platform/tests/dom/collections/HTMLCollection-supported-property-names.html @@ -0,0 +1,135 @@ +<!doctype html> +<meta charset=utf-8> +<link rel=help href=https://dom.spec.whatwg.org/#interface-htmlcollection> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<div id=log></div> + +<!-- with no attribute --> +<span></span> + +<!-- with `id` attribute --> +<span id=''></span> +<span id='some-id'></span> +<span id='some-id'></span><!-- to ensure no duplicates --> + +<!-- with `name` attribute --> +<span name=''></span> +<span name='some-name'></span> +<span name='some-name'></span><!-- to ensure no duplicates --> + +<!-- with `name` and `id` attribute --> +<span id='another-id' name='another-name'></span> + +<script> +test(function () { + var elements = document.getElementsByTagName("span"); + assert_array_equals( + Object.getOwnPropertyNames(elements), + ['0', '1', '2', '3', '4', '5', '6', '7', 'some-id', 'some-name', 'another-id', 'another-name'] + ); +}, 'Object.getOwnPropertyNames on HTMLCollection'); + +test(function () { + var elem = document.createElementNS('some-random-namespace', 'foo'); + this.add_cleanup(function () {elem.remove();}); + elem.setAttribute("name", "some-name"); + document.body.appendChild(elem); + + var elements = document.getElementsByTagName("foo"); + assert_array_equals(Object.getOwnPropertyNames(elements), ['0']); +}, 'Object.getOwnPropertyNames on HTMLCollection with non-HTML namespace'); + +test(function () { + var elem = document.createElement('foo'); + this.add_cleanup(function () {elem.remove();}); + document.body.appendChild(elem); + + var elements = document.getElementsByTagName("foo"); + elements.someProperty = "some value"; + + assert_array_equals(Object.getOwnPropertyNames(elements), ['0', 'someProperty']); +}, 'Object.getOwnPropertyNames on HTMLCollection with expando object'); + +test(function() { + var elements = document.getElementsByTagName("span"); + var old_item = elements["some-id"]; + var old_desc = Object.getOwnPropertyDescriptor(elements, "some-id"); + assert_equals(old_desc.value, old_item); + assert_false(old_desc.enumerable); + assert_true(old_desc.configurable); + assert_false(old_desc.writable); + + elements["some-id"] = 5; + assert_equals(elements["some-id"], old_item); + assert_throws_js(TypeError, function() { + "use strict"; + elements["some-id"] = 5; + }); + assert_throws_js(TypeError, function() { + Object.defineProperty(elements, "some-id", { value: 5 }); + }); + + delete elements["some-id"]; + assert_equals(elements["some-id"], old_item); + + assert_throws_js(TypeError, function() { + "use strict"; + delete elements["some-id"]; + }); + assert_equals(elements["some-id"], old_item); + +}, 'Trying to set an expando that would shadow an already-existing named property'); + +test(function() { + var elements = document.getElementsByTagName("span"); + var old_item = elements["new-id"]; + var old_desc = Object.getOwnPropertyDescriptor(elements, "new-id"); + assert_equals(old_item, undefined); + assert_equals(old_desc, undefined); + + elements["new-id"] = 5; + assert_equals(elements["new-id"], 5); + + var span = document.createElement("span"); + this.add_cleanup(function () {span.remove();}); + span.id = "new-id"; + document.body.appendChild(span); + + assert_equals(elements.namedItem("new-id"), span); + assert_equals(elements["new-id"], 5); + + delete elements["new-id"]; + assert_equals(elements["new-id"], span); +}, 'Trying to set an expando that shadows a named property that gets added later'); + +test(function() { + var elements = document.getElementsByTagName("span"); + var old_item = elements["new-id2"]; + var old_desc = Object.getOwnPropertyDescriptor(elements, "new-id2"); + assert_equals(old_item, undefined); + assert_equals(old_desc, undefined); + + Object.defineProperty(elements, "new-id2", { configurable: false, writable: + false, value: 5 }); + assert_equals(elements["new-id2"], 5); + + var span = document.createElement("span"); + this.add_cleanup(function () {span.remove();}); + span.id = "new-id2"; + document.body.appendChild(span); + + assert_equals(elements.namedItem("new-id2"), span); + assert_equals(elements["new-id2"], 5); + + delete elements["new-id2"]; + assert_equals(elements["new-id2"], 5); + + assert_throws_js(TypeError, function() { + "use strict"; + delete elements["new-id2"]; + }); + assert_equals(elements["new-id2"], 5); +}, 'Trying to set a non-configurable expando that shadows a named property that gets added later'); +</script> diff --git a/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html b/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html new file mode 100644 index 0000000000..430aa44c3a --- /dev/null +++ b/testing/web-platform/tests/dom/collections/domstringmap-supported-property-names.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>DOMStringMap Test: Supported property names</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> + +<div id="edge1" data-="012">Simple</div> + +<div id="edge2" data-id-="012">Simple</div> + +<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth> + John Doe +</div> + +<div id="user2" data-unique-id="1234567890"> Jane Doe </div> + +<div id="user3" data-unique-id="4324324241"> Jim Doe </div> + +<script> + +test(function() { + var element = document.querySelector('#edge1'); + assert_array_equals(Object.getOwnPropertyNames(element.dataset), + [""]); +}, "Object.getOwnPropertyNames on DOMStringMap, empty data attribute"); + +test(function() { + var element = document.querySelector('#edge2'); + assert_array_equals(Object.getOwnPropertyNames(element.dataset), + ["id-"]); +}, "Object.getOwnPropertyNames on DOMStringMap, data attribute trailing hyphen"); + +test(function() { + var element = document.querySelector('#user'); + assert_array_equals(Object.getOwnPropertyNames(element.dataset), + ['id', 'user', 'dateOfBirth']); +}, "Object.getOwnPropertyNames on DOMStringMap, multiple data attributes"); + +test(function() { + var element = document.querySelector('#user2'); + element.dataset.middleName = "mark"; + assert_array_equals(Object.getOwnPropertyNames(element.dataset), + ['uniqueId', 'middleName']); +}, "Object.getOwnPropertyNames on DOMStringMap, attribute set on dataset in JS"); + +test(function() { + var element = document.querySelector('#user3'); + element.setAttribute("data-age", 30); + assert_array_equals(Object.getOwnPropertyNames(element.dataset), + ['uniqueId', 'age']); +}, "Object.getOwnPropertyNames on DOMStringMap, attribute set on element in JS"); + +</script> diff --git a/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html b/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html new file mode 100644 index 0000000000..2c5dee4efd --- /dev/null +++ b/testing/web-platform/tests/dom/collections/namednodemap-supported-property-names.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>NamedNodeMap Test: Supported property names</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="simple" class="fancy">Simple</div> +<input id="result" type="text" value="" width="200px"> +<script> + +test(function() { + var elt = document.querySelector('#simple'); + assert_array_equals(Object.getOwnPropertyNames(elt.attributes), + ['0','1','id','class']); +}, "Object.getOwnPropertyNames on NamedNodeMap"); + +test(function() { + var result = document.getElementById("result"); + assert_array_equals(Object.getOwnPropertyNames(result.attributes), + ['0','1','2','3','id','type','value','width']); +}, "Object.getOwnPropertyNames on NamedNodeMap of input"); + +test(function() { + var result = document.getElementById("result"); + result.removeAttribute("width"); + assert_array_equals(Object.getOwnPropertyNames(result.attributes), + ['0','1','2','id','type','value']); +}, "Object.getOwnPropertyNames on NamedNodeMap after attribute removal"); + +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/common.js b/testing/web-platform/tests/dom/common.js new file mode 100644 index 0000000000..70367b2eff --- /dev/null +++ b/testing/web-platform/tests/dom/common.js @@ -0,0 +1,1083 @@ +"use strict"; +// Written by Aryeh Gregor <ayg@aryeh.name> + +// TODO: iframes, contenteditable/designMode + +// Everything is done in functions in this test harness, so we have to declare +// all the variables before use to make sure they can be reused. +var testDiv, paras, detachedDiv, detachedPara1, detachedPara2, + foreignDoc, foreignPara1, foreignPara2, xmlDoc, xmlElement, + detachedXmlElement, detachedTextNode, foreignTextNode, + detachedForeignTextNode, xmlTextNode, detachedXmlTextNode, + processingInstruction, detachedProcessingInstruction, comment, + detachedComment, foreignComment, detachedForeignComment, xmlComment, + detachedXmlComment, docfrag, foreignDocfrag, xmlDocfrag, doctype, + foreignDoctype, xmlDoctype; +var testRangesShort, testRanges, testPoints, testNodesShort, testNodes; + +function setupRangeTests() { + testDiv = document.querySelector("#test"); + if (testDiv) { + testDiv.parentNode.removeChild(testDiv); + } + testDiv = document.createElement("div"); + testDiv.id = "test"; + document.body.insertBefore(testDiv, document.body.firstChild); + + paras = []; + paras.push(document.createElement("p")); + paras[0].setAttribute("id", "a"); + // Test some diacritics, to make sure browsers are using code units here + // and not something like grapheme clusters. + paras[0].textContent = "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\n"; + testDiv.appendChild(paras[0]); + + paras.push(document.createElement("p")); + paras[1].setAttribute("id", "b"); + paras[1].setAttribute("style", "display:none"); + paras[1].textContent = "Ijklmnop\n"; + testDiv.appendChild(paras[1]); + + paras.push(document.createElement("p")); + paras[2].setAttribute("id", "c"); + paras[2].textContent = "Qrstuvwx"; + testDiv.appendChild(paras[2]); + + paras.push(document.createElement("p")); + paras[3].setAttribute("id", "d"); + paras[3].setAttribute("style", "display:none"); + paras[3].textContent = "Yzabcdef"; + testDiv.appendChild(paras[3]); + + paras.push(document.createElement("p")); + paras[4].setAttribute("id", "e"); + paras[4].setAttribute("style", "display:none"); + paras[4].textContent = "Ghijklmn"; + testDiv.appendChild(paras[4]); + + detachedDiv = document.createElement("div"); + detachedPara1 = document.createElement("p"); + detachedPara1.appendChild(document.createTextNode("Opqrstuv")); + detachedPara2 = document.createElement("p"); + detachedPara2.appendChild(document.createTextNode("Wxyzabcd")); + detachedDiv.appendChild(detachedPara1); + detachedDiv.appendChild(detachedPara2); + + // Opera doesn't automatically create a doctype for a new HTML document, + // contrary to spec. It also doesn't let you add doctypes to documents + // after the fact through any means I've tried. So foreignDoc in Opera + // will have no doctype, foreignDoctype will be null, and Opera will fail + // some tests somewhat mysteriously as a result. + foreignDoc = document.implementation.createHTMLDocument(""); + foreignPara1 = foreignDoc.createElement("p"); + foreignPara1.appendChild(foreignDoc.createTextNode("Efghijkl")); + foreignPara2 = foreignDoc.createElement("p"); + foreignPara2.appendChild(foreignDoc.createTextNode("Mnopqrst")); + foreignDoc.body.appendChild(foreignPara1); + foreignDoc.body.appendChild(foreignPara2); + + // Now we get to do really silly stuff, which nobody in the universe is + // ever going to actually do, but the spec defines behavior, so too bad. + // Testing is fun! + xmlDoctype = document.implementation.createDocumentType("qorflesnorf", "abcde", "x\"'y"); + xmlDoc = document.implementation.createDocument(null, null, xmlDoctype); + detachedXmlElement = xmlDoc.createElement("everyone-hates-hyphenated-element-names"); + detachedTextNode = document.createTextNode("Uvwxyzab"); + detachedForeignTextNode = foreignDoc.createTextNode("Cdefghij"); + detachedXmlTextNode = xmlDoc.createTextNode("Klmnopqr"); + // PIs only exist in XML documents, so don't bother with document or + // foreignDoc. + detachedProcessingInstruction = xmlDoc.createProcessingInstruction("whippoorwill", "chirp chirp chirp"); + detachedComment = document.createComment("Stuvwxyz"); + // Hurrah, we finally got to "z" at the end! + detachedForeignComment = foreignDoc.createComment("אריה יהודה"); + detachedXmlComment = xmlDoc.createComment("בן חיים אליעזר"); + + // We should also test with document fragments that actually contain stuff + // . . . but, maybe later. + docfrag = document.createDocumentFragment(); + foreignDocfrag = foreignDoc.createDocumentFragment(); + xmlDocfrag = xmlDoc.createDocumentFragment(); + + xmlElement = xmlDoc.createElement("igiveuponcreativenames"); + xmlTextNode = xmlDoc.createTextNode("do re mi fa so la ti"); + xmlElement.appendChild(xmlTextNode); + processingInstruction = xmlDoc.createProcessingInstruction("somePI", 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?'); + xmlDoc.appendChild(xmlElement); + xmlDoc.appendChild(processingInstruction); + xmlComment = xmlDoc.createComment("I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt"); + xmlDoc.appendChild(xmlComment); + + comment = document.createComment("Alphabet soup?"); + testDiv.appendChild(comment); + + foreignComment = foreignDoc.createComment('"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.'); + foreignDoc.appendChild(foreignComment); + foreignTextNode = foreignDoc.createTextNode("I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now."); + foreignDoc.body.appendChild(foreignTextNode); + + doctype = document.doctype; + foreignDoctype = foreignDoc.doctype; + + testRangesShort = [ + // Various ranges within the text node children of different + // paragraphs. All should be valid. + "[paras[0].firstChild, 0, paras[0].firstChild, 0]", + "[paras[0].firstChild, 0, paras[0].firstChild, 1]", + "[paras[0].firstChild, 2, paras[0].firstChild, 8]", + "[paras[0].firstChild, 2, paras[0].firstChild, 9]", + "[paras[1].firstChild, 0, paras[1].firstChild, 0]", + "[paras[1].firstChild, 2, paras[1].firstChild, 9]", + "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 0]", + "[detachedPara1.firstChild, 2, detachedPara1.firstChild, 8]", + "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 0]", + "[foreignPara1.firstChild, 2, foreignPara1.firstChild, 8]", + // Now try testing some elements, not just text nodes. + "[document.documentElement, 0, document.documentElement, 1]", + "[document.documentElement, 0, document.documentElement, 2]", + "[document.documentElement, 1, document.documentElement, 2]", + "[document.head, 1, document.head, 1]", + "[document.body, 4, document.body, 5]", + "[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]", + "[paras[0], 0, paras[0], 1]", + "[detachedPara1, 0, detachedPara1, 1]", + // Now try some ranges that span elements. + "[paras[0].firstChild, 0, paras[1].firstChild, 0]", + "[paras[0].firstChild, 0, paras[1].firstChild, 8]", + "[paras[0].firstChild, 3, paras[3], 1]", + // How about something that spans a node and its descendant? + "[paras[0], 0, paras[0].firstChild, 7]", + "[testDiv, 2, paras[4], 1]", + // Then a few more interesting things just for good measure. + "[document, 0, document, 1]", + "[document, 0, document, 2]", + "[comment, 2, comment, 3]", + "[testDiv, 0, comment, 5]", + "[foreignDoc, 1, foreignComment, 2]", + "[foreignDoc.body, 0, foreignTextNode, 36]", + "[xmlDoc, 1, xmlComment, 0]", + "[detachedTextNode, 0, detachedTextNode, 8]", + "[detachedForeignTextNode, 0, detachedForeignTextNode, 8]", + "[detachedXmlTextNode, 0, detachedXmlTextNode, 8]", + "[detachedComment, 3, detachedComment, 4]", + "[detachedForeignComment, 0, detachedForeignComment, 1]", + "[detachedXmlComment, 2, detachedXmlComment, 6]", + "[docfrag, 0, docfrag, 0]", + "[processingInstruction, 0, processingInstruction, 4]", + ]; + + testRanges = testRangesShort.concat([ + "[paras[1].firstChild, 0, paras[1].firstChild, 1]", + "[paras[1].firstChild, 2, paras[1].firstChild, 8]", + "[detachedPara1.firstChild, 0, detachedPara1.firstChild, 1]", + "[foreignPara1.firstChild, 0, foreignPara1.firstChild, 1]", + "[foreignDoc.head, 1, foreignDoc.head, 1]", + "[foreignDoc.body, 0, foreignDoc.body, 0]", + "[paras[0], 0, paras[0], 0]", + "[detachedPara1, 0, detachedPara1, 0]", + "[testDiv, 1, paras[2].firstChild, 5]", + "[document.documentElement, 1, document.body, 0]", + "[foreignDoc.documentElement, 1, foreignDoc.body, 0]", + "[document, 1, document, 2]", + "[paras[2].firstChild, 4, comment, 2]", + "[paras[3], 1, comment, 8]", + "[foreignDoc, 0, foreignDoc, 0]", + "[xmlDoc, 0, xmlDoc, 0]", + "[detachedForeignTextNode, 7, detachedForeignTextNode, 7]", + "[detachedXmlTextNode, 7, detachedXmlTextNode, 7]", + "[detachedComment, 5, detachedComment, 5]", + "[detachedForeignComment, 4, detachedForeignComment, 4]", + "[foreignDocfrag, 0, foreignDocfrag, 0]", + "[xmlDocfrag, 0, xmlDocfrag, 0]", + ]); + + testPoints = [ + // Various positions within the page, some invalid. Remember that + // paras[0] is visible, and paras[1] is display: none. + "[paras[0].firstChild, -1]", + "[paras[0].firstChild, 0]", + "[paras[0].firstChild, 1]", + "[paras[0].firstChild, 2]", + "[paras[0].firstChild, 8]", + "[paras[0].firstChild, 9]", + "[paras[0].firstChild, 10]", + "[paras[0].firstChild, 65535]", + "[paras[1].firstChild, -1]", + "[paras[1].firstChild, 0]", + "[paras[1].firstChild, 1]", + "[paras[1].firstChild, 2]", + "[paras[1].firstChild, 8]", + "[paras[1].firstChild, 9]", + "[paras[1].firstChild, 10]", + "[paras[1].firstChild, 65535]", + "[detachedPara1.firstChild, 0]", + "[detachedPara1.firstChild, 1]", + "[detachedPara1.firstChild, 8]", + "[detachedPara1.firstChild, 9]", + "[foreignPara1.firstChild, 0]", + "[foreignPara1.firstChild, 1]", + "[foreignPara1.firstChild, 8]", + "[foreignPara1.firstChild, 9]", + // Now try testing some elements, not just text nodes. + "[document.documentElement, -1]", + "[document.documentElement, 0]", + "[document.documentElement, 1]", + "[document.documentElement, 2]", + "[document.documentElement, 7]", + "[document.head, 1]", + "[document.body, 3]", + "[foreignDoc.documentElement, 0]", + "[foreignDoc.documentElement, 1]", + "[foreignDoc.head, 0]", + "[foreignDoc.body, 1]", + "[paras[0], 0]", + "[paras[0], 1]", + "[paras[0], 2]", + "[paras[1], 0]", + "[paras[1], 1]", + "[paras[1], 2]", + "[detachedPara1, 0]", + "[detachedPara1, 1]", + "[testDiv, 0]", + "[testDiv, 3]", + // Then a few more interesting things just for good measure. + "[document, -1]", + "[document, 0]", + "[document, 1]", + "[document, 2]", + "[document, 3]", + "[comment, -1]", + "[comment, 0]", + "[comment, 4]", + "[comment, 96]", + "[foreignDoc, 0]", + "[foreignDoc, 1]", + "[foreignComment, 2]", + "[foreignTextNode, 0]", + "[foreignTextNode, 36]", + "[xmlDoc, -1]", + "[xmlDoc, 0]", + "[xmlDoc, 1]", + "[xmlDoc, 5]", + "[xmlComment, 0]", + "[xmlComment, 4]", + "[processingInstruction, 0]", + "[processingInstruction, 5]", + "[processingInstruction, 9]", + "[detachedTextNode, 0]", + "[detachedTextNode, 8]", + "[detachedForeignTextNode, 0]", + "[detachedForeignTextNode, 8]", + "[detachedXmlTextNode, 0]", + "[detachedXmlTextNode, 8]", + "[detachedProcessingInstruction, 12]", + "[detachedComment, 3]", + "[detachedComment, 5]", + "[detachedForeignComment, 0]", + "[detachedForeignComment, 4]", + "[detachedXmlComment, 2]", + "[docfrag, 0]", + "[foreignDocfrag, 0]", + "[xmlDocfrag, 0]", + "[doctype, 0]", + "[doctype, -17]", + "[doctype, 1]", + "[foreignDoctype, 0]", + "[xmlDoctype, 0]", + ]; + + testNodesShort = [ + "paras[0]", + "paras[0].firstChild", + "paras[1].firstChild", + "foreignPara1", + "foreignPara1.firstChild", + "detachedPara1", + "detachedPara1.firstChild", + "document", + "detachedDiv", + "foreignDoc", + "foreignPara2", + "xmlDoc", + "xmlElement", + "detachedTextNode", + "foreignTextNode", + "processingInstruction", + "detachedProcessingInstruction", + "comment", + "detachedComment", + "docfrag", + "doctype", + "foreignDoctype", + ]; + + testNodes = testNodesShort.concat([ + "paras[1]", + "detachedPara2", + "detachedPara2.firstChild", + "testDiv", + "detachedXmlElement", + "detachedForeignTextNode", + "xmlTextNode", + "detachedXmlTextNode", + "xmlComment", + "foreignComment", + "detachedForeignComment", + "detachedXmlComment", + "foreignDocfrag", + "xmlDocfrag", + "xmlDoctype", + ]); +} +if ("setup" in window) { + setup(setupRangeTests); +} else { + // Presumably we're running from within an iframe or something + setupRangeTests(); +} + +/** + * The "length" of a node as defined by the Ranges section of DOM4. + */ +function nodeLength(node) { + // "The length of a node node depends on node: + // + // "DocumentType + // "0." + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + return 0; + } + // "Text + // "ProcessingInstruction + // "Comment + // "Its length attribute value." + // Browsers don't historically support the length attribute on + // ProcessingInstruction, so to avoid spurious failures, do + // node.data.length instead of node.length. + if (node.nodeType == Node.TEXT_NODE || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE || node.nodeType == Node.COMMENT_NODE) { + return node.data.length; + } + // "Any other node + // "Its number of children." + return node.childNodes.length; +} + +/** + * Returns the furthest ancestor of a Node as defined by the spec. + */ +function furthestAncestor(node) { + var root = node; + while (root.parentNode != null) { + root = root.parentNode; + } + return root; +} + +/** + * "The ancestor containers of a Node are the Node itself and all its + * ancestors." + * + * Is node1 an ancestor container of node2? + */ +function isAncestorContainer(node1, node2) { + return node1 == node2 || + (node2.compareDocumentPosition(node1) & Node.DOCUMENT_POSITION_CONTAINS); +} + +/** + * Returns the first Node that's after node in tree order, or null if node is + * the last Node. + */ +function nextNode(node) { + if (node.hasChildNodes()) { + return node.firstChild; + } + return nextNodeDescendants(node); +} + +/** + * Returns the last Node that's before node in tree order, or null if node is + * the first Node. + */ +function previousNode(node) { + if (node.previousSibling) { + node = node.previousSibling; + while (node.hasChildNodes()) { + node = node.lastChild; + } + return node; + } + return node.parentNode; +} + +/** + * Returns the next Node that's after node and all its descendants in tree + * order, or null if node is the last Node or an ancestor of it. + */ +function nextNodeDescendants(node) { + while (node && !node.nextSibling) { + node = node.parentNode; + } + if (!node) { + return null; + } + return node.nextSibling; +} + +/** + * Returns the ownerDocument of the Node, or the Node itself if it's a + * Document. + */ +function ownerDocument(node) { + return node.nodeType == Node.DOCUMENT_NODE + ? node + : node.ownerDocument; +} + +/** + * Returns true if ancestor is an ancestor of descendant, false otherwise. + */ +function isAncestor(ancestor, descendant) { + if (!ancestor || !descendant) { + return false; + } + while (descendant && descendant != ancestor) { + descendant = descendant.parentNode; + } + return descendant == ancestor; +} + +/** + * Returns true if ancestor is an inclusive ancestor of descendant, false + * otherwise. + */ +function isInclusiveAncestor(ancestor, descendant) { + return ancestor === descendant || isAncestor(ancestor, descendant); +} + +/** + * Returns true if descendant is a descendant of ancestor, false otherwise. + */ +function isDescendant(descendant, ancestor) { + return isAncestor(ancestor, descendant); +} + +/** + * Returns true if descendant is an inclusive descendant of ancestor, false + * otherwise. + */ +function isInclusiveDescendant(descendant, ancestor) { + return descendant === ancestor || isDescendant(descendant, ancestor); +} + +/** + * The position of two boundary points relative to one another, as defined by + * the spec. + */ +function getPosition(nodeA, offsetA, nodeB, offsetB) { + // "If node A is the same as node B, return equal if offset A equals offset + // B, before if offset A is less than offset B, and after if offset A is + // greater than offset B." + if (nodeA == nodeB) { + if (offsetA == offsetB) { + return "equal"; + } + if (offsetA < offsetB) { + return "before"; + } + if (offsetA > offsetB) { + return "after"; + } + } + + // "If node A is after node B in tree order, compute the position of (node + // B, offset B) relative to (node A, offset A). If it is before, return + // after. If it is after, return before." + if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_FOLLOWING) { + var pos = getPosition(nodeB, offsetB, nodeA, offsetA); + if (pos == "before") { + return "after"; + } + if (pos == "after") { + return "before"; + } + } + + // "If node A is an ancestor of node B:" + if (nodeB.compareDocumentPosition(nodeA) & Node.DOCUMENT_POSITION_CONTAINS) { + // "Let child equal node B." + var child = nodeB; + + // "While child is not a child of node A, set child to its parent." + while (child.parentNode != nodeA) { + child = child.parentNode; + } + + // "If the index of child is less than offset A, return after." + if (indexOf(child) < offsetA) { + return "after"; + } + } + + // "Return before." + return "before"; +} + +/** + * "contained" as defined by DOM Range: "A Node node is contained in a range + * range if node's furthest ancestor is the same as range's root, and (node, 0) + * is after range's start, and (node, length of node) is before range's end." + */ +function isContained(node, range) { + var pos1 = getPosition(node, 0, range.startContainer, range.startOffset); + var pos2 = getPosition(node, nodeLength(node), range.endContainer, range.endOffset); + + return furthestAncestor(node) == furthestAncestor(range.startContainer) + && pos1 == "after" + && pos2 == "before"; +} + +/** + * "partially contained" as defined by DOM Range: "A Node is partially + * contained in a range if it is an ancestor container of the range's start but + * not its end, or vice versa." + */ +function isPartiallyContained(node, range) { + var cond1 = isAncestorContainer(node, range.startContainer); + var cond2 = isAncestorContainer(node, range.endContainer); + return (cond1 && !cond2) || (cond2 && !cond1); +} + +/** + * Index of a node as defined by the spec. + */ +function indexOf(node) { + if (!node.parentNode) { + // No preceding sibling nodes, right? + return 0; + } + var i = 0; + while (node != node.parentNode.childNodes[i]) { + i++; + } + return i; +} + +/** + * extractContents() implementation, following the spec. If an exception is + * supposed to be thrown, will return a string with the name (e.g., + * "HIERARCHY_REQUEST_ERR") instead of a document fragment. It might also + * return an arbitrary human-readable string if a condition is hit that implies + * a spec bug. + */ +function myExtractContents(range) { + // "Let frag be a new DocumentFragment whose ownerDocument is the same as + // the ownerDocument of the context object's start node." + var ownerDoc = range.startContainer.nodeType == Node.DOCUMENT_NODE + ? range.startContainer + : range.startContainer.ownerDocument; + var frag = ownerDoc.createDocumentFragment(); + + // "If the context object's start and end are the same, abort this method, + // returning frag." + if (range.startContainer == range.endContainer + && range.startOffset == range.endOffset) { + return frag; + } + + // "Let original start node, original start offset, original end node, and + // original end offset be the context object's start and end nodes and + // offsets, respectively." + var originalStartNode = range.startContainer; + var originalStartOffset = range.startOffset; + var originalEndNode = range.endContainer; + var originalEndOffset = range.endOffset; + + // "If original start node is original end node, and they are a Text, + // ProcessingInstruction, or Comment node:" + if (range.startContainer == range.endContainer + && (range.startContainer.nodeType == Node.TEXT_NODE + || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || range.startContainer.nodeType == Node.COMMENT_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // start node." + var clone = originalStartNode.cloneNode(false); + + // "Set the data of clone to the result of calling + // substringData(original start offset, original end offset − original + // start offset) on original start node." + clone.data = originalStartNode.substringData(originalStartOffset, + originalEndOffset - originalStartOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Call deleteData(original start offset, original end offset − + // original start offset) on original start node." + originalStartNode.deleteData(originalStartOffset, + originalEndOffset - originalStartOffset); + + // "Abort this method, returning frag." + return frag; + } + + // "Let common ancestor equal original start node." + var commonAncestor = originalStartNode; + + // "While common ancestor is not an ancestor container of original end + // node, set common ancestor to its own parent." + while (!isAncestorContainer(commonAncestor, originalEndNode)) { + commonAncestor = commonAncestor.parentNode; + } + + // "If original start node is an ancestor container of original end node, + // let first partially contained child be null." + var firstPartiallyContainedChild; + if (isAncestorContainer(originalStartNode, originalEndNode)) { + firstPartiallyContainedChild = null; + // "Otherwise, let first partially contained child be the first child of + // common ancestor that is partially contained in the context object." + } else { + for (var i = 0; i < commonAncestor.childNodes.length; i++) { + if (isPartiallyContained(commonAncestor.childNodes[i], range)) { + firstPartiallyContainedChild = commonAncestor.childNodes[i]; + break; + } + } + if (!firstPartiallyContainedChild) { + throw "Spec bug: no first partially contained child!"; + } + } + + // "If original end node is an ancestor container of original start node, + // let last partially contained child be null." + var lastPartiallyContainedChild; + if (isAncestorContainer(originalEndNode, originalStartNode)) { + lastPartiallyContainedChild = null; + // "Otherwise, let last partially contained child be the last child of + // common ancestor that is partially contained in the context object." + } else { + for (var i = commonAncestor.childNodes.length - 1; i >= 0; i--) { + if (isPartiallyContained(commonAncestor.childNodes[i], range)) { + lastPartiallyContainedChild = commonAncestor.childNodes[i]; + break; + } + } + if (!lastPartiallyContainedChild) { + throw "Spec bug: no last partially contained child!"; + } + } + + // "Let contained children be a list of all children of common ancestor + // that are contained in the context object, in tree order." + // + // "If any member of contained children is a DocumentType, raise a + // HIERARCHY_REQUEST_ERR exception and abort these steps." + var containedChildren = []; + for (var i = 0; i < commonAncestor.childNodes.length; i++) { + if (isContained(commonAncestor.childNodes[i], range)) { + if (commonAncestor.childNodes[i].nodeType + == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + containedChildren.push(commonAncestor.childNodes[i]); + } + } + + // "If original start node is an ancestor container of original end node, + // set new node to original start node and new offset to original start + // offset." + var newNode, newOffset; + if (isAncestorContainer(originalStartNode, originalEndNode)) { + newNode = originalStartNode; + newOffset = originalStartOffset; + // "Otherwise:" + } else { + // "Let reference node equal original start node." + var referenceNode = originalStartNode; + + // "While reference node's parent is not null and is not an ancestor + // container of original end node, set reference node to its parent." + while (referenceNode.parentNode + && !isAncestorContainer(referenceNode.parentNode, originalEndNode)) { + referenceNode = referenceNode.parentNode; + } + + // "Set new node to the parent of reference node, and new offset to one + // plus the index of reference node." + newNode = referenceNode.parentNode; + newOffset = 1 + indexOf(referenceNode); + } + + // "If first partially contained child is a Text, ProcessingInstruction, or + // Comment node:" + if (firstPartiallyContainedChild + && (firstPartiallyContainedChild.nodeType == Node.TEXT_NODE + || firstPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || firstPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // start node." + var clone = originalStartNode.cloneNode(false); + + // "Set the data of clone to the result of calling substringData() on + // original start node, with original start offset as the first + // argument and (length of original start node − original start offset) + // as the second." + clone.data = originalStartNode.substringData(originalStartOffset, + nodeLength(originalStartNode) - originalStartOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Call deleteData() on original start node, with original start + // offset as the first argument and (length of original start node − + // original start offset) as the second." + originalStartNode.deleteData(originalStartOffset, + nodeLength(originalStartNode) - originalStartOffset); + // "Otherwise, if first partially contained child is not null:" + } else if (firstPartiallyContainedChild) { + // "Let clone be the result of calling cloneNode(false) on first + // partially contained child." + var clone = firstPartiallyContainedChild.cloneNode(false); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Let subrange be a new Range whose start is (original start node, + // original start offset) and whose end is (first partially contained + // child, length of first partially contained child)." + var subrange = ownerDoc.createRange(); + subrange.setStart(originalStartNode, originalStartOffset); + subrange.setEnd(firstPartiallyContainedChild, + nodeLength(firstPartiallyContainedChild)); + + // "Let subfrag be the result of calling extractContents() on + // subrange." + var subfrag = myExtractContents(subrange); + + // "For each child of subfrag, in order, append that child to clone as + // its last child." + for (var i = 0; i < subfrag.childNodes.length; i++) { + clone.appendChild(subfrag.childNodes[i]); + } + } + + // "For each contained child in contained children, append contained child + // as the last child of frag." + for (var i = 0; i < containedChildren.length; i++) { + frag.appendChild(containedChildren[i]); + } + + // "If last partially contained child is a Text, ProcessingInstruction, or + // Comment node:" + if (lastPartiallyContainedChild + && (lastPartiallyContainedChild.nodeType == Node.TEXT_NODE + || lastPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || lastPartiallyContainedChild.nodeType == Node.COMMENT_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // end node." + var clone = originalEndNode.cloneNode(false); + + // "Set the data of clone to the result of calling substringData(0, + // original end offset) on original end node." + clone.data = originalEndNode.substringData(0, originalEndOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Call deleteData(0, original end offset) on original end node." + originalEndNode.deleteData(0, originalEndOffset); + // "Otherwise, if last partially contained child is not null:" + } else if (lastPartiallyContainedChild) { + // "Let clone be the result of calling cloneNode(false) on last + // partially contained child." + var clone = lastPartiallyContainedChild.cloneNode(false); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Let subrange be a new Range whose start is (last partially + // contained child, 0) and whose end is (original end node, original + // end offset)." + var subrange = ownerDoc.createRange(); + subrange.setStart(lastPartiallyContainedChild, 0); + subrange.setEnd(originalEndNode, originalEndOffset); + + // "Let subfrag be the result of calling extractContents() on + // subrange." + var subfrag = myExtractContents(subrange); + + // "For each child of subfrag, in order, append that child to clone as + // its last child." + for (var i = 0; i < subfrag.childNodes.length; i++) { + clone.appendChild(subfrag.childNodes[i]); + } + } + + // "Set the context object's start and end to (new node, new offset)." + range.setStart(newNode, newOffset); + range.setEnd(newNode, newOffset); + + // "Return frag." + return frag; +} + +/** + * insertNode() implementation, following the spec. If an exception is meant + * to be thrown, will return a string with the expected exception name, for + * instance "HIERARCHY_REQUEST_ERR". + */ +function myInsertNode(range, node) { + // "If range's start node is a ProcessingInstruction or Comment node, or is + // a Text node whose parent is null, or is node, throw an + // "HierarchyRequestError" exception and terminate these steps." + if (range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || range.startContainer.nodeType == Node.COMMENT_NODE + || (range.startContainer.nodeType == Node.TEXT_NODE + && !range.startContainer.parentNode) + || range.startContainer == node) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "Let referenceNode be null." + var referenceNode = null; + + // "If range's start node is a Text node, set referenceNode to that Text node." + if (range.startContainer.nodeType == Node.TEXT_NODE) { + referenceNode = range.startContainer; + + // "Otherwise, set referenceNode to the child of start node whose index is + // start offset, and null if there is no such child." + } else { + if (range.startOffset < range.startContainer.childNodes.length) { + referenceNode = range.startContainer.childNodes[range.startOffset]; + } else { + referenceNode = null; + } + } + + // "Let parent be range's start node if referenceNode is null, and + // referenceNode's parent otherwise." + var parent_ = referenceNode === null ? range.startContainer : + referenceNode.parentNode; + + // "Ensure pre-insertion validity of node into parent before + // referenceNode." + var error = ensurePreInsertionValidity(node, parent_, referenceNode); + if (error) { + return error; + } + + // "If range's start node is a Text node, set referenceNode to the result + // of splitting it with offset range's start offset." + if (range.startContainer.nodeType == Node.TEXT_NODE) { + referenceNode = range.startContainer.splitText(range.startOffset); + } + + // "If node is referenceNode, set referenceNode to its next sibling." + if (node == referenceNode) { + referenceNode = referenceNode.nextSibling; + } + + // "If node's parent is not null, remove node from its parent." + if (node.parentNode) { + node.parentNode.removeChild(node); + } + + // "Let newOffset be parent's length if referenceNode is null, and + // referenceNode's index otherwise." + var newOffset = referenceNode === null ? nodeLength(parent_) : + indexOf(referenceNode); + + // "Increase newOffset by node's length if node is a DocumentFragment node, + // and one otherwise." + newOffset += node.nodeType == Node.DOCUMENT_FRAGMENT_NODE ? + nodeLength(node) : 1; + + // "Pre-insert node into parent before referenceNode." + parent_.insertBefore(node, referenceNode); + + // "If range's start and end are the same, set range's end to (parent, + // newOffset)." + if (range.startContainer == range.endContainer + && range.startOffset == range.endOffset) { + range.setEnd(parent_, newOffset); + } +} + +// To make filter() calls more readable +function isElement(node) { + return node.nodeType == Node.ELEMENT_NODE; +} + +function isText(node) { + return node.nodeType == Node.TEXT_NODE; +} + +function isDoctype(node) { + return node.nodeType == Node.DOCUMENT_TYPE_NODE; +} + +function ensurePreInsertionValidity(node, parent_, child) { + // "If parent is not a Document, DocumentFragment, or Element node, throw a + // HierarchyRequestError." + if (parent_.nodeType != Node.DOCUMENT_NODE + && parent_.nodeType != Node.DOCUMENT_FRAGMENT_NODE + && parent_.nodeType != Node.ELEMENT_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If node is a host-including inclusive ancestor of parent, throw a + // HierarchyRequestError." + // + // XXX Does not account for host + if (isInclusiveAncestor(node, parent_)) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If child is not null and its parent is not parent, throw a NotFoundError + // exception." + if (child && child.parentNode != parent_) { + return "NOT_FOUND_ERR"; + } + + // "If node is not a DocumentFragment, DocumentType, Element, Text, + // ProcessingInstruction, or Comment node, throw a HierarchyRequestError." + if (node.nodeType != Node.DOCUMENT_FRAGMENT_NODE + && node.nodeType != Node.DOCUMENT_TYPE_NODE + && node.nodeType != Node.ELEMENT_NODE + && node.nodeType != Node.TEXT_NODE + && node.nodeType != Node.PROCESSING_INSTRUCTION_NODE + && node.nodeType != Node.COMMENT_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If either node is a Text node and parent is a document, or node is a + // doctype and parent is not a document, throw a HierarchyRequestError." + if ((node.nodeType == Node.TEXT_NODE + && parent_.nodeType == Node.DOCUMENT_NODE) + || (node.nodeType == Node.DOCUMENT_TYPE_NODE + && parent_.nodeType != Node.DOCUMENT_NODE)) { + return "HIERARCHY_REQUEST_ERR"; + } + + // "If parent is a document, and any of the statements below, switched on + // node, are true, throw a HierarchyRequestError." + if (parent_.nodeType == Node.DOCUMENT_NODE) { + switch (node.nodeType) { + case Node.DOCUMENT_FRAGMENT_NODE: + // "If node has more than one element child or has a Text node + // child. Otherwise, if node has one element child and either + // parent has an element child, child is a doctype, or child is not + // null and a doctype is following child." + if ([].filter.call(node.childNodes, isElement).length > 1) { + return "HIERARCHY_REQUEST_ERR"; + } + + if ([].some.call(node.childNodes, isText)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if ([].filter.call(node.childNodes, isElement).length == 1) { + if ([].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && child.nodeType == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) + .filter(isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + } + break; + + case Node.ELEMENT_NODE: + // "parent has an element child, child is a doctype, or child is + // not null and a doctype is following child." + if ([].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child.nodeType == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, indexOf(child) + 1) + .filter(isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + break; + + case Node.DOCUMENT_TYPE_NODE: + // "parent has a doctype child, an element is preceding child, or + // child is null and parent has an element child." + if ([].some.call(parent_.childNodes, isDoctype)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (child && [].slice.call(parent_.childNodes, 0, indexOf(child)) + .some(isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + + if (!child && [].some.call(parent_.childNodes, isElement)) { + return "HIERARCHY_REQUEST_ERR"; + } + break; + } + } +} + +/** + * Asserts that two nodes are equal, in the sense of isEqualNode(). If they + * aren't, tries to print a relatively informative reason why not. TODO: Move + * this to testharness.js? + */ +function assertNodesEqual(actual, expected, msg) { + if (!actual.isEqualNode(expected)) { + msg = "Actual and expected mismatch for " + msg + ". "; + + while (actual && expected) { + assert_true(actual.nodeType === expected.nodeType + && actual.nodeName === expected.nodeName + && actual.nodeValue === expected.nodeValue, + "First differing node: expected " + format_value(expected) + + ", got " + format_value(actual) + " [" + msg + "]"); + actual = nextNode(actual); + expected = nextNode(expected); + } + + assert_unreached("DOMs were not equal but we couldn't figure out why"); + } +} + +/** + * Given a DOMException, return the name (e.g., "HIERARCHY_REQUEST_ERR"). + */ +function getDomExceptionName(e) { + var ret = null; + for (var prop in e) { + if (/^[A-Z_]+_ERR$/.test(prop) && e[prop] == e.code) { + return prop; + } + } + + throw "Exception seems to not be a DOMException? " + e; +} + +/** + * Given an array of endpoint data [start container, start offset, end + * container, end offset], returns a Range with those endpoints. + */ +function rangeFromEndpoints(endpoints) { + // If we just use document instead of the ownerDocument of endpoints[0], + // WebKit will throw on setStart/setEnd. This is a WebKit bug, but it's in + // range, not selection, so we don't want to fail anything for it. + var range = ownerDocument(endpoints[0]).createRange(); + range.setStart(endpoints[0], endpoints[1]); + range.setEnd(endpoints[2], endpoints[3]); + return range; +} diff --git a/testing/web-platform/tests/dom/constants.js b/testing/web-platform/tests/dom/constants.js new file mode 100644 index 0000000000..397df96fbc --- /dev/null +++ b/testing/web-platform/tests/dom/constants.js @@ -0,0 +1,11 @@ +function testConstants(objects, constants, msg) { + objects.forEach(function(arr) { + var o = arr[0], desc = arr[1]; + test(function() { + constants.forEach(function(d) { + assert_true(d[0] in o, "Object " + o + " doesn't have " + d[0]) + assert_equals(o[d[0]], d[1], "Object " + o + " value for " + d[0] + " is wrong") + }) + }, "Constants for " + msg + " on " + desc + ".") + }) +} diff --git a/testing/web-platform/tests/dom/eventPathRemoved.html b/testing/web-platform/tests/dom/eventPathRemoved.html new file mode 100644 index 0000000000..1ed9f88753 --- /dev/null +++ b/testing/web-platform/tests/dom/eventPathRemoved.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>Event.path must be removed</title> +<!-- Note that this duplicates a test in historical.html for the purposes of + using in the Interop-2022 metric --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(() => { + const name = "path"; + assert_false(name in Event.prototype) + assert_equals(Event.prototype[name], undefined) + assert_false(name in new Event("test")) + assert_equals((new Event("test"))[name], undefined) + }, "Event.prototype should not have property named 'path'") +</script> diff --git a/testing/web-platform/tests/dom/events/AddEventListenerOptions-once.any.js b/testing/web-platform/tests/dom/events/AddEventListenerOptions-once.any.js new file mode 100644 index 0000000000..b4edd4345c --- /dev/null +++ b/testing/web-platform/tests/dom/events/AddEventListenerOptions-once.any.js @@ -0,0 +1,96 @@ +// META: title=AddEventListenerOptions.once + +"use strict"; + +test(function() { + var invoked_once = false; + var invoked_normal = false; + function handler_once() { + invoked_once = true; + } + function handler_normal() { + invoked_normal = true; + } + + const et = new EventTarget(); + et.addEventListener('test', handler_once, {once: true}); + et.addEventListener('test', handler_normal); + et.dispatchEvent(new Event('test')); + assert_equals(invoked_once, true, "Once handler should be invoked"); + assert_equals(invoked_normal, true, "Normal handler should be invoked"); + + invoked_once = false; + invoked_normal = false; + et.dispatchEvent(new Event('test')); + assert_equals(invoked_once, false, "Once handler shouldn't be invoked again"); + assert_equals(invoked_normal, true, "Normal handler should be invoked again"); + et.removeEventListener('test', handler_normal); +}, "Once listener should be invoked only once"); + +test(function() { + const et = new EventTarget(); + var invoked_count = 0; + function handler() { + invoked_count++; + if (invoked_count == 1) + et.dispatchEvent(new Event('test')); + } + et.addEventListener('test', handler, {once: true}); + et.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 1, "Once handler should only be invoked once"); + + invoked_count = 0; + function handler2() { + invoked_count++; + if (invoked_count == 1) + et.addEventListener('test', handler2, {once: true}); + if (invoked_count <= 2) + et.dispatchEvent(new Event('test')); + } + et.addEventListener('test', handler2, {once: true}); + et.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 2, "Once handler should only be invoked once after each adding"); +}, "Once listener should be invoked only once even if the event is nested"); + +test(function() { + var invoked_count = 0; + function handler() { + invoked_count++; + } + + const et = new EventTarget(); + + et.addEventListener('test', handler, {once: true}); + et.addEventListener('test', handler); + et.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 1, "The handler should only be added once"); + + invoked_count = 0; + et.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 0, "The handler was added as a once listener"); + + invoked_count = 0; + et.addEventListener('test', handler, {once: true}); + et.removeEventListener('test', handler); + et.dispatchEvent(new Event('test')); + assert_equals(invoked_count, 0, "The handler should have been removed"); +}, "Once listener should be added / removed like normal listeners"); + +test(function() { + const et = new EventTarget(); + + var invoked_count = 0; + + for (let n = 4; n > 0; n--) { + et.addEventListener('test', (e) => { + invoked_count++; + e.stopImmediatePropagation(); + }, {once: true}); + } + + for (let n = 4; n > 0; n--) { + et.dispatchEvent(new Event('test')); + } + + assert_equals(invoked_count, 4, "The listeners should be invoked"); +}, "Multiple once listeners should be invoked even if the stopImmediatePropagation is set"); diff --git a/testing/web-platform/tests/dom/events/AddEventListenerOptions-passive.any.js b/testing/web-platform/tests/dom/events/AddEventListenerOptions-passive.any.js new file mode 100644 index 0000000000..8e59cf5b37 --- /dev/null +++ b/testing/web-platform/tests/dom/events/AddEventListenerOptions-passive.any.js @@ -0,0 +1,134 @@ +// META: title=AddEventListenerOptions.passive + +test(function() { + var supportsPassive = false; + var query_options = { + get passive() { + supportsPassive = true; + return false; + }, + get dummy() { + assert_unreached("dummy value getter invoked"); + return false; + } + }; + + const et = new EventTarget(); + et.addEventListener('test_event', null, query_options); + assert_true(supportsPassive, "addEventListener doesn't support the passive option"); + + supportsPassive = false; + et.removeEventListener('test_event', null, query_options); + assert_false(supportsPassive, "removeEventListener supports the passive option when it should not"); +}, "Supports passive option on addEventListener only"); + +function testPassiveValue(optionsValue, expectedDefaultPrevented, existingEventTarget) { + var defaultPrevented = undefined; + var handler = function handler(e) { + assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented"); + e.preventDefault(); + defaultPrevented = e.defaultPrevented; + } + const et = existingEventTarget || new EventTarget(); + et.addEventListener('test', handler, optionsValue); + var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true})); + + assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue)); + assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent"); + + et.removeEventListener('test', handler, optionsValue); +} + +test(function() { + testPassiveValue(undefined, true); + testPassiveValue({}, true); + testPassiveValue({passive: false}, true); + testPassiveValue({passive: true}, false); + testPassiveValue({passive: 0}, true); + testPassiveValue({passive: 1}, false); +}, "preventDefault should be ignored if-and-only-if the passive option is true"); + +function testPassiveValueOnReturnValue(test, optionsValue, expectedDefaultPrevented) { + var defaultPrevented = undefined; + var handler = test.step_func(e => { + assert_false(e.defaultPrevented, "Event prematurely marked defaultPrevented"); + e.returnValue = false; + defaultPrevented = e.defaultPrevented; + }); + const et = new EventTarget(); + et.addEventListener('test', handler, optionsValue); + var uncanceled = et.dispatchEvent(new Event('test', {bubbles: true, cancelable: true})); + + assert_equals(defaultPrevented, expectedDefaultPrevented, "Incorrect defaultPrevented for options: " + JSON.stringify(optionsValue)); + assert_equals(uncanceled, !expectedDefaultPrevented, "Incorrect return value from dispatchEvent"); + + et.removeEventListener('test', handler, optionsValue); +} + +async_test(t => { + testPassiveValueOnReturnValue(t, undefined, true); + testPassiveValueOnReturnValue(t, {}, true); + testPassiveValueOnReturnValue(t, {passive: false}, true); + testPassiveValueOnReturnValue(t, {passive: true}, false); + testPassiveValueOnReturnValue(t, {passive: 0}, true); + testPassiveValueOnReturnValue(t, {passive: 1}, false); + t.done(); +}, "returnValue should be ignored if-and-only-if the passive option is true"); + +function testPassiveWithOtherHandlers(optionsValue, expectedDefaultPrevented) { + var handlerInvoked1 = false; + var dummyHandler1 = function() { + handlerInvoked1 = true; + }; + var handlerInvoked2 = false; + var dummyHandler2 = function() { + handlerInvoked2 = true; + }; + + const et = new EventTarget(); + et.addEventListener('test', dummyHandler1, {passive:true}); + et.addEventListener('test', dummyHandler2); + + testPassiveValue(optionsValue, expectedDefaultPrevented, et); + + assert_true(handlerInvoked1, "Extra passive handler not invoked"); + assert_true(handlerInvoked2, "Extra non-passive handler not invoked"); + + et.removeEventListener('test', dummyHandler1); + et.removeEventListener('test', dummyHandler2); +} + +test(function() { + testPassiveWithOtherHandlers({}, true); + testPassiveWithOtherHandlers({passive: false}, true); + testPassiveWithOtherHandlers({passive: true}, false); +}, "passive behavior of one listener should be unaffected by the presence of other listeners"); + +function testOptionEquivalence(optionValue1, optionValue2, expectedEquality) { + var invocationCount = 0; + var handler = function handler(e) { + invocationCount++; + } + const et = new EventTarget(); + et.addEventListener('test', handler, optionValue1); + et.addEventListener('test', handler, optionValue2); + et.dispatchEvent(new Event('test', {bubbles: true})); + assert_equals(invocationCount, expectedEquality ? 1 : 2, "equivalence of options " + + JSON.stringify(optionValue1) + " and " + JSON.stringify(optionValue2)); + et.removeEventListener('test', handler, optionValue1); + et.removeEventListener('test', handler, optionValue2); +} + +test(function() { + // Sanity check options that should be treated as distinct handlers + testOptionEquivalence({capture:true}, {capture:false, passive:false}, false); + testOptionEquivalence({capture:true}, {passive:true}, false); + + // Option values that should be treated as equivalent + testOptionEquivalence({}, {passive:false}, true); + testOptionEquivalence({passive:true}, {passive:false}, true); + testOptionEquivalence(undefined, {passive:true}, true); + testOptionEquivalence({capture: true, passive: false}, {capture: true, passive: true}, true); + +}, "Equivalence of option values"); + diff --git a/testing/web-platform/tests/dom/events/AddEventListenerOptions-signal.any.js b/testing/web-platform/tests/dom/events/AddEventListenerOptions-signal.any.js new file mode 100644 index 0000000000..e6a3426159 --- /dev/null +++ b/testing/web-platform/tests/dom/events/AddEventListenerOptions-signal.any.js @@ -0,0 +1,143 @@ +'use strict'; + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', handler, { signal: controller.signal }); + et.dispatchEvent(new Event('test')); + assert_equals(count, 1, "Adding a signal still adds a listener"); + et.dispatchEvent(new Event('test')); + assert_equals(count, 2, "The listener was not added with the once flag"); + controller.abort(); + et.dispatchEvent(new Event('test')); + assert_equals(count, 2, "Aborting on the controller removes the listener"); + et.addEventListener('test', handler, { signal: controller.signal }); + et.dispatchEvent(new Event('test')); + assert_equals(count, 2, "Passing an aborted signal never adds the handler"); +}, "Passing an AbortSignal to addEventListener options should allow removing a listener"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', handler, { signal: controller.signal }); + et.removeEventListener('test', handler); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Passing an AbortSignal to addEventListener does not prevent removeEventListener"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', handler, { signal: controller.signal, once: true }); + controller.abort(); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Passing an AbortSignal to addEventListener works with the once flag"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', handler, { signal: controller.signal, once: true }); + et.removeEventListener('test', handler); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Removing a once listener works with a passed signal"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('first', handler, { signal: controller.signal, once: true }); + et.addEventListener('second', handler, { signal: controller.signal, once: true }); + controller.abort(); + et.dispatchEvent(new Event('first')); + et.dispatchEvent(new Event('second')); + assert_equals(count, 0, "The listener was still removed"); +}, "Passing an AbortSignal to multiple listeners"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', handler, { signal: controller.signal, capture: true }); + controller.abort(); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Passing an AbortSignal to addEventListener works with the capture flag"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', () => { + controller.abort(); + }, { signal: controller.signal }); + et.addEventListener('test', handler, { signal: controller.signal }); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Aborting from a listener does not call future listeners"); + +test(function() { + let count = 0; + function handler() { + count++; + } + const et = new EventTarget(); + const controller = new AbortController(); + et.addEventListener('test', () => { + et.addEventListener('test', handler, { signal: controller.signal }); + controller.abort(); + }, { signal: controller.signal }); + et.dispatchEvent(new Event('test')); + assert_equals(count, 0, "The listener was still removed"); +}, "Adding then aborting a listener in another listener does not call it"); + +test(function() { + const et = new EventTarget(); + const ac = new AbortController(); + let count = 0; + et.addEventListener('foo', () => { + et.addEventListener('foo', () => { + count++; + if (count > 5) ac.abort(); + et.dispatchEvent(new Event('foo')); + }, { signal: ac.signal }); + et.dispatchEvent(new Event('foo')); + }, { once: true }); + et.dispatchEvent(new Event('foo')); +}, "Aborting from a nested listener should remove it"); + +test(function() { + const et = new EventTarget(); + assert_throws_js(TypeError, () => { et.addEventListener("foo", () => {}, { signal: null }); }); +}, "Passing null as the signal should throw"); + +test(function() { + const et = new EventTarget(); + assert_throws_js(TypeError, () => { et.addEventListener("foo", null, { signal: null }); }); +}, "Passing null as the signal should throw (listener is also null)"); diff --git a/testing/web-platform/tests/dom/events/Body-FrameSet-Event-Handlers.html b/testing/web-platform/tests/dom/events/Body-FrameSet-Event-Handlers.html new file mode 100644 index 0000000000..3a891158d5 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Body-FrameSet-Event-Handlers.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<html> +<title>HTMLBodyElement and HTMLFrameSetElement Event Handler Tests</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +function getObject(interface) { + switch(interface) { + case "Element": + var e = document.createElementNS("http://example.com/", "example"); + assert_true(e instanceof Element); + assert_false(e instanceof HTMLElement); + assert_false(e instanceof SVGElement); + return e; + case "HTMLElement": + var e = document.createElement("html"); + assert_true(e instanceof HTMLElement); + return e; + case "HTMLBodyElement": + var e = document.createElement("body"); + assert_true(e instanceof HTMLBodyElement); + return e; + case "HTMLFormElement": + var e = document.createElement("form"); + assert_true(e instanceof HTMLFormElement); + return e; + case "HTMLFrameSetElement": + var e = document.createElement("frameset"); + assert_true(e instanceof HTMLFrameSetElement); + return e; + case "SVGElement": + var e = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + assert_true(e instanceof SVGElement); + return e; + case "Document": + assert_true(document instanceof Document); + return document; + case "Window": + assert_true(window instanceof Window); + return window; + } + assert_unreached(); +} + +function testSet(interface, attribute) { + test(function() { + var object = getObject(interface); + function nop() {} + assert_equals(object[attribute], null, "Initially null"); + object[attribute] = nop; + assert_equals(object[attribute], nop, "Return same function"); + object[attribute] = ""; + assert_equals(object[attribute], null, "Return null after setting string"); + object[attribute] = null; + assert_equals(object[attribute], null, "Finally null"); + }, "Set " + interface + "." + attribute); +} + +function testReflect(interface, attribute) { + test(function() { + var element = getObject(interface); + assert_false(element.hasAttribute(attribute), "Initially missing"); + element.setAttribute(attribute, "return"); + assert_equals(element.getAttribute(attribute), "return", "Return same string"); + assert_equals(typeof element[attribute], "function", "Convert to function"); + element.removeAttribute(attribute); + }, "Reflect " + interface + "." + attribute); +} + +function testForwardToWindow(interface, attribute) { + test(function() { + var element = getObject(interface); + window[attribute] = null; + element.setAttribute(attribute, "return"); + assert_equals(typeof window[attribute], "function", "Convert to function"); + assert_equals(window[attribute], element[attribute], "Forward content attribute"); + function nop() {} + element[attribute] = nop; + assert_equals(window[attribute], nop, "Forward IDL attribute"); + window[attribute] = null; + }, "Forward " + interface + "." + attribute + " to Window"); +} + +// Object.propertyIsEnumerable cannot be used because it doesn't +// work with properties inherited through the prototype chain. +function getEnumerable(interface) { + var enumerable = {}; + for (var attribute in getObject(interface)) { + enumerable[attribute] = true; + } + return enumerable; +} + +var enumerableCache = {}; +function testEnumerate(interface, attribute) { + if (!(interface in enumerableCache)) { + enumerableCache[interface] = getEnumerable(interface); + } + test(function() { + assert_true(enumerableCache[interface][attribute]); + }, "Enumerate " + interface + "." + attribute); +} + +[ + "onblur", + "onerror", + "onfocus", + "onload", + "onscroll", + "onresize" +].forEach(function(attribute) { + testSet("HTMLBodyElement", attribute); + testEnumerate("HTMLBodyElement", attribute); + testReflect("HTMLBodyElement", attribute); + testForwardToWindow("HTMLBodyElement", attribute); + testSet("HTMLFrameSetElement", attribute); + testEnumerate("HTMLFrameSetElement", attribute); + testReflect("HTMLFrameSetElement", attribute); + testForwardToWindow("HTMLFrameSetElement", attribute); +}); +</script> +</html> diff --git a/testing/web-platform/tests/dom/events/CustomEvent.html b/testing/web-platform/tests/dom/events/CustomEvent.html new file mode 100644 index 0000000000..87050943f9 --- /dev/null +++ b/testing/web-platform/tests/dom/events/CustomEvent.html @@ -0,0 +1,35 @@ +<!doctype html> +<title>CustomEvent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var type = "foo"; + + var target = document.createElement("div"); + target.addEventListener(type, this.step_func(function(evt) { + assert_equals(evt.type, type); + }), true); + + var fooEvent = document.createEvent("CustomEvent"); + fooEvent.initEvent(type, true, true); + target.dispatchEvent(fooEvent); +}, "CustomEvent dispatching."); + +test(function() { + var e = document.createEvent("CustomEvent"); + assert_throws_js(TypeError, function() { + e.initCustomEvent(); + }); +}, "First parameter to initCustomEvent should be mandatory."); + +test(function() { + var e = document.createEvent("CustomEvent"); + e.initCustomEvent("foo"); + assert_equals(e.type, "foo", "type"); + assert_false(e.bubbles, "bubbles"); + assert_false(e.cancelable, "cancelable"); + assert_equals(e.detail, null, "detail"); +}, "initCustomEvent's default parameter values."); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-cancelBubble.html b/testing/web-platform/tests/dom/events/Event-cancelBubble.html new file mode 100644 index 0000000000..d8d2d7239d --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-cancelBubble.html @@ -0,0 +1,132 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Event.cancelBubble</title> + <link rel="author" title="Chris Rebert" href="http://chrisrebert.com"> + <link rel="help" href="https://dom.spec.whatwg.org/#dom-event-cancelbubble"> + <meta name="flags" content="dom"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> + <div id="outer"> + <div id="middle"> + <div id="inner"></div> + </div> + </div> + <script> +test(function () { + // See https://dom.spec.whatwg.org/#stop-propagation-flag + var e = document.createEvent('Event'); + assert_false(e.cancelBubble, "cancelBubble must be false after event creation."); +}, "cancelBubble must be false when an event is initially created."); + +test(function () { + // See https://dom.spec.whatwg.org/#concept-event-initialize + + // Event which bubbles. + var one = document.createEvent('Event'); + one.cancelBubble = true; + one.initEvent('foo', true/*bubbles*/, false/*cancelable*/); + assert_false(one.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=true]"); + // Re-initialization. + one.cancelBubble = true; + one.initEvent('foo', true/*bubbles*/, false/*cancelable*/); + assert_false(one.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=true]"); + + // Event which doesn't bubble. + var two = document.createEvent('Event'); + two.cancelBubble = true; + two.initEvent('foo', false/*bubbles*/, false/*cancelable*/); + assert_false(two.cancelBubble, "initEvent() must set cancelBubble to false. [bubbles=false]"); + // Re-initialization. + two.cancelBubble = true; + two.initEvent('foo', false/*bubbles*/, false/*cancelable*/); + assert_false(two.cancelBubble, "2nd initEvent() call must set cancelBubble to false. [bubbles=false]"); +}, "Initializing an event must set cancelBubble to false."); + +test(function () { + // See https://dom.spec.whatwg.org/#dom-event-stoppropagation + var e = document.createEvent('Event'); + e.stopPropagation(); + assert_true(e.cancelBubble, "stopPropagation() must set cancelBubble to true."); +}, "stopPropagation() must set cancelBubble to true."); + +test(function () { + // See https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation + var e = document.createEvent('Event'); + e.stopImmediatePropagation(); + assert_true(e.cancelBubble, "stopImmediatePropagation() must set cancelBubble to true."); +}, "stopImmediatePropagation() must set cancelBubble to true."); + +test(function () { + var one = document.createEvent('Event'); + one.stopPropagation(); + one.cancelBubble = false; + assert_true(one.cancelBubble, "cancelBubble must still be true after attempting to set it to false."); +}, "Event.cancelBubble=false must have no effect."); + +test(function (t) { + var outer = document.getElementById('outer'); + var middle = document.getElementById('middle'); + var inner = document.getElementById('inner'); + + outer.addEventListener('barbaz', t.step_func(function () { + assert_unreached("Setting Event.cancelBubble=false after setting Event.cancelBubble=true should have no effect."); + }), false/*useCapture*/); + + middle.addEventListener('barbaz', function (e) { + e.cancelBubble = true;// Stop propagation. + e.cancelBubble = false;// Should be a no-op. + }, false/*useCapture*/); + + var barbazEvent = document.createEvent('Event'); + barbazEvent.initEvent('barbaz', true/*bubbles*/, false/*cancelable*/); + inner.dispatchEvent(barbazEvent); +}, "Event.cancelBubble=false must have no effect during event propagation."); + +test(function () { + // See https://dom.spec.whatwg.org/#concept-event-dispatch + // "14. Unset event’s [...] stop propagation flag," + var e = document.createEvent('Event'); + e.initEvent('foobar', true/*bubbles*/, true/*cancelable*/); + document.body.addEventListener('foobar', function listener(e) { + e.stopPropagation(); + }); + document.body.dispatchEvent(e); + assert_false(e.cancelBubble, "cancelBubble must be false after an event has been dispatched."); +}, "cancelBubble must be false after an event has been dispatched."); + +test(function (t) { + var outer = document.getElementById('outer'); + var middle = document.getElementById('middle'); + var inner = document.getElementById('inner'); + + var propagationStopper = function (e) { + e.cancelBubble = true; + }; + + // Bubble phase + middle.addEventListener('bar', propagationStopper, false/*useCapture*/); + outer.addEventListener('bar', t.step_func(function listenerOne() { + assert_unreached("Setting cancelBubble=true should stop the event from bubbling further."); + }), false/*useCapture*/); + + var barEvent = document.createEvent('Event'); + barEvent.initEvent('bar', true/*bubbles*/, false/*cancelable*/); + inner.dispatchEvent(barEvent); + + // Capture phase + outer.addEventListener('qux', propagationStopper, true/*useCapture*/); + middle.addEventListener('qux', t.step_func(function listenerTwo() { + assert_unreached("Setting cancelBubble=true should stop the event from propagating further, including during the Capture Phase."); + }), true/*useCapture*/); + + var quxEvent = document.createEvent('Event'); + quxEvent.initEvent('qux', false/*bubbles*/, false/*cancelable*/); + inner.dispatchEvent(quxEvent); +}, "Event.cancelBubble=true must set the stop propagation flag."); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-constants.html b/testing/web-platform/tests/dom/events/Event-constants.html new file mode 100644 index 0000000000..635e9894d9 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-constants.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>Event constants</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../constants.js"></script> +<div id="log"></div> +<script> +var objects; +setup(function() { + objects = [ + [Event, "Event interface object"], + [Event.prototype, "Event prototype object"], + [document.createEvent("Event"), "Event object"], + [document.createEvent("CustomEvent"), "CustomEvent object"] + ] +}) +testConstants(objects, [ + ["NONE", 0], + ["CAPTURING_PHASE", 1], + ["AT_TARGET", 2], + ["BUBBLING_PHASE", 3] +], "eventPhase") +</script> diff --git a/testing/web-platform/tests/dom/events/Event-constructors.any.js b/testing/web-platform/tests/dom/events/Event-constructors.any.js new file mode 100644 index 0000000000..faa623ea92 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-constructors.any.js @@ -0,0 +1,120 @@ +// META: title=Event constructors + +test(function() { + assert_throws_js( + TypeError, + () => Event(""), + "Calling Event constructor without 'new' must throw") +}) +test(function() { + assert_throws_js(TypeError, function() { + new Event() + }) +}) +test(function() { + var test_error = { name: "test" } + assert_throws_exactly(test_error, function() { + new Event({ toString: function() { throw test_error; } }) + }) +}) +test(function() { + var ev = new Event("") + assert_equals(ev.type, "") + assert_equals(ev.target, null) + assert_equals(ev.srcElement, null) + assert_equals(ev.currentTarget, null) + assert_equals(ev.eventPhase, Event.NONE) + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, false) + assert_equals(ev.defaultPrevented, false) + assert_equals(ev.returnValue, true) + assert_equals(ev.isTrusted, false) + assert_true(ev.timeStamp > 0) + assert_true("initEvent" in ev) +}) +test(function() { + var ev = new Event("test") + assert_equals(ev.type, "test") + assert_equals(ev.target, null) + assert_equals(ev.srcElement, null) + assert_equals(ev.currentTarget, null) + assert_equals(ev.eventPhase, Event.NONE) + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, false) + assert_equals(ev.defaultPrevented, false) + assert_equals(ev.returnValue, true) + assert_equals(ev.isTrusted, false) + assert_true(ev.timeStamp > 0) + assert_true("initEvent" in ev) +}) +test(function() { + assert_throws_js(TypeError, function() { Event("test") }, + 'Calling Event constructor without "new" must throw'); +}) +test(function() { + var ev = new Event("I am an event", { bubbles: true, cancelable: false}) + assert_equals(ev.type, "I am an event") + assert_equals(ev.bubbles, true) + assert_equals(ev.cancelable, false) +}) +test(function() { + var ev = new Event("@", { bubblesIGNORED: true, cancelable: true}) + assert_equals(ev.type, "@") + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, true) +}) +test(function() { + var ev = new Event("@", { "bubbles\0IGNORED": true, cancelable: true}) + assert_equals(ev.type, "@") + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, true) +}) +test(function() { + var ev = new Event("Xx", { cancelable: true}) + assert_equals(ev.type, "Xx") + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, true) +}) +test(function() { + var ev = new Event("Xx", {}) + assert_equals(ev.type, "Xx") + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, false) +}) +test(function() { + var ev = new Event("Xx", {bubbles: true, cancelable: false, sweet: "x"}) + assert_equals(ev.type, "Xx") + assert_equals(ev.bubbles, true) + assert_equals(ev.cancelable, false) + assert_equals(ev.sweet, undefined) +}) +test(function() { + var called = [] + var ev = new Event("Xx", { + get cancelable() { + called.push("cancelable") + return false + }, + get bubbles() { + called.push("bubbles") + return true; + }, + get sweet() { + called.push("sweet") + return "x" + } + }) + assert_array_equals(called, ["bubbles", "cancelable"]) + assert_equals(ev.type, "Xx") + assert_equals(ev.bubbles, true) + assert_equals(ev.cancelable, false) + assert_equals(ev.sweet, undefined) +}) +test(function() { + var ev = new CustomEvent("$", {detail: 54, sweet: "x", sweet2: "x", cancelable:true}) + assert_equals(ev.type, "$") + assert_equals(ev.bubbles, false) + assert_equals(ev.cancelable, true) + assert_equals(ev.sweet, undefined) + assert_equals(ev.detail, 54) +}) diff --git a/testing/web-platform/tests/dom/events/Event-defaultPrevented-after-dispatch.html b/testing/web-platform/tests/dom/events/Event-defaultPrevented-after-dispatch.html new file mode 100644 index 0000000000..8fef005eb5 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-defaultPrevented-after-dispatch.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Event.defaultPrevented is not reset after dispatchEvent()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id=log></div> +<input id="target" type="hidden" value=""/> +<script> +test(function() { + var EVENT = "foo"; + var TARGET = document.getElementById("target"); + var evt = document.createEvent("Event"); + evt.initEvent(EVENT, true, true); + + TARGET.addEventListener(EVENT, this.step_func(function(e) { + e.preventDefault(); + assert_true(e.defaultPrevented, "during dispatch"); + }), true); + TARGET.dispatchEvent(evt); + + assert_true(evt.defaultPrevented, "after dispatch"); + assert_equals(evt.target, TARGET); + assert_equals(evt.srcElement, TARGET); +}, "Default prevention via preventDefault"); + +test(function() { + var EVENT = "foo"; + var TARGET = document.getElementById("target"); + var evt = document.createEvent("Event"); + evt.initEvent(EVENT, true, true); + + TARGET.addEventListener(EVENT, this.step_func(function(e) { + e.returnValue = false; + assert_true(e.defaultPrevented, "during dispatch"); + }), true); + TARGET.dispatchEvent(evt); + + assert_true(evt.defaultPrevented, "after dispatch"); + assert_equals(evt.target, TARGET); + assert_equals(evt.srcElement, TARGET); +}, "Default prevention via returnValue"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-defaultPrevented.html b/testing/web-platform/tests/dom/events/Event-defaultPrevented.html new file mode 100644 index 0000000000..2548fa3e06 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-defaultPrevented.html @@ -0,0 +1,55 @@ +<!doctype html> +<title>Event.defaultPrevented</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var ev; +test(function() { + ev = document.createEvent("Event"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "When an event is created, defaultPrevented should be initialized to false."); +test(function() { + ev.initEvent("foo", true, false); + assert_equals(ev.bubbles, true, "bubbles"); + assert_equals(ev.cancelable, false, "cancelable"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "initEvent should work correctly (not cancelable)."); +test(function() { + assert_equals(ev.cancelable, false, "cancelable (before)"); + ev.preventDefault(); + assert_equals(ev.cancelable, false, "cancelable (after)"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "preventDefault() should not change defaultPrevented if cancelable is false."); +test(function() { + assert_equals(ev.cancelable, false, "cancelable (before)"); + ev.returnValue = false; + assert_equals(ev.cancelable, false, "cancelable (after)"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "returnValue should not change defaultPrevented if cancelable is false."); +test(function() { + ev.initEvent("foo", true, true); + assert_equals(ev.bubbles, true, "bubbles"); + assert_equals(ev.cancelable, true, "cancelable"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "initEvent should work correctly (cancelable)."); +test(function() { + assert_equals(ev.cancelable, true, "cancelable (before)"); + ev.preventDefault(); + assert_equals(ev.cancelable, true, "cancelable (after)"); + assert_equals(ev.defaultPrevented, true, "defaultPrevented"); +}, "preventDefault() should change defaultPrevented if cancelable is true."); +test(function() { + ev.initEvent("foo", true, true); + assert_equals(ev.cancelable, true, "cancelable (before)"); + ev.returnValue = false; + assert_equals(ev.cancelable, true, "cancelable (after)"); + assert_equals(ev.defaultPrevented, true, "defaultPrevented"); +}, "returnValue should change defaultPrevented if cancelable is true."); +test(function() { + ev.initEvent("foo", true, true); + assert_equals(ev.bubbles, true, "bubbles"); + assert_equals(ev.cancelable, true, "cancelable"); + assert_equals(ev.defaultPrevented, false, "defaultPrevented"); +}, "initEvent should unset defaultPrevented."); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-bubble-canceled.html b/testing/web-platform/tests/dom/events/Event-dispatch-bubble-canceled.html new file mode 100644 index 0000000000..20f398f66f --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-bubble-canceled.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<html> +<head> +<title>Setting cancelBubble=true prior to dispatchEvent()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> + +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> + +<script> +test(function() { + var event = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var current_targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = []; + var actual_targets = []; + var expected_phases = []; + var actual_phases = []; + + var test_event = function(evt) { + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + }; + + for (var i = 0; i < current_targets.length; ++i) { + current_targets[i].addEventListener(event, test_event, true); + current_targets[i].addEventListener(event, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event, true, true); + evt.cancelBubble = true; + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "actual_targets"); + assert_array_equals(actual_phases, expected_phases, "actual_phases"); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-false.html b/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-false.html new file mode 100644 index 0000000000..0f43cb0275 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-false.html @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title> Event.bubbles attribute is set to false </title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-initevent"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +function targetsForDocumentChain(document) { + return [ + document, + document.documentElement, + document.getElementsByTagName("body")[0], + document.getElementById("table"), + document.getElementById("table-body"), + document.getElementById("parent") + ]; +} + +function testChain(document, targetParents, phases, event_type) { + var target = document.getElementById("target"); + var targets = targetParents.concat(target); + var expected_targets = targets.concat(target); + + var actual_targets = [], actual_phases = []; + var test_event = function(evt) { + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + } + + for (var i = 0; i < targets.length; i++) { + targets[i].addEventListener(event_type, test_event, true); + targets[i].addEventListener(event_type, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, false, true); + + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "targets"); + assert_array_equals(actual_phases, phases, "phases"); +} + +var phasesForDocumentChain = [ + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.AT_TARGET, + Event.AT_TARGET, +]; + +test(function () { + var chainWithWindow = [window].concat(targetsForDocumentChain(document)); + testChain( + document, chainWithWindow, [Event.CAPTURING_PHASE].concat(phasesForDocumentChain), "click"); +}, "In window.document with click event"); + +test(function () { + testChain(document, targetsForDocumentChain(document), phasesForDocumentChain, "load"); +}, "In window.document with load event") + +test(function () { + var documentClone = document.cloneNode(true); + testChain( + documentClone, targetsForDocumentChain(documentClone), phasesForDocumentChain, "click"); +}, "In window.document.cloneNode(true)"); + +test(function () { + var newDocument = new Document(); + newDocument.appendChild(document.documentElement.cloneNode(true)); + testChain( + newDocument, targetsForDocumentChain(newDocument), phasesForDocumentChain, "click"); +}, "In new Document()"); + +test(function () { + var HTMLDocument = document.implementation.createHTMLDocument(); + HTMLDocument.body.appendChild(document.getElementById("table").cloneNode(true)); + testChain( + HTMLDocument, targetsForDocumentChain(HTMLDocument), phasesForDocumentChain, "click"); +}, "In DOMImplementation.createHTMLDocument()"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-true.html b/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-true.html new file mode 100644 index 0000000000..b23605a1eb --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-bubbles-true.html @@ -0,0 +1,108 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title> Event.bubbles attribute is set to false </title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-initevent"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +function concatReverse(a) { + return a.concat(a.map(function(x) { return x }).reverse()); +} + +function targetsForDocumentChain(document) { + return [ + document, + document.documentElement, + document.getElementsByTagName("body")[0], + document.getElementById("table"), + document.getElementById("table-body"), + document.getElementById("parent") + ]; +} + +function testChain(document, targetParents, phases, event_type) { + var target = document.getElementById("target"); + var targets = targetParents.concat(target); + var expected_targets = concatReverse(targets); + + var actual_targets = [], actual_phases = []; + var test_event = function(evt) { + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + } + + for (var i = 0; i < targets.length; i++) { + targets[i].addEventListener(event_type, test_event, true); + targets[i].addEventListener(event_type, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "targets"); + assert_array_equals(actual_phases, phases, "phases"); +} + +var phasesForDocumentChain = [ + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.AT_TARGET, + Event.AT_TARGET, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, +]; + +test(function () { + var chainWithWindow = [window].concat(targetsForDocumentChain(document)); + var phases = [Event.CAPTURING_PHASE].concat(phasesForDocumentChain, Event.BUBBLING_PHASE); + testChain(document, chainWithWindow, phases, "click"); +}, "In window.document with click event"); + +test(function () { + testChain(document, targetsForDocumentChain(document), phasesForDocumentChain, "load"); +}, "In window.document with load event") + +test(function () { + var documentClone = document.cloneNode(true); + testChain( + documentClone, targetsForDocumentChain(documentClone), phasesForDocumentChain, "click"); +}, "In window.document.cloneNode(true)"); + +test(function () { + var newDocument = new Document(); + newDocument.appendChild(document.documentElement.cloneNode(true)); + testChain( + newDocument, targetsForDocumentChain(newDocument), phasesForDocumentChain, "click"); +}, "In new Document()"); + +test(function () { + var HTMLDocument = document.implementation.createHTMLDocument(); + HTMLDocument.body.appendChild(document.getElementById("table").cloneNode(true)); + testChain( + HTMLDocument, targetsForDocumentChain(HTMLDocument), phasesForDocumentChain, "click"); +}, "In DOMImplementation.createHTMLDocument()"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-click.html b/testing/web-platform/tests/dom/events/Event-dispatch-click.html new file mode 100644 index 0000000000..010305775d --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-click.html @@ -0,0 +1,369 @@ +<!doctype html> +<title>Synthetic click event "magic"</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<div id=dump style=display:none></div> +<script> +var dump = document.getElementById("dump") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + input.onclick = t.step_func_done(function() { + assert_true(input.checked) + }) + input.click() +}, "basic with click()") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + input.onclick = t.step_func_done(function() { + assert_true(input.checked) + }) + input.dispatchEvent(new MouseEvent("click", {bubbles:true})) // equivalent to the above +}, "basic with dispatchEvent()") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + input.onclick = t.step_func_done(function() { + assert_false(input.checked) + }) + input.dispatchEvent(new Event("click", {bubbles:true})) // no MouseEvent +}, "basic with wrong event class") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + var child = input.appendChild(new Text("does not matter")) + child.dispatchEvent(new MouseEvent("click")) // does not bubble + assert_false(input.checked) + t.done() +}, "look at parents only when event bubbles") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + input.onclick = t.step_func_done(function() { + assert_true(input.checked) + }) + var child = input.appendChild(new Text("does not matter")) + child.dispatchEvent(new MouseEvent("click", {bubbles:true})) +}, "look at parents when event bubbles") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + input.onclick = t.step_func(function() { + assert_false(input.checked, "input pre-click must not be triggered") + }) + var child = input.appendChild(document.createElement("input")) + child.type = "checkbox" + child.onclick = t.step_func(function() { + assert_true(child.checked, "child pre-click must be triggered") + }) + child.dispatchEvent(new MouseEvent("click", {bubbles:true})) + t.done() +}, "pick the first with activation behavior <input type=checkbox>") + +async_test(function(t) { // as above with <a> + window.hrefComplete = t.step_func(function(a) { + assert_equals(a, 'child'); + t.done(); + }); + var link = document.createElement("a") + link.href = "javascript:hrefComplete('link')" // must not be triggered + dump.appendChild(link) + var child = link.appendChild(document.createElement("a")) + child.href = "javascript:hrefComplete('child')" + child.dispatchEvent(new MouseEvent("click", {bubbles:true})) +}, "pick the first with activation behavior <a href>") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + var clickEvent = new MouseEvent("click") + input.onchange = t.step_func_done(function() { + assert_false(clickEvent.defaultPrevented) + assert_true(clickEvent.returnValue) + assert_equals(clickEvent.eventPhase, 0) + assert_equals(clickEvent.currentTarget, null) + assert_equals(clickEvent.target, input) + assert_equals(clickEvent.srcElement, input) + assert_equals(clickEvent.composedPath().length, 0) + }) + input.dispatchEvent(clickEvent) +}, "event state during post-click handling") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + var clickEvent = new MouseEvent("click") + var finalTarget = document.createElement("doesnotmatter") + finalTarget.onclick = t.step_func_done(function() { + assert_equals(clickEvent.target, finalTarget) + assert_equals(clickEvent.srcElement, finalTarget) + }) + input.onchange = t.step_func(function() { + finalTarget.dispatchEvent(clickEvent) + }) + input.dispatchEvent(clickEvent) +}, "redispatch during post-click handling") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + dump.appendChild(input) + var child = input.appendChild(document.createElement("input")) + child.type = "checkbox" + child.disabled = true + child.click() + assert_false(input.checked) + assert_false(child.checked) + t.done() +}, "disabled checkbox still has activation behavior") + +async_test(function(t) { + var state = "start" + + var form = document.createElement("form") + form.onsubmit = t.step_func(() => { + if(state == "start" || state == "checkbox") { + state = "failure" + } else if(state == "form") { + state = "done" + } + return false + }) + dump.appendChild(form) + var button = form.appendChild(document.createElement("button")) + button.type = "submit" + var checkbox = button.appendChild(document.createElement("input")) + checkbox.type = "checkbox" + checkbox.onclick = t.step_func(() => { + if(state == "start") { + assert_unreached() + } else if(state == "checkbox") { + assert_true(checkbox.checked) + } + }) + checkbox.disabled = true + checkbox.click() + assert_equals(state, "start") + + state = "checkbox" + checkbox.disabled = false + checkbox.click() + assert_equals(state, "checkbox") + + state = "form" + button.click() + assert_equals(state, "done") + + t.done() +}, "disabled checkbox still has activation behavior, part 2") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "checkbox" + input.onclick = t.step_func_done(function() { + assert_true(input.checked) + }) + input.click() +}, "disconnected checkbox should be checked") + +async_test(function(t) { + var input = document.createElement("input") + input.type = "radio" + input.onclick = t.step_func_done(function() { + assert_true(input.checked) + }) + input.click() +}, "disconnected radio should be checked") + +async_test(t => { + const input = document.createElement('input'); + input.type = 'checkbox'; + input.onclick = t.step_func_done(() => { + assert_true(input.checked); + }); + input.dispatchEvent(new MouseEvent('click')); +}, `disconnected checkbox should be checked from dispatchEvent(new MouseEvent('click'))`); + +async_test(t => { + const input = document.createElement('input'); + input.type = 'radio'; + input.onclick = t.step_func_done(() => { + assert_true(input.checked); + }); + input.dispatchEvent(new MouseEvent('click')); +}, `disconnected radio should be checked from dispatchEvent(new MouseEvent('click'))`); + +test(() => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + input.dispatchEvent(new MouseEvent("click")); + assert_true(input.checked); +}, `disabled checkbox should be checked from dispatchEvent(new MouseEvent("click"))`); + +test(() => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + input.dispatchEvent(new MouseEvent("click")); + assert_true(input.checked); +}, `disabled radio should be checked from dispatchEvent(new MouseEvent("click"))`); + +async_test(t => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + input.onclick = t.step_func_done(); + input.dispatchEvent(new MouseEvent("click")); +}, `disabled checkbox should fire onclick`); + +async_test(t => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + input.onclick = t.step_func_done(); + input.dispatchEvent(new MouseEvent("click")); +}, `disabled radio should fire onclick`); + +async_test(t => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + input.onclick = t.step_func(ev => { + assert_true(input.checked); + ev.preventDefault(); + queueMicrotask(t.step_func_done(() => { + assert_false(input.checked); + })); + }); + input.dispatchEvent(new MouseEvent("click", { cancelable: true })); +}, `disabled checkbox should get legacy-canceled-activation behavior`); + +async_test(t => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + input.onclick = t.step_func(ev => { + assert_true(input.checked); + ev.preventDefault(); + queueMicrotask(t.step_func_done(() => { + assert_false(input.checked); + })); + }); + input.dispatchEvent(new MouseEvent("click", { cancelable: true })); +}, `disabled radio should get legacy-canceled-activation behavior`); + +test(t => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + const ev = new MouseEvent("click", { cancelable: true }); + ev.preventDefault(); + input.dispatchEvent(ev); + assert_false(input.checked); +}, `disabled checkbox should get legacy-canceled-activation behavior 2`); + +test(t => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + const ev = new MouseEvent("click", { cancelable: true }); + ev.preventDefault(); + input.dispatchEvent(ev); + assert_false(input.checked); +}, `disabled radio should get legacy-canceled-activation behavior 2`); + +for (const type of ["checkbox", "radio"]) { + for (const handler of ["oninput", "onchange"]) { + async_test(t => { + const input = document.createElement("input"); + input.type = type; + input.onclick = t.step_func(ev => { + input.disabled = true; + }); + input[handler] = t.step_func(ev => { + assert_equals(input.checked, true); + t.done(); + }); + dump.append(input); + input.click(); + }, `disabling ${type} in onclick listener shouldn't suppress ${handler}`); + } +} + +async_test(function(t) { + var form = document.createElement("form") + var didSubmit = false + form.onsubmit = t.step_func(() => { + didSubmit = true + return false + }) + var input = form.appendChild(document.createElement("input")) + input.type = "submit" + input.click() + assert_false(didSubmit) + t.done() +}, "disconnected form should not submit") + +async_test(t => { + const form = document.createElement("form"); + form.onsubmit = t.step_func(ev => { + ev.preventDefault(); + assert_unreached("The form is unexpectedly submitted."); + }); + dump.append(form); + const input = form.appendChild(document.createElement("input")); + input.type = "submit" + input.disabled = true; + input.dispatchEvent(new MouseEvent("click", { cancelable: true })); + t.done(); +}, "disabled submit button should not activate"); + +async_test(t => { + const form = document.createElement("form"); + form.onsubmit = t.step_func(ev => { + ev.preventDefault(); + assert_unreached("The form is unexpectedly submitted."); + }); + dump.append(form); + const input = form.appendChild(document.createElement("input")); + input.onclick = t.step_func(() => { + input.disabled = true; + }); + input.type = "submit" + input.dispatchEvent(new MouseEvent("click", { cancelable: true })); + t.done(); +}, "submit button should not activate if the event listener disables it"); + +async_test(t => { + const form = document.createElement("form"); + form.onsubmit = t.step_func(ev => { + ev.preventDefault(); + assert_unreached("The form is unexpectedly submitted."); + }); + dump.append(form); + const input = form.appendChild(document.createElement("input")); + input.onclick = t.step_func(() => { + input.type = "submit" + input.disabled = true; + }); + input.click(); + t.done(); +}, "submit button that morphed from checkbox should not activate"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-click.tentative.html b/testing/web-platform/tests/dom/events/Event-dispatch-click.tentative.html new file mode 100644 index 0000000000..cfdae55ef2 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-click.tentative.html @@ -0,0 +1,78 @@ +<!doctype html> +<title>Clicks on input element</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=dump style=display:none></div> +<script> +var dump = document.getElementById("dump") + +test(t => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + const label = document.createElement("label"); + label.append(input); + dump.append(label); + label.click(); + assert_false(input.checked); +}, "disabled checkbox should not be checked from label click"); + +test(t => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + const label = document.createElement("label"); + label.append(input); + dump.append(label); + label.click(); + assert_false(input.checked); +}, "disabled radio should not be checked from label click"); + +test(t => { + const input = document.createElement("input"); + input.type = "checkbox"; + input.disabled = true; + const label = document.createElement("label"); + label.append(input); + dump.append(label); + label.dispatchEvent(new MouseEvent("click")); + assert_false(input.checked); +}, "disabled checkbox should not be checked from label click by dispatchEvent"); + +test(t => { + const input = document.createElement("input"); + input.type = "radio"; + input.disabled = true; + const label = document.createElement("label"); + label.append(input); + dump.append(label); + label.dispatchEvent(new MouseEvent("click")); + assert_false(input.checked); +}, "disabled radio should not be checked from label click by dispatchEvent"); + +test(t => { + const checkbox = dump.appendChild(document.createElement("input")); + checkbox.type = "checkbox"; + checkbox.onclick = ev => { + checkbox.type = "date"; + ev.preventDefault(); + }; + checkbox.dispatchEvent(new MouseEvent("click", { cancelable: true })); + assert_false(checkbox.checked); +}, "checkbox morphed into another type should not mutate checked state"); + +test(t => { + const radio1 = dump.appendChild(document.createElement("input")); + const radio2 = dump.appendChild(radio1.cloneNode()); + radio1.type = radio2.type = "radio"; + radio1.name = radio2.name = "foo"; + radio2.checked = true; + radio1.onclick = ev => { + radio1.type = "date"; + ev.preventDefault(); + }; + radio1.dispatchEvent(new MouseEvent("click", { cancelable: true })); + assert_false(radio1.checked); + assert_true(radio2.checked); +}, "radio morphed into another type should not steal the existing checked state"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-detached-click.html b/testing/web-platform/tests/dom/events/Event-dispatch-detached-click.html new file mode 100644 index 0000000000..76ea3d78ba --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-detached-click.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Click event on an element not in the document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var EVENT = "click"; + var TARGET = document.createElement("somerandomelement"); + var t = async_test("Click event can be dispatched to an element that is not in the document.") + TARGET.addEventListener(EVENT, t.step_func(function(evt) { + assert_equals(evt.target, TARGET); + assert_equals(evt.srcElement, TARGET); + t.done(); + }), true); + var e = document.createEvent("Event"); + e.initEvent(EVENT, true, true); + TARGET.dispatchEvent(e); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-detached-input-and-change.html b/testing/web-platform/tests/dom/events/Event-dispatch-detached-input-and-change.html new file mode 100644 index 0000000000..a53ae71ac2 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-detached-input-and-change.html @@ -0,0 +1,190 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<title>input and change events for detached checkbox and radio elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_false(inputEventFired); + assert_false(changeEventFired); +}, 'detached checkbox should not emit input or change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_false(inputEventFired); + assert_false(changeEventFired); +}, 'detached radio should not emit input or change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_false(inputEventFired); + assert_false(changeEventFired); +}, `detached checkbox should not emit input or change events on dispatchEvent(new MouseEvent('click')).`); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_false(inputEventFired); + assert_false(changeEventFired); +}, `detached radio should not emit input or change events on dispatchEvent(new MouseEvent('click')).`); + + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + document.body.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, 'attached checkbox should emit input and change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + document.body.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, 'attached radio should emit input and change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + document.body.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, `attached checkbox should emit input and change events on dispatchEvent(new MouseEvent('click')).`); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + document.body.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, `attached radio should emit input and change events on dispatchEvent(new MouseEvent('click')).`); + + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + const shadowHost = document.createElement('div'); + document.body.appendChild(shadowHost); + const shadowRoot = shadowHost.attachShadow({mode: 'open'}); + shadowRoot.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, 'attached to shadow dom checkbox should emit input and change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + const shadowHost = document.createElement('div'); + document.body.appendChild(shadowHost); + const shadowRoot = shadowHost.attachShadow({mode: 'open'}); + shadowRoot.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.click(); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, 'attached to shadow dom radio should emit input and change events on click().'); + +test(() => { + const input = document.createElement('input'); + input.type = 'checkbox'; + const shadowHost = document.createElement('div'); + document.body.appendChild(shadowHost); + const shadowRoot = shadowHost.attachShadow({mode: 'open'}); + shadowRoot.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, `attached to shadow dom checkbox should emit input and change events on dispatchEvent(new MouseEvent('click')).`); + +test(() => { + const input = document.createElement('input'); + input.type = 'radio'; + const shadowHost = document.createElement('div'); + document.body.appendChild(shadowHost); + const shadowRoot = shadowHost.attachShadow({mode: 'open'}); + shadowRoot.appendChild(input); + + let inputEventFired = false; + input.addEventListener('input', () => inputEventFired = true); + let changeEventFired = false; + input.addEventListener('change', () => changeEventFired = true); + input.dispatchEvent(new MouseEvent('click')); + assert_true(inputEventFired); + assert_true(changeEventFired); +}, `attached to shadow dom radio should emit input and change events on dispatchEvent(new MouseEvent('click')).`); + +</script> +</body> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-handlers-changed.html b/testing/web-platform/tests/dom/events/Event-dispatch-handlers-changed.html new file mode 100644 index 0000000000..24e6fd70cb --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-handlers-changed.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title> Dispatch additional events inside an event listener </title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> + +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> + +<script> +test(function() { + var event_type = "bar"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = [ + window, + document, + html, + body, + table, + tbody, + parent, + target, + target, + target, // The additional listener for target runs as we copy its listeners twice + parent, + tbody, + table, + body, + html, + document, + window + ]; + var expected_listeners = [0,0,0,0,0,0,0,0,1,3,1,1,1,1,1,1,1]; + + var actual_targets = [], actual_listeners = []; + var test_event_function = function(i) { + return this.step_func(function(evt) { + actual_targets.push(evt.currentTarget); + actual_listeners.push(i); + + if (evt.eventPhase != evt.BUBBLING_PHASE && evt.currentTarget.foo != 1) { + evt.currentTarget.removeEventListener(event_type, event_handlers[0], true); + evt.currentTarget.addEventListener(event_type, event_handlers[2], true); + evt.currentTarget.foo = 1; + } + + if (evt.eventPhase != evt.CAPTURING_PHASE && evt.currentTarget.foo != 3) { + evt.currentTarget.removeEventListener(event_type, event_handlers[0], false); + evt.currentTarget.addEventListener(event_type, event_handlers[3], false); + evt.currentTarget.foo = 3; + } + }); + }.bind(this); + var event_handlers = [ + test_event_function(0), + test_event_function(1), + test_event_function(2), + test_event_function(3), + ]; + + for (var i = 0; i < targets.length; ++i) { + targets[i].addEventListener(event_type, event_handlers[0], true); + targets[i].addEventListener(event_type, event_handlers[1], false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "actual_targets"); + assert_array_equals(actual_listeners, expected_listeners, "actual_listeners"); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-listener-order.window.js b/testing/web-platform/tests/dom/events/Event-dispatch-listener-order.window.js new file mode 100644 index 0000000000..a01a472872 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-listener-order.window.js @@ -0,0 +1,20 @@ +test(t => { + const hostParent = document.createElement("section"), + host = hostParent.appendChild(document.createElement("div")), + shadowRoot = host.attachShadow({ mode: "closed" }), + targetParent = shadowRoot.appendChild(document.createElement("p")), + target = targetParent.appendChild(document.createElement("span")), + path = [hostParent, host, shadowRoot, targetParent, target], + expected = [], + result = []; + path.forEach((node, index) => { + expected.splice(index, 0, "capturing " + node.nodeName); + expected.splice(index + 1, 0, "bubbling " + node.nodeName); + }); + path.forEach(node => { + node.addEventListener("test", () => { result.push("bubbling " + node.nodeName) }); + node.addEventListener("test", () => { result.push("capturing " + node.nodeName) }, true); + }); + target.dispatchEvent(new CustomEvent('test', { detail: {}, bubbles: true, composed: true })); + assert_array_equals(result, expected); +}); diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-multiple-cancelBubble.html b/testing/web-platform/tests/dom/events/Event-dispatch-multiple-cancelBubble.html new file mode 100644 index 0000000000..2873fd7794 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-multiple-cancelBubble.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> +<head> +<title>Multiple dispatchEvent() and cancelBubble</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id=log></div> + +<div id="parent" style="display: none"> + <input id="target" type="hidden" value=""/> +</div> + +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var actual_result; + var test_event = function(evt) { + actual_result.push(evt.currentTarget); + + if (parent == evt.currentTarget) { + evt.cancelBubble = true; + } + }; + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + target.addEventListener(event_type, test_event, false); + parent.addEventListener(event_type, test_event, false); + document.addEventListener(event_type, test_event, false); + window.addEventListener(event_type, test_event, false); + + actual_result = []; + target.dispatchEvent(evt); + assert_array_equals(actual_result, [target, parent]); + + actual_result = []; + parent.dispatchEvent(evt); + assert_array_equals(actual_result, [parent]); + + actual_result = []; + document.dispatchEvent(evt); + assert_array_equals(actual_result, [document, window]); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-multiple-stopPropagation.html b/testing/web-platform/tests/dom/events/Event-dispatch-multiple-stopPropagation.html new file mode 100644 index 0000000000..72644bd861 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-multiple-stopPropagation.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> +<head> +<title> Multiple dispatchEvent() and stopPropagation() </title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id=log></div> + +<div id="parent" style="display: none"> + <input id="target" type="hidden" value=""/> +</div> + +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var actual_result; + var test_event = function(evt) { + actual_result.push(evt.currentTarget); + + if (parent == evt.currentTarget) { + evt.stopPropagation(); + } + }; + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + target.addEventListener(event_type, test_event, false); + parent.addEventListener(event_type, test_event, false); + document.addEventListener(event_type, test_event, false); + window.addEventListener(event_type, test_event, false); + + actual_result = []; + target.dispatchEvent(evt); + assert_array_equals(actual_result, [target, parent]); + + actual_result = []; + parent.dispatchEvent(evt); + assert_array_equals(actual_result, [parent]); + + actual_result = []; + document.dispatchEvent(evt); + assert_array_equals(actual_result, [document, window]); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-omitted-capture.html b/testing/web-platform/tests/dom/events/Event-dispatch-omitted-capture.html new file mode 100644 index 0000000000..77074d9a3e --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-omitted-capture.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>EventTarget.addEventListener: capture argument omitted</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var targets = [ + target, + document.getElementById("parent"), + document.getElementById("table-body"), + document.getElementById("table"), + document.body, + document.documentElement, + document, + window + ]; + var phases = [ + Event.AT_TARGET, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE + ]; + + var actual_targets = [], actual_phases = []; + var test_event = function(evt) { + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + } + + for (var i = 0; i < targets.length; i++) { + targets[i].addEventListener(event_type, test_event); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + target.dispatchEvent(evt); + + for (var i = 0; i < targets.length; i++) { + targets[i].removeEventListener(event_type, test_event); + } + + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, targets, "targets"); + assert_array_equals(actual_phases, phases, "phases"); +}, "EventTarget.addEventListener with the capture argument omitted"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html b/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html new file mode 100644 index 0000000000..361006a724 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html @@ -0,0 +1,251 @@ +<!doctype html> +<meta charset="utf8"> +<meta name="timeout" content="long"> +<title>Events must dispatch on disabled elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<style> + @keyframes fade { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } + } +</style> +<body> +<script> +// HTML elements that can be disabled +const formElements = ["button", "fieldset", "input", "select", "textarea"]; + +test(() => { + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + // pass becomes true if the event is called and it's the right type. + let pass = false; + const listener = ({ type }) => { + pass = type === "click"; + }; + elem.addEventListener("click", listener, { once: true }); + elem.dispatchEvent(new Event("click")); + assert_true( + pass, + `Untrusted "click" Event didn't dispatch on ${elem.constructor.name}.` + ); + } +}, "Can dispatch untrusted 'click' Events at disabled HTML elements."); + +test(() => { + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + // pass becomes true if the event is called and it's the right type. + let pass = false; + const listener = ({ type }) => { + pass = type === "pass"; + }; + elem.addEventListener("pass", listener, { once: true }); + elem.dispatchEvent(new Event("pass")); + assert_true( + pass, + `Untrusted "pass" Event didn't dispatch on ${elem.constructor.name}` + ); + } +}, "Can dispatch untrusted Events at disabled HTML elements."); + +test(() => { + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + // pass becomes true if the event is called and it's the right type. + let pass = false; + const listener = ({ type }) => { + pass = type === "custom-pass"; + }; + elem.addEventListener("custom-pass", listener, { once: true }); + elem.dispatchEvent(new CustomEvent("custom-pass")); + assert_true( + pass, + `CustomEvent "custom-pass" didn't dispatch on ${elem.constructor.name}` + ); + } +}, "Can dispatch CustomEvents at disabled HTML elements."); + +test(() => { + for (const localName of formElements) { + const elem = document.createElement(localName); + + // Element is disabled... so this click() MUST NOT fire an event. + elem.disabled = true; + let pass = true; + elem.onclick = e => { + pass = false; + }; + elem.click(); + assert_true( + pass, + `.click() must not dispatch "click" event on disabled ${ + elem.constructor.name + }.` + ); + + // Element is (re)enabled... so this click() fires an event. + elem.disabled = false; + pass = false; + elem.onclick = e => { + pass = true; + }; + elem.click(); + assert_true( + pass, + `.click() must dispatch "click" event on enabled ${ + elem.constructor.name + }.` + ); + } +}, "Calling click() on disabled elements must not dispatch events."); + +promise_test(async () => { + // For each form element type, set up transition event handlers. + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + document.body.appendChild(elem); + const eventPromises = [ + "transitionrun", + "transitionstart", + "transitionend", + ].map(eventType => { + return new Promise(r => { + elem.addEventListener(eventType, r); + }); + }); + // Flushing style triggers transition. + getComputedStyle(elem).opacity; + elem.style.transition = "opacity .1s"; + elem.style.opacity = 0; + getComputedStyle(elem).opacity; + // All the events fire... + await Promise.all(eventPromises); + elem.remove(); + } +}, "CSS Transitions transitionrun, transitionstart, transitionend events fire on disabled form elements"); + +promise_test(async () => { + // For each form element type, set up transition event handlers. + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + document.body.appendChild(elem); + getComputedStyle(elem).opacity; + elem.style.transition = "opacity 100s"; + // We use ontransitionstart to cancel the event. + elem.ontransitionstart = () => { + elem.style.display = "none"; + }; + const promiseToCancel = new Promise(r => { + elem.ontransitioncancel = r; + }); + // Flushing style triggers the transition. + elem.style.opacity = 0; + getComputedStyle(elem).opacity; + await promiseToCancel; + // And we are done with this element. + elem.remove(); + } +}, "CSS Transitions transitioncancel event fires on disabled form elements"); + +promise_test(async () => { + // For each form element type, set up transition event handlers. + for (const localName of formElements) { + const elem = document.createElement(localName); + document.body.appendChild(elem); + elem.disabled = true; + const animationStartPromise = new Promise(r => { + elem.addEventListener("animationstart", () => { + // Seek to the second iteration to trigger the animationiteration event + elem.style.animationDelay = "-100s" + r(); + }); + }); + const animationIterationPromise = new Promise(r => { + elem.addEventListener("animationiteration", ()=>{ + elem.style.animationDelay = "-200s" + r(); + }); + }); + const animationEndPromise = new Promise(r => { + elem.addEventListener("animationend", r); + }); + elem.style.animation = "fade 100s 2"; + elem.classList.add("animate"); + // All the events fire... + await Promise.all([ + animationStartPromise, + animationIterationPromise, + animationEndPromise, + ]); + elem.remove(); + } +}, "CSS Animation animationstart, animationiteration, animationend fire on disabled form elements"); + +promise_test(async () => { + // For each form element type, set up transition event handlers. + for (const localName of formElements) { + const elem = document.createElement(localName); + document.body.appendChild(elem); + elem.disabled = true; + + const promiseToCancel = new Promise(r => { + elem.addEventListener("animationcancel", r); + }); + + elem.addEventListener("animationstart", () => { + // Cancel the animation by hiding it. + elem.style.display = "none"; + }); + + // Trigger the animation + elem.style.animation = "fade 100s"; + elem.classList.add("animate"); + await promiseToCancel; + // And we are done with this element. + elem.remove(); + } +}, "CSS Animation's animationcancel event fires on disabled form elements"); + +promise_test(async () => { + for (const localName of formElements) { + const elem = document.createElement(localName); + elem.disabled = true; + document.body.appendChild(elem); + // Element is disabled, so clicking must not fire events + let pass = true; + elem.onclick = e => { + pass = false; + }; + // Disabled elements are not clickable. + await test_driver.click(elem); + assert_true( + pass, + `${elem.constructor.name} is disabled, so onclick must not fire.` + ); + // Element is (re)enabled... so this click() will fire an event. + pass = false; + elem.disabled = false; + elem.onclick = () => { + pass = true; + }; + await test_driver.click(elem); + assert_true( + pass, + `${elem.constructor.name} is enabled, so onclick must fire.` + ); + elem.remove(); + } +}, "Real clicks on disabled elements must not dispatch events."); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-order-at-target.html b/testing/web-platform/tests/dom/events/Event-dispatch-order-at-target.html new file mode 100644 index 0000000000..79673c3256 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-order-at-target.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Listeners are invoked in correct order (AT_TARGET phase)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +"use strict"; + +test(() => { + const el = document.createElement("div"); + const expectedOrder = ["capturing", "bubbling"]; + + let actualOrder = []; + el.addEventListener("click", evt => { + assert_equals(evt.eventPhase, Event.AT_TARGET); + actualOrder.push("bubbling"); + }, false); + el.addEventListener("click", evt => { + assert_equals(evt.eventPhase, Event.AT_TARGET); + actualOrder.push("capturing"); + }, true); + + el.dispatchEvent(new Event("click", {bubbles: true})); + assert_array_equals(actualOrder, expectedOrder, "bubbles: true"); + + actualOrder = []; + el.dispatchEvent(new Event("click", {bubbles: false})); + assert_array_equals(actualOrder, expectedOrder, "bubbles: false"); +}, "Listeners are invoked in correct order (AT_TARGET phase)"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-order.html b/testing/web-platform/tests/dom/events/Event-dispatch-order.html new file mode 100644 index 0000000000..ca94434595 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-order.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Event phases order</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +async_test(function() { + document.addEventListener('DOMContentLoaded', this.step_func_done(function() { + var parent = document.getElementById('parent'); + var child = document.getElementById('child'); + + var order = []; + + parent.addEventListener('click', this.step_func(function(){ order.push(1) }), true); + child.addEventListener('click', this.step_func(function(){ order.push(2) }), false); + parent.addEventListener('click', this.step_func(function(){ order.push(3) }), false); + + child.dispatchEvent(new Event('click', {bubbles: true})); + + assert_array_equals(order, [1, 2, 3]); + })); +}, "Event phases order"); +</script> +<div id="parent"> + <div id="child"></div> +</div> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-other-document.html b/testing/web-platform/tests/dom/events/Event-dispatch-other-document.html new file mode 100644 index 0000000000..689b48087a --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-other-document.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>Custom event on an element in another document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var doc = document.implementation.createHTMLDocument("Demo"); + var element = doc.createElement("div"); + var called = false; + element.addEventListener("foo", this.step_func(function(ev) { + assert_false(called); + called = true; + assert_equals(ev.target, element); + assert_equals(ev.srcElement, element); + })); + doc.body.appendChild(element); + + var event = new Event("foo"); + element.dispatchEvent(event); + assert_true(called); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-propagation-stopped.html b/testing/web-platform/tests/dom/events/Event-dispatch-propagation-stopped.html new file mode 100644 index 0000000000..889f8cfe11 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-propagation-stopped.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<html> +<head> +<title> Calling stopPropagation() prior to dispatchEvent() </title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id=log></div> + +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> + +<script> +test(function() { + var event = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var current_targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = []; + var actual_targets = []; + var expected_phases = []; + var actual_phases = []; + + var test_event = function(evt) { + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + }; + + for (var i = 0; i < current_targets.length; ++i) { + current_targets[i].addEventListener(event, test_event, true); + current_targets[i].addEventListener(event, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event, true, true); + evt.stopPropagation(); + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "actual_targets"); + assert_array_equals(actual_phases, expected_phases, "actual_phases"); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-redispatch.html b/testing/web-platform/tests/dom/events/Event-dispatch-redispatch.html new file mode 100644 index 0000000000..cf861ca177 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-redispatch.html @@ -0,0 +1,124 @@ +<!DOCTYPE html> +<meta charset=urf-8> +<title>EventTarget#dispatchEvent(): redispatching a native event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<button>click me!</button> +<div id=log></div> +<script> +var test_contentLoaded_redispatching = async_test("Redispatching DOMContentLoaded event after being dispatched"); +var test_mouseup_redispatching = async_test("Redispatching mouseup event whose default action dispatches a click event"); +var test_redispatching_of_dispatching_event = async_test("Redispatching event which is being dispatched"); + +var buttonElement = document.querySelector("button"); +var contentLoadedEvent; + +var waitForLoad = new Promise(resolve => { + window.addEventListener("load", () => { requestAnimationFrame(resolve); }, {capture: false, once: true}); +}); + +document.addEventListener("DOMContentLoaded", event => { + contentLoadedEvent = event; + test_redispatching_of_dispatching_event.step(() => { + assert_throws_dom("InvalidStateError", () => { + document.dispatchEvent(contentLoadedEvent); + }, "Trusted DOMContentLoaded event"); + }); +}, {capture: true, once: true}); + +window.addEventListener("load", loadEvent => { + let untrustedContentLoadedEvent; + buttonElement.addEventListener("DOMContentLoaded", event => { + untrustedContentLoadedEvent = event; + test_contentLoaded_redispatching.step(() => { + assert_false(untrustedContentLoadedEvent.isTrusted, "Redispatched DOMContentLoaded event shouldn't be trusted"); + }); + test_redispatching_of_dispatching_event.step(() => { + assert_throws_dom("InvalidStateError", () => { + document.dispatchEvent(untrustedContentLoadedEvent); + }, "Untrusted DOMContentLoaded event"); + }); + }); + + test_contentLoaded_redispatching.step(() => { + assert_true(contentLoadedEvent.isTrusted, "Received DOMContentLoaded event should be trusted before redispatching"); + buttonElement.dispatchEvent(contentLoadedEvent); + assert_false(contentLoadedEvent.isTrusted, "Received DOMContentLoaded event shouldn't be trusted after redispatching"); + assert_not_equals(untrustedContentLoadedEvent, undefined, "Untrusted DOMContentLoaded event should've been fired"); + test_contentLoaded_redispatching.done(); + }); +}, {capture: true, once: true}); + +async function testMouseUpAndClickEvent() { + let mouseupEvent; + buttonElement.addEventListener("mouseup", event => { + mouseupEvent = event; + test_mouseup_redispatching.step(() => { + assert_true(mouseupEvent.isTrusted, "First mouseup event should be trusted"); + }); + test_redispatching_of_dispatching_event.step(() => { + assert_throws_dom("InvalidStateError", () => { + buttonElement.dispatchEvent(mouseupEvent); + }, "Trusted mouseup event"); + }); + }, {once: true}); + + let clickEvent; + buttonElement.addEventListener("click", event => { + clickEvent = event; + test_mouseup_redispatching.step(() => { + assert_true(clickEvent.isTrusted, "First click event should be trusted"); + }); + test_redispatching_of_dispatching_event.step(() => { + assert_throws_dom("InvalidStateError", function() { + buttonElement.dispatchEvent(event); + }, "Trusted click event"); + }); + buttonElement.addEventListener("mouseup", event => { + test_mouseup_redispatching.step(() => { + assert_false(event.isTrusted, "Redispatched mouseup event shouldn't be trusted"); + }); + test_redispatching_of_dispatching_event.step(() => { + assert_throws_dom("InvalidStateError", function() { + buttonElement.dispatchEvent(event); + }, "Untrusted mouseup event"); + }); + }, {once: true}); + function onClick() { + test_mouseup_redispatching.step(() => { + assert_true(false, "click event shouldn't be fired for dispatched mouseup event"); + }); + } + test_mouseup_redispatching.step(() => { + assert_true(mouseupEvent.isTrusted, "Received mouseup event should be trusted before redispatching from click event listener"); + buttonElement.addEventListener("click", onClick); + buttonElement.dispatchEvent(mouseupEvent); + buttonElement.removeEventListener("click", onClick); + assert_false(mouseupEvent.isTrusted, "Received mouseup event shouldn't be trusted after redispatching"); + assert_true(clickEvent.isTrusted, "First click event should still be trusted even after redispatching mouseup event"); + }); + }, {once: true}); + + await waitForLoad; + let bounds = buttonElement.getBoundingClientRect(); + test(() => { assert_true(true); }, `Synthesizing click on button...`); + new test_driver.click(buttonElement) + .then(() => { + test_mouseup_redispatching.step(() => { + assert_not_equals(clickEvent, undefined, "mouseup and click events should've been fired"); + }); + test_mouseup_redispatching.done(); + test_redispatching_of_dispatching_event.done(); + }, (reason) => { + test_mouseup_redispatching.step(() => { + assert_true(false, `Failed to send mouse click due to ${reason}`); + }); + test_mouseup_redispatching.done(); + test_redispatching_of_dispatching_event.done(); + }); +} +testMouseUpAndClickEvent(); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-reenter.html b/testing/web-platform/tests/dom/events/Event-dispatch-reenter.html new file mode 100644 index 0000000000..71f8517bdd --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-reenter.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title> Dispatch additional events inside an event listener </title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = [ + window, document, html, body, table, + target, parent, tbody, + table, body, html, document, window, + tbody, parent, target]; + var actual_targets = []; + var expected_types = [ + "foo", "foo", "foo", "foo", "foo", + "bar", "bar", "bar", + "bar", "bar", "bar", "bar", "bar", + "foo", "foo", "foo" + ]; + + var actual_targets = [], actual_types = []; + var test_event = this.step_func(function(evt) { + actual_targets.push(evt.currentTarget); + actual_types.push(evt.type); + + if (table == evt.currentTarget && event_type == evt.type) { + var e = document.createEvent("Event"); + e.initEvent("bar", true, true); + target.dispatchEvent(e); + } + }); + + for (var i = 0; i < targets.length; ++i) { + targets[i].addEventListener(event_type, test_event, true); + targets[i].addEventListener("bar", test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, false, true); + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "actual_targets"); + assert_array_equals(actual_types, expected_types, "actual_types"); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-target-moved.html b/testing/web-platform/tests/dom/events/Event-dispatch-target-moved.html new file mode 100644 index 0000000000..facb2c7b95 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-target-moved.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title> Determined event propagation path - target moved </title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = targets.concat([target, parent, tbody, table, body, html, document, window]); + var phases = [ + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.AT_TARGET, + Event.AT_TARGET, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + ]; + + var actual_targets = [], actual_phases = []; + var test_event = this.step_func(function(evt) { + if (parent === target.parentNode) { + var table_row = document.getElementById("table-row"); + table_row.appendChild(parent.removeChild(target)); + } + + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + }); + + for (var i = 0; i < targets.length; i++) { + targets[i].addEventListener(event_type, test_event, true); + targets[i].addEventListener(event_type, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "targets"); + assert_array_equals(actual_phases, phases, "phases"); +}, "Event propagation path when an element in it is moved within the DOM"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-target-removed.html b/testing/web-platform/tests/dom/events/Event-dispatch-target-removed.html new file mode 100644 index 0000000000..531799c3ad --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-target-removed.html @@ -0,0 +1,72 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Determined event propagation path - target removed</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var tbody = document.getElementById("table-body"); + var table = document.getElementById("table"); + var body = document.body; + var html = document.documentElement; + var targets = [window, document, html, body, table, tbody, parent, target]; + var expected_targets = targets.concat([target, parent, tbody, table, body, html, document, window]); + var phases = [ + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.CAPTURING_PHASE, + Event.AT_TARGET, + Event.AT_TARGET, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + Event.BUBBLING_PHASE, + ]; + + var actual_targets = [], actual_phases = []; + var test_event = this.step_func(function(evt) { + if (parent === target.parentNode) { + parent.removeChild(target); + } + + actual_targets.push(evt.currentTarget); + actual_phases.push(evt.eventPhase); + }); + + for (var i = 0; i < targets.length; i++) { + targets[i].addEventListener(event_type, test_event, true); + targets[i].addEventListener(event_type, test_event, false); + } + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + target.dispatchEvent(evt); + + assert_array_equals(actual_targets, expected_targets, "targets"); + assert_array_equals(actual_phases, phases, "phases"); +}, "Event propagation path when an element in it is removed from the DOM"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-throwing.html b/testing/web-platform/tests/dom/events/Event-dispatch-throwing.html new file mode 100644 index 0000000000..7d1c0d94a0 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-dispatch-throwing.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>Throwing in event listeners</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +setup({allow_uncaught_exception:true}) + +test(function() { + var errorEvents = 0; + window.onerror = this.step_func(function(e) { + assert_equals(typeof e, 'string'); + ++errorEvents; + }); + + var element = document.createElement('div'); + + element.addEventListener('click', function() { + throw new Error('Error from only listener'); + }); + + element.dispatchEvent(new Event('click')); + + assert_equals(errorEvents, 1); +}, "Throwing in event listener with a single listeners"); + +test(function() { + var errorEvents = 0; + window.onerror = this.step_func(function(e) { + assert_equals(typeof e, 'string'); + ++errorEvents; + }); + + var element = document.createElement('div'); + + var secondCalled = false; + + element.addEventListener('click', function() { + throw new Error('Error from first listener'); + }); + element.addEventListener('click', this.step_func(function() { + secondCalled = true; + }), false); + + element.dispatchEvent(new Event('click')); + + assert_equals(errorEvents, 1); + assert_true(secondCalled); +}, "Throwing in event listener with multiple listeners"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-init-while-dispatching.html b/testing/web-platform/tests/dom/events/Event-init-while-dispatching.html new file mode 100644 index 0000000000..2aa1f6701c --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-init-while-dispatching.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Re-initializing events while dispatching them</title> +<link rel="author" title="Josh Matthews" href="mailto:josh@joshmatthews.net"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var events = { + 'KeyboardEvent': { + 'constructor': function() { return new KeyboardEvent("type", {key: "A"}); }, + 'init': function(ev) { ev.initKeyboardEvent("type2", true, true, null, "a", 1, "", true, "") }, + 'check': function(ev) { + assert_equals(ev.key, "A", "initKeyboardEvent key setter should short-circuit"); + assert_false(ev.repeat, "initKeyboardEvent repeat setter should short-circuit"); + assert_equals(ev.location, 0, "initKeyboardEvent location setter should short-circuit"); + } + }, + 'MouseEvent': { + 'constructor': function() { return new MouseEvent("type"); }, + 'init': function(ev) { ev.initMouseEvent("type2", true, true, null, 0, 1, 1, 1, 1, true, true, true, true, 1, null) }, + 'check': function(ev) { + assert_equals(ev.screenX, 0, "initMouseEvent screenX setter should short-circuit"); + assert_equals(ev.screenY, 0, "initMouseEvent screenY setter should short-circuit"); + assert_equals(ev.clientX, 0, "initMouseEvent clientX setter should short-circuit"); + assert_equals(ev.clientY, 0, "initMouseEvent clientY setter should short-circuit"); + assert_false(ev.ctrlKey, "initMouseEvent ctrlKey setter should short-circuit"); + assert_false(ev.altKey, "initMouseEvent altKey setter should short-circuit"); + assert_false(ev.shiftKey, "initMouseEvent shiftKey setter should short-circuit"); + assert_false(ev.metaKey, "initMouseEvent metaKey setter should short-circuit"); + assert_equals(ev.button, 0, "initMouseEvent button setter should short-circuit"); + } + }, + 'CustomEvent': { + 'constructor': function() { return new CustomEvent("type") }, + 'init': function(ev) { ev.initCustomEvent("type2", true, true, 1) }, + 'check': function(ev) { + assert_equals(ev.detail, null, "initCustomEvent detail setter should short-circuit"); + } + }, + 'UIEvent': { + 'constructor': function() { return new UIEvent("type") }, + 'init': function(ev) { ev.initUIEvent("type2", true, true, window, 1) }, + 'check': function(ev) { + assert_equals(ev.view, null, "initUIEvent view setter should short-circuit"); + assert_equals(ev.detail, 0, "initUIEvent detail setter should short-circuit"); + } + }, + 'Event': { + 'constructor': function() { return new Event("type") }, + 'init': function(ev) { ev.initEvent("type2", true, true) }, + 'check': function(ev) { + assert_equals(ev.bubbles, false, "initEvent bubbles setter should short-circuit"); + assert_equals(ev.cancelable, false, "initEvent cancelable setter should short-circuit"); + assert_equals(ev.type, "type", "initEvent type setter should short-circuit"); + } + } +}; + +var names = Object.keys(events); +for (var i = 0; i < names.length; i++) { + var t = async_test("Calling init" + names[i] + " while dispatching."); + t.step(function() { + var e = events[names[i]].constructor(); + + var target = document.createElement("div") + target.addEventListener("type", t.step_func(function() { + events[names[i]].init(e); + + var o = e; + while ((o = Object.getPrototypeOf(o))) { + if (!(o.constructor.name in events)) { + break; + } + events[o.constructor.name].check(e); + } + }), false); + + assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true") + }); + t.done(); +} +</script> diff --git a/testing/web-platform/tests/dom/events/Event-initEvent.html b/testing/web-platform/tests/dom/events/Event-initEvent.html new file mode 100644 index 0000000000..ad1018d4da --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-initEvent.html @@ -0,0 +1,136 @@ +<!DOCTYPE html> +<title>Event.initEvent</title> +<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var booleans = [true, false]; +booleans.forEach(function(bubbles) { + booleans.forEach(function(cancelable) { + test(function() { + var e = document.createEvent("Event") + e.initEvent("type", bubbles, cancelable) + + // Step 2. + // Stop (immediate) propagation flag is tested later + assert_equals(e.defaultPrevented, false, "defaultPrevented") + assert_equals(e.returnValue, true, "returnValue") + // Step 3. + assert_equals(e.isTrusted, false, "isTrusted") + // Step 4. + assert_equals(e.target, null, "target") + assert_equals(e.srcElement, null, "srcElement") + // Step 5. + assert_equals(e.type, "type", "type") + // Step 6. + assert_equals(e.bubbles, bubbles, "bubbles") + // Step 7. + assert_equals(e.cancelable, cancelable, "cancelable") + }, "Properties of initEvent(type, " + bubbles + ", " + cancelable + ")") + }) +}) + +test(function() { + var e = document.createEvent("Event") + e.initEvent("type 1", true, false) + assert_equals(e.type, "type 1", "type (first init)") + assert_equals(e.bubbles, true, "bubbles (first init)") + assert_equals(e.cancelable, false, "cancelable (first init)") + + e.initEvent("type 2", false, true) + assert_equals(e.type, "type 2", "type (second init)") + assert_equals(e.bubbles, false, "bubbles (second init)") + assert_equals(e.cancelable, true, "cancelable (second init)") +}, "Calling initEvent multiple times (getting type).") + +test(function() { + // https://bugzilla.mozilla.org/show_bug.cgi?id=998809 + var e = document.createEvent("Event") + e.initEvent("type 1", true, false) + assert_equals(e.bubbles, true, "bubbles (first init)") + assert_equals(e.cancelable, false, "cancelable (first init)") + + e.initEvent("type 2", false, true) + assert_equals(e.type, "type 2", "type (second init)") + assert_equals(e.bubbles, false, "bubbles (second init)") + assert_equals(e.cancelable, true, "cancelable (second init)") +}, "Calling initEvent multiple times (not getting type).") + +// Step 2. +async_test(function() { + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17715 + + var e = document.createEvent("Event") + e.initEvent("type", false, false) + assert_equals(e.type, "type", "type (first init)") + assert_equals(e.bubbles, false, "bubbles (first init)") + assert_equals(e.cancelable, false, "cancelable (first init)") + + var target = document.createElement("div") + target.addEventListener("type", this.step_func(function() { + e.initEvent("fail", true, true) + assert_equals(e.type, "type", "type (second init)") + assert_equals(e.bubbles, false, "bubbles (second init)") + assert_equals(e.cancelable, false, "cancelable (second init)") + }), false) + + assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true") + + this.done() +}, "Calling initEvent must not have an effect during dispatching.") + +test(function() { + var e = document.createEvent("Event") + e.stopPropagation() + e.initEvent("type", false, false) + var target = document.createElement("div") + var called = false + target.addEventListener("type", function() { called = true }, false) + assert_false(e.cancelBubble, "cancelBubble must be false") + assert_true(target.dispatchEvent(e), "dispatchEvent must return true") + assert_true(called, "Listener must be called") +}, "Calling initEvent must unset the stop propagation flag.") + +test(function() { + var e = document.createEvent("Event") + e.stopImmediatePropagation() + e.initEvent("type", false, false) + var target = document.createElement("div") + var called = false + target.addEventListener("type", function() { called = true }, false) + assert_true(target.dispatchEvent(e), "dispatchEvent must return true") + assert_true(called, "Listener must be called") +}, "Calling initEvent must unset the stop immediate propagation flag.") + +async_test(function() { + var e = document.createEvent("Event") + e.initEvent("type", false, false) + + var target = document.createElement("div") + target.addEventListener("type", this.step_func(function() { + e.initEvent("type2", true, true); + assert_equals(e.type, "type", "initEvent type setter should short-circuit"); + assert_false(e.bubbles, "initEvent bubbles setter should short-circuit"); + assert_false(e.cancelable, "initEvent cancelable setter should short-circuit"); + }), false) + assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true") + + this.done() +}, "Calling initEvent during propagation.") + +test(function() { + var e = document.createEvent("Event") + assert_throws_js(TypeError, function() { + e.initEvent() + }) +}, "First parameter to initEvent should be mandatory.") + +test(function() { + var e = document.createEvent("Event") + e.initEvent("type") + assert_equals(e.type, "type", "type") + assert_false(e.bubbles, "bubbles") + assert_false(e.cancelable, "cancelable") +}, "Tests initEvent's default parameter values.") +</script> diff --git a/testing/web-platform/tests/dom/events/Event-isTrusted.any.js b/testing/web-platform/tests/dom/events/Event-isTrusted.any.js new file mode 100644 index 0000000000..00bcecd0ed --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-isTrusted.any.js @@ -0,0 +1,11 @@ +test(function() { + var desc1 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); + assert_not_equals(desc1, undefined); + assert_equals(typeof desc1.get, "function"); + + var desc2 = Object.getOwnPropertyDescriptor(new Event("x"), "isTrusted"); + assert_not_equals(desc2, undefined); + assert_equals(typeof desc2.get, "function"); + + assert_equals(desc1.get, desc2.get); +}); diff --git a/testing/web-platform/tests/dom/events/Event-propagation.html b/testing/web-platform/tests/dom/events/Event-propagation.html new file mode 100644 index 0000000000..33989eb4bf --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-propagation.html @@ -0,0 +1,48 @@ +<!doctype html> +<title>Event propagation tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; + +function testPropagationFlag(ev, expected, desc) { + test(function() { + var called = false; + var callback = function() { called = true }; + this.add_cleanup(function() { + document.head.removeEventListener("foo", callback) + }); + document.head.addEventListener("foo", callback); + document.head.dispatchEvent(ev); + assert_equals(called, expected, "Propagation flag"); + // dispatchEvent resets the propagation flags so it will happily dispatch + // the event the second time around. + document.head.dispatchEvent(ev); + assert_equals(called, true, "Propagation flag after first dispatch"); + }, desc); +} + +var ev = document.createEvent("Event"); +ev.initEvent("foo", true, false); +testPropagationFlag(ev, true, "Newly-created Event"); +ev.stopPropagation(); +testPropagationFlag(ev, false, "After stopPropagation()"); +ev.initEvent("foo", true, false); +testPropagationFlag(ev, true, "Reinitialized after stopPropagation()"); + +var ev = document.createEvent("Event"); +ev.initEvent("foo", true, false); +ev.stopImmediatePropagation(); +testPropagationFlag(ev, false, "After stopImmediatePropagation()"); +ev.initEvent("foo", true, false); +testPropagationFlag(ev, true, "Reinitialized after stopImmediatePropagation()"); + +var ev = document.createEvent("Event"); +ev.initEvent("foo", true, false); +ev.cancelBubble = true; +testPropagationFlag(ev, false, "After cancelBubble=true"); +ev.initEvent("foo", true, false); +testPropagationFlag(ev, true, "Reinitialized after cancelBubble=true"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-returnValue.html b/testing/web-platform/tests/dom/events/Event-returnValue.html new file mode 100644 index 0000000000..08df2d4141 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-returnValue.html @@ -0,0 +1,64 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <title>Event.returnValue</title> + <link rel="author" title="Chris Rebert" href="http://chrisrebert.com"> + <link rel="help" href="https://dom.spec.whatwg.org/#dom-event-returnvalue"> + <meta name="flags" content="dom"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> + <div id="log"></div> + <script> +test(function() { + var ev = new Event("foo"); + assert_true(ev.returnValue, "returnValue"); +}, "When an event is created, returnValue should be initialized to true."); +test(function() { + var ev = new Event("foo", {"cancelable": false}); + assert_false(ev.cancelable, "cancelable (before)"); + ev.preventDefault(); + assert_false(ev.cancelable, "cancelable (after)"); + assert_true(ev.returnValue, "returnValue"); +}, "preventDefault() should not change returnValue if cancelable is false."); +test(function() { + var ev = new Event("foo", {"cancelable": false}); + assert_false(ev.cancelable, "cancelable (before)"); + ev.returnValue = false; + assert_false(ev.cancelable, "cancelable (after)"); + assert_true(ev.returnValue, "returnValue"); +}, "returnValue=false should have no effect if cancelable is false."); +test(function() { + var ev = new Event("foo", {"cancelable": true}); + assert_true(ev.cancelable, "cancelable (before)"); + ev.preventDefault(); + assert_true(ev.cancelable, "cancelable (after)"); + assert_false(ev.returnValue, "returnValue"); +}, "preventDefault() should change returnValue if cancelable is true."); +test(function() { + var ev = new Event("foo", {"cancelable": true}); + assert_true(ev.cancelable, "cancelable (before)"); + ev.returnValue = false; + assert_true(ev.cancelable, "cancelable (after)"); + assert_false(ev.returnValue, "returnValue"); +}, "returnValue should change returnValue if cancelable is true."); +test(function() { + var ev = document.createEvent("Event"); + ev.returnValue = false; + ev.initEvent("foo", true, true); + assert_true(ev.bubbles, "bubbles"); + assert_true(ev.cancelable, "cancelable"); + assert_true(ev.returnValue, "returnValue"); +}, "initEvent should unset returnValue."); +test(function() { + var ev = new Event("foo", {"cancelable": true}); + ev.preventDefault(); + ev.returnValue = true;// no-op + assert_true(ev.defaultPrevented); + assert_false(ev.returnValue); +}, "returnValue=true should have no effect once the canceled flag was set."); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/Event-stopImmediatePropagation.html b/testing/web-platform/tests/dom/events/Event-stopImmediatePropagation.html new file mode 100644 index 0000000000..b75732257a --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-stopImmediatePropagation.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event's stopImmediatePropagation</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation"> +<link rel="author" href="mailto:d@domenic.me" title="Domenic Denicola"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="target"></div> + +<script> +"use strict"; + +setup({ single_test: true }); + +const target = document.querySelector("#target"); + +let timesCalled = 0; +target.addEventListener("test", e => { + ++timesCalled; + e.stopImmediatePropagation(); + assert_equals(e.cancelBubble, true, "The stop propagation flag must have been set"); +}); +target.addEventListener("test", () => { + ++timesCalled; +}); + +const e = new Event("test"); +target.dispatchEvent(e); +assert_equals(timesCalled, 1, "The second listener must not have been called"); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-stopPropagation-cancel-bubbling.html b/testing/web-platform/tests/dom/events/Event-stopPropagation-cancel-bubbling.html new file mode 100644 index 0000000000..5c2c49f338 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-stopPropagation-cancel-bubbling.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +test(t => { + const element = document.createElement('div'); + + element.addEventListener('click', () => { + event.stopPropagation(); + }, { capture: true }); + + element.addEventListener('click', + t.unreached_func('stopPropagation in the capture handler should have canceled this bubble handler.')); + + element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-subclasses-constructors.html b/testing/web-platform/tests/dom/events/Event-subclasses-constructors.html new file mode 100644 index 0000000000..08a5ded011 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-subclasses-constructors.html @@ -0,0 +1,179 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event constructors</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function assert_props(iface, event, defaults) { + assert_true(event instanceof self[iface]); + expected[iface].properties.forEach(function(p) { + var property = p[0], value = p[defaults ? 1 : 2]; + assert_true(property in event, + "Event " + format_value(event) + " should have a " + + property + " property"); + assert_equals(event[property], value, + "The value of the " + property + " property should be " + + format_value(value)); + }); + if ("parent" in expected[iface]) { + assert_props(expected[iface].parent, event, defaults); + } +} + +// Class declarations don't go on the global by default, so put it there ourselves: + +self.SubclassedEvent = class SubclassedEvent extends Event { + constructor(name, props) { + super(name, props); + if (props && typeof(props) == "object" && "customProp" in props) { + this.customProp = props.customProp; + } else { + this.customProp = 5; + } + } + + get fixedProp() { + return 17; + } +} + +var EventModifierInit = [ + ["ctrlKey", false, true], + ["shiftKey", false, true], + ["altKey", false, true], + ["metaKey", false, true], +]; +var expected = { + "Event": { + "properties": [ + ["bubbles", false, true], + ["cancelable", false, true], + ["isTrusted", false, false], + ], + }, + + "UIEvent": { + "parent": "Event", + "properties": [ + ["view", null, window], + ["detail", 0, 7], + ], + }, + + "FocusEvent": { + "parent": "UIEvent", + "properties": [ + ["relatedTarget", null, document], + ], + }, + + "MouseEvent": { + "parent": "UIEvent", + "properties": EventModifierInit.concat([ + ["screenX", 0, 40], + ["screenY", 0, 40], + ["clientX", 0, 40], + ["clientY", 0, 40], + ["button", 0, 40], + ["buttons", 0, 40], + ["relatedTarget", null, document], + ]), + }, + + "WheelEvent": { + "parent": "MouseEvent", + "properties": [ + ["deltaX", 0.0, 3.1], + ["deltaY", 0.0, 3.1], + ["deltaZ", 0.0, 3.1], + ["deltaMode", 0, 40], + ], + }, + + "KeyboardEvent": { + "parent": "UIEvent", + "properties": EventModifierInit.concat([ + ["key", "", "string"], + ["code", "", "string"], + ["location", 0, 7], + ["repeat", false, true], + ["isComposing", false, true], + ["charCode", 0, 7], + ["keyCode", 0, 7], + ["which", 0, 7], + ]), + }, + + "CompositionEvent": { + "parent": "UIEvent", + "properties": [ + ["data", "", "string"], + ], + }, + + "SubclassedEvent": { + "parent": "Event", + "properties": [ + ["customProp", 5, 8], + ["fixedProp", 17, 17], + ], + }, +}; + +Object.keys(expected).forEach(function(iface) { + test(function() { + var event = new self[iface]("type"); + assert_props(iface, event, true); + }, iface + " constructor (no argument)"); + + test(function() { + var event = new self[iface]("type", undefined); + assert_props(iface, event, true); + }, iface + " constructor (undefined argument)"); + + test(function() { + var event = new self[iface]("type", null); + assert_props(iface, event, true); + }, iface + " constructor (null argument)"); + + test(function() { + var event = new self[iface]("type", {}); + assert_props(iface, event, true); + }, iface + " constructor (empty argument)"); + + test(function() { + var dictionary = {}; + expected[iface].properties.forEach(function(p) { + var property = p[0], value = p[1]; + dictionary[property] = value; + }); + var event = new self[iface]("type", dictionary); + assert_props(iface, event, true); + }, iface + " constructor (argument with default values)"); + + test(function() { + function fill_in(iface, dictionary) { + if ("parent" in expected[iface]) { + fill_in(expected[iface].parent, dictionary) + } + expected[iface].properties.forEach(function(p) { + var property = p[0], value = p[2]; + dictionary[property] = value; + }); + } + + var dictionary = {}; + fill_in(iface, dictionary); + + var event = new self[iface]("type", dictionary); + assert_props(iface, event, false); + }, iface + " constructor (argument with non-default values)"); +}); + +test(function () { + assert_throws_js(TypeError, function() { + new UIEvent("x", { view: 7 }) + }); +}, "UIEvent constructor (view argument with wrong type)") +</script> diff --git a/testing/web-platform/tests/dom/events/Event-timestamp-cross-realm-getter.html b/testing/web-platform/tests/dom/events/Event-timestamp-cross-realm-getter.html new file mode 100644 index 0000000000..45823de26b --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-timestamp-cross-realm-getter.html @@ -0,0 +1,27 @@ +<!doctype html> +<meta charset="utf-8"> +<title>event.timeStamp is initialized using event's relevant global object</title> +<link rel="help" href="https://dom.spec.whatwg.org/#ref-for-dom-event-timestamp%E2%91%A1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +const t = async_test(); +t.step_timeout(() => { + const iframeDelayed = document.createElement("iframe"); + iframeDelayed.onload = t.step_func_done(() => { + // Use eval() to eliminate false-positive test result for WebKit builds before r280256, + // which invoked WebIDL accessors in context of lexical (caller) global object. + const timeStampExpected = iframeDelayed.contentWindow.eval(`new Event("foo").timeStamp`); + const eventDelayed = new iframeDelayed.contentWindow.Event("foo"); + + const {get} = Object.getOwnPropertyDescriptor(Event.prototype, "timeStamp"); + assert_approx_equals(get.call(eventDelayed), timeStampExpected, 5, "via Object.getOwnPropertyDescriptor"); + + Object.setPrototypeOf(eventDelayed, Event.prototype); + assert_approx_equals(eventDelayed.timeStamp, timeStampExpected, 5, "via Object.setPrototypeOf"); + }); + document.body.append(iframeDelayed); +}, 1000); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.html b/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.html new file mode 100644 index 0000000000..a049fef64b --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="text/javascript"> +'use strict'; +for (let eventType of ["MouseEvent", "KeyboardEvent", "WheelEvent", "FocusEvent"]) { + test(function() { + let before = performance.now(); + let e = new window[eventType]('test'); + let after = performance.now(); + assert_greater_than_equal(e.timeStamp, before, "Event timestamp should be greater than performance.now() timestamp taken before its creation"); + assert_less_than_equal(e.timeStamp, after, "Event timestamp should be less than performance.now() timestamp taken after its creation"); + }, `Constructed ${eventType} timestamp should be high resolution and have the same time origin as performance.now()`); +} +</script> diff --git a/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.https.html b/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.https.html new file mode 100644 index 0000000000..70f9742947 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-timestamp-high-resolution.https.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="text/javascript"> +'use strict'; +for (let eventType of ["GamepadEvent"]) { + test(function() { + let before = performance.now(); + let e = new window[eventType]('test'); + let after = performance.now(); + assert_greater_than_equal(e.timeStamp, before, "Event timestamp should be greater than performance.now() timestamp taken before its creation"); + assert_less_than_equal(e.timeStamp, after, "Event timestamp should be less than performance.now() timestamp taken after its creation"); + }, `Constructed ${eventType} timestamp should be high resolution and have the same time origin as performance.now()`); +} +</script> diff --git a/testing/web-platform/tests/dom/events/Event-timestamp-safe-resolution.html b/testing/web-platform/tests/dom/events/Event-timestamp-safe-resolution.html new file mode 100644 index 0000000000..24f2dec93c --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-timestamp-safe-resolution.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="text/javascript"> +'use strict'; + +// Computes greatest common divisor of a and b using Euclid's algorithm +function computeGCD(a, b) { + if (!Number.isInteger(a) || !Number.isInteger(b)) { + throw new Error('Parameters must be integer numbers'); + } + + var r; + while (b != 0) { + r = a % b; + a = b; + b = r; + } + return (a < 0) ? -a : a; +} + +// Finds minimum resolution Δ given a set of samples which are known to be in the form of N*Δ. +// We use GCD of all samples as a simple estimator. +function estimateMinimumResolution(samples) { + var gcd; + for (const sample of samples) { + gcd = gcd ? computeGCD(gcd, sample) : sample; + } + + return gcd; +} + +test(function() { + const samples = []; + for (var i = 0; i < 1e3; i++) { + var deltaInMicroSeconds = 0; + const e1 = new MouseEvent('test1'); + do { + const e2 = new MouseEvent('test2'); + deltaInMicroSeconds = Math.round((e2.timeStamp - e1.timeStamp) * 1000); + } while (deltaInMicroSeconds == 0) // only collect non-zero samples + + samples.push(deltaInMicroSeconds); + } + + const minResolution = estimateMinimumResolution(samples); + assert_greater_than_equal(minResolution, 5); +}, 'Event timestamp should not have a resolution better than 5 microseconds'); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/events/Event-type-empty.html b/testing/web-platform/tests/dom/events/Event-type-empty.html new file mode 100644 index 0000000000..225b85a613 --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-type-empty.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>Event.type set to the empty string</title> +<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function do_test(t, e) { + assert_equals(e.type, "", "type"); + assert_equals(e.bubbles, false, "bubbles"); + assert_equals(e.cancelable, false, "cancelable"); + + var target = document.createElement("div"); + var handled = false; + target.addEventListener("", t.step_func(function(e) { + handled = true; + })); + assert_true(target.dispatchEvent(e)); + assert_true(handled); +} + +async_test(function() { + var e = document.createEvent("Event"); + e.initEvent("", false, false); + do_test(this, e); + this.done(); +}, "initEvent"); + +async_test(function() { + var e = new Event(""); + do_test(this, e); + this.done(); +}, "Constructor"); +</script> diff --git a/testing/web-platform/tests/dom/events/Event-type.html b/testing/web-platform/tests/dom/events/Event-type.html new file mode 100644 index 0000000000..22792f5c6c --- /dev/null +++ b/testing/web-platform/tests/dom/events/Event-type.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<title>Event.type</title> +<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-type"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var e = document.createEvent("Event") + assert_equals(e.type, ""); +}, "Event.type should initially be the empty string"); +test(function() { + var e = document.createEvent("Event") + e.initEvent("foo", false, false) + assert_equals(e.type, "foo") +}, "Event.type should be initialized by initEvent"); +test(function() { + var e = new Event("bar") + assert_equals(e.type, "bar") +}, "Event.type should be initialized by the constructor"); +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-addEventListener.sub.window.js b/testing/web-platform/tests/dom/events/EventListener-addEventListener.sub.window.js new file mode 100644 index 0000000000..b44bc33285 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-addEventListener.sub.window.js @@ -0,0 +1,9 @@ +async_test(function(t) { + let crossOriginFrame = document.createElement('iframe'); + crossOriginFrame.src = 'https://{{hosts[alt][]}}:{{ports[https][0]}}/common/blank.html'; + document.body.appendChild(crossOriginFrame); + crossOriginFrame.addEventListener('load', t.step_func_done(function() { + let crossOriginWindow = crossOriginFrame.contentWindow; + window.addEventListener('click', crossOriginWindow); + })); +}, "EventListener.addEventListener doesn't throw when a cross origin object is passed in."); diff --git a/testing/web-platform/tests/dom/events/EventListener-handleEvent-cross-realm.html b/testing/web-platform/tests/dom/events/EventListener-handleEvent-cross-realm.html new file mode 100644 index 0000000000..663d04213f --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-handleEvent-cross-realm.html @@ -0,0 +1,75 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cross-realm EventListener throws TypeError of its associated Realm</title> +<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe name="eventListenerGlobalObject" src="resources/empty-document.html"></iframe> + +<script> +setup({ allow_uncaught_exception: true }); + +test_onload(() => { + const eventTarget = new EventTarget; + const eventListener = new eventListenerGlobalObject.Object; + + eventTarget.addEventListener("foo", eventListener); + assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); }); +}, "EventListener is cross-realm plain object without 'handleEvent' property"); + +test_onload(() => { + const eventTarget = new EventTarget; + const eventListener = new eventListenerGlobalObject.Object; + eventListener.handleEvent = {}; + + eventTarget.addEventListener("foo", eventListener); + assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); }); +}, "EventListener is cross-realm plain object with non-callable 'handleEvent' property"); + +test_onload(() => { + const eventTarget = new EventTarget; + const { proxy, revoke } = Proxy.revocable(() => {}, {}); + revoke(); + + const eventListener = new eventListenerGlobalObject.Object; + eventListener.handleEvent = proxy; + + eventTarget.addEventListener("foo", eventListener); + assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); }); +}, "EventListener is cross-realm plain object with revoked Proxy as 'handleEvent' property"); + +test_onload(() => { + const eventTarget = new EventTarget; + const { proxy, revoke } = eventListenerGlobalObject.Proxy.revocable({}, {}); + revoke(); + + eventTarget.addEventListener("foo", proxy); + assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); }); +}, "EventListener is cross-realm non-callable revoked Proxy"); + +test_onload(() => { + const eventTarget = new EventTarget; + const { proxy, revoke } = eventListenerGlobalObject.Proxy.revocable(() => {}, {}); + revoke(); + + eventTarget.addEventListener("foo", proxy); + assert_reports_exception(eventListenerGlobalObject.TypeError, () => { eventTarget.dispatchEvent(new Event("foo")); }); +}, "EventListener is cross-realm callable revoked Proxy"); + +function test_onload(fn, desc) { + async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc); +} + +function assert_reports_exception(expectedConstructor, fn) { + let error; + const onErrorHandler = event => { error = event.error; }; + + eventListenerGlobalObject.addEventListener("error", onErrorHandler); + fn(); + eventListenerGlobalObject.removeEventListener("error", onErrorHandler); + + assert_equals(typeof error, "object"); + assert_equals(error.constructor, expectedConstructor); +} +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-handleEvent.html b/testing/web-platform/tests/dom/events/EventListener-handleEvent.html new file mode 100644 index 0000000000..06bc1f6e2a --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-handleEvent.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>EventListener::handleEvent()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-eventlistener"> +<div id=log></div> +<script> +setup({ allow_uncaught_exception: true }); + +test(function(t) { + var type = "foo"; + var target = document.createElement("div"); + var eventListener = { + handleEvent: function(evt) { + var that = this; + t.step(function() { + assert_equals(evt.type, type); + assert_equals(evt.target, target); + assert_equals(evt.srcElement, target); + assert_equals(that, eventListener); + }); + }, + }; + + target.addEventListener(type, eventListener); + target.dispatchEvent(new Event(type)); +}, "calls `handleEvent` method of `EventListener`"); + +test(function(t) { + var type = "foo"; + var target = document.createElement("div"); + var calls = 0; + + target.addEventListener(type, { + get handleEvent() { + calls++; + return function() {}; + }, + }); + + assert_equals(calls, 0); + target.dispatchEvent(new Event(type)); + target.dispatchEvent(new Event(type)); + assert_equals(calls, 2); +}, "performs `Get` every time event is dispatched"); + +test(function(t) { + var type = "foo"; + var target = document.createElement("div"); + var calls = 0; + var eventListener = function() { calls++; }; + eventListener.handleEvent = t.unreached_func("`handleEvent` method should not be called on functions"); + + target.addEventListener(type, eventListener); + target.dispatchEvent(new Event(type)); + assert_equals(calls, 1); +}, "doesn't call `handleEvent` method on callable `EventListener`"); + +const uncaught_error_test = async (t, getHandleEvent) => { + const type = "foo"; + const target = document.createElement("div"); + + let calls = 0; + target.addEventListener(type, { + get handleEvent() { + calls++; + return getHandleEvent(); + }, + }); + + const timeout = () => { + return new Promise(resolve => { + t.step_timeout(resolve, 0); + }); + }; + + const eventWatcher = new EventWatcher(t, window, "error", timeout); + const errorPromise = eventWatcher.wait_for("error"); + + target.dispatchEvent(new Event(type)); + + const event = await errorPromise; + assert_equals(calls, 1, "handleEvent property was not looked up"); + throw event.error; +}; + +promise_test(t => { + const error = { name: "test" }; + + return promise_rejects_exactly(t, error, + uncaught_error_test(t, () => { throw error; })); +}, "rethrows errors when getting `handleEvent`"); + +promise_test(t => { + return promise_rejects_js(t, TypeError, uncaught_error_test(t, () => null)); +}, "throws if `handleEvent` is falsy and not callable"); + +promise_test(t => { + return promise_rejects_js(t, TypeError, uncaught_error_test(t, () => 42)); +}, "throws if `handleEvent` is thruthy and not callable"); +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-incumbent-global-1.sub.html b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-1.sub.html new file mode 100644 index 0000000000..9d941385cb --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-1.sub.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe src="{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subframe-1.sub.html"></iframe> +<script> + +var t = async_test("Check the incumbent global EventListeners are called with"); + +onload = t.step_func(function() { + onmessage = t.step_func_done(function(e) { + var d = e.data; + assert_equals(d.actual, d.expected, d.reason); + }); + + frames[0].postMessage("start", "*"); +}); + +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-incumbent-global-2.sub.html b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-2.sub.html new file mode 100644 index 0000000000..4433c098d7 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-2.sub.html @@ -0,0 +1,20 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe src="{{location[scheme]}}://{{domains[www1]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subframe-2.sub.html"></iframe> +<script> + +var t = async_test("Check the incumbent global EventListeners are called with"); + +onload = t.step_func(function() { + onmessage = t.step_func_done(function(e) { + var d = e.data; + assert_equals(d.actual, d.expected, d.reason); + }); + + frames[0].postMessage("start", "*"); +}); + +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-1.sub.html b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-1.sub.html new file mode 100644 index 0000000000..25487cc5e0 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-1.sub.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<iframe src="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subsubframe.sub.html"></iframe> +<script> + document.domain = "{{host}}"; + onmessage = function(e) { + if (e.data == "start") { + frames[0].document.body.addEventListener("click", frames[0].postMessage.bind(frames[0], "respond", "*", undefined)); + frames[0].postMessage("sendclick", "*"); + } else { + parent.postMessage(e.data, "*"); + } + } +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-2.sub.html b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-2.sub.html new file mode 100644 index 0000000000..9c7235e2ad --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subframe-2.sub.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<iframe src="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}{{location[path]}}/../EventListener-incumbent-global-subsubframe.sub.html"></iframe> +<script> + document.domain = "{{host}}"; + onmessage = function(e) { + if (e.data == "start") { + frames[0].document.body.addEventListener("click", frames[0].getTheListener()); + frames[0].postMessage("sendclick", "*"); + } else { + parent.postMessage(e.data, "*"); + } + } +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subsubframe.sub.html b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subsubframe.sub.html new file mode 100644 index 0000000000..dd683f6f65 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-incumbent-global-subsubframe.sub.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<script> + function getTheListener() { + return postMessage.bind(this, "respond", "*", undefined) + } + document.domain = "{{host}}"; + onmessage = function (e) { + if (e.data == "sendclick") { + document.body.click(); + } else { + parent.postMessage( + { + actual: e.origin, + expected: parent.location.origin, + reason: "Incumbent should have been the caller of addEventListener()" + }, + "*") + }; + } +</script> diff --git a/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html b/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html new file mode 100644 index 0000000000..a01afcd8d1 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListener-invoke-legacy.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Invoke legacy event listener</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> + @keyframes test { + 0% { color: red; } + 100% { color: green; } + } +</style> +<div id="log"></div> +<script> +function runLegacyEventTest(type, legacyType, ctor, setup) { + function createTestElem(t) { + var elem = document.createElement('div'); + document.body.appendChild(elem); + t.add_cleanup(function() { + document.body.removeChild(elem); + }); + return elem; + } + + async_test(function(t) { + var elem = createTestElem(t); + var gotEvent = false; + elem.addEventListener(legacyType, + t.unreached_func("listener of " + legacyType + " should not be invoked")); + elem.addEventListener(type, t.step_func(function() { + assert_false(gotEvent, "unexpected " + type + " event"); + gotEvent = true; + t.step_timeout(function() { t.done(); }, 100); + })); + setup(elem); + }, "Listener of " + type); + + async_test(function(t) { + var elem = createTestElem(t); + var count = 0; + elem.addEventListener(legacyType, t.step_func(function() { + ++count; + if (count > 1) { + assert_unreached("listener of " + legacyType + " should not be invoked again"); + return; + } + elem.dispatchEvent(new window[ctor](type)); + t.done(); + })); + setup(elem); + }, "Legacy listener of " + type); +} + +function setupTransition(elem) { + getComputedStyle(elem).color; + elem.style.color = 'green'; + elem.style.transition = 'color 30ms'; +} + +function setupAnimation(elem) { + elem.style.animation = 'test 30ms'; +} + +runLegacyEventTest('transitionend', 'webkitTransitionEnd', "TransitionEvent", setupTransition); +runLegacyEventTest('animationend', 'webkitAnimationEnd', "AnimationEvent", setupAnimation); +runLegacyEventTest('animationstart', 'webkitAnimationStart', "AnimationEvent", setupAnimation); +</script> diff --git a/testing/web-platform/tests/dom/events/EventListenerOptions-capture.html b/testing/web-platform/tests/dom/events/EventListenerOptions-capture.html new file mode 100644 index 0000000000..f72cf3ca54 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventListenerOptions-capture.html @@ -0,0 +1,98 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>EventListenerOptions.capture</title> +<link rel="author" title="Rick Byers" href="mailto:rbyers@chromium.org"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventlisteneroptions-capture"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> + +<script> + +function testCaptureValue(captureValue, expectedValue) { + var handlerPhase = undefined; + var handler = function handler(e) { + assert_equals(handlerPhase, undefined, "Handler invoked after remove"); + handlerPhase = e.eventPhase; + } + document.addEventListener('test', handler, captureValue); + document.body.dispatchEvent(new Event('test', {bubbles: true})); + document.removeEventListener('test', handler, captureValue); + document.body.dispatchEvent(new Event('test', {bubbles: true})); + assert_equals(handlerPhase, expectedValue, "Incorrect event phase for value: " + JSON.stringify(captureValue)); +} + +test(function() { + testCaptureValue(true, Event.CAPTURING_PHASE); + testCaptureValue(false, Event.BUBBLING_PHASE); + testCaptureValue(null, Event.BUBBLING_PHASE); + testCaptureValue(undefined, Event.BUBBLING_PHASE); + testCaptureValue(2.3, Event.CAPTURING_PHASE); + testCaptureValue(-1000.3, Event.CAPTURING_PHASE); + testCaptureValue(NaN, Event.BUBBLING_PHASE); + testCaptureValue(+0.0, Event.BUBBLING_PHASE); + testCaptureValue(-0.0, Event.BUBBLING_PHASE); + testCaptureValue("", Event.BUBBLING_PHASE); + testCaptureValue("AAAA", Event.CAPTURING_PHASE); +}, "Capture boolean should be honored correctly"); + +test(function() { + testCaptureValue({}, Event.BUBBLING_PHASE); + testCaptureValue({capture:true}, Event.CAPTURING_PHASE); + testCaptureValue({capture:false}, Event.BUBBLING_PHASE); + testCaptureValue({capture:2}, Event.CAPTURING_PHASE); + testCaptureValue({capture:0}, Event.BUBBLING_PHASE); +}, "Capture option should be honored correctly"); + +test(function() { + var supportsCapture = false; + var query_options = { + get capture() { + supportsCapture = true; + return false; + }, + get dummy() { + assert_unreached("dummy value getter invoked"); + return false; + } + }; + + document.addEventListener('test_event', null, query_options); + assert_true(supportsCapture, "addEventListener doesn't support the capture option"); + supportsCapture = false; + document.removeEventListener('test_event', null, query_options); + assert_true(supportsCapture, "removeEventListener doesn't support the capture option"); +}, "Supports capture option"); + +function testOptionEquality(addOptionValue, removeOptionValue, expectedEquality) { + var handlerInvoked = false; + var handler = function handler(e) { + assert_equals(handlerInvoked, false, "Handler invoked multiple times"); + handlerInvoked = true; + } + document.addEventListener('test', handler, addOptionValue); + document.removeEventListener('test', handler, removeOptionValue); + document.body.dispatchEvent(new Event('test', {bubbles: true})); + assert_equals(!handlerInvoked, expectedEquality, "equivalence of options " + + JSON.stringify(addOptionValue) + " and " + JSON.stringify(removeOptionValue)); + if (handlerInvoked) + document.removeEventListener('test', handler, addOptionValue); +} + +test(function() { + // Option values that should be treated as equivalent + testOptionEquality({}, false, true); + testOptionEquality({capture: false}, false, true); + testOptionEquality(true, {capture: true}, true); + testOptionEquality({capture: null}, undefined, true); + testOptionEquality({capture: true}, {dummy: false, capture: 1}, true); + testOptionEquality({dummy: true}, false, true); + + // Option values that should be treated as distinct + testOptionEquality(true, false, false); + testOptionEquality(true, {capture:false}, false); + testOptionEquality({}, true, false); + +}, "Equivalence of option values"); + +</script> diff --git a/testing/web-platform/tests/dom/events/EventTarget-add-listener-platform-object.html b/testing/web-platform/tests/dom/events/EventTarget-add-listener-platform-object.html new file mode 100644 index 0000000000..d5565c22b3 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-add-listener-platform-object.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>addEventListener with a platform object</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +</script> +<my-custom-click id=click>Click me!</my-custom-click> +<script> +"use strict"; +setup({ single_test: true }); + +class MyCustomClick extends HTMLElement { + connectedCallback() { + this.addEventListener("click", this); + } + + handleEvent(event) { + if (event.target === this) { + this.dataset.yay = "It worked!"; + } + } +} +window.customElements.define("my-custom-click", MyCustomClick); + +const customElement = document.getElementById("click"); +customElement.click(); + +assert_equals(customElement.dataset.yay, "It worked!"); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/events/EventTarget-add-remove-listener.any.js b/testing/web-platform/tests/dom/events/EventTarget-add-remove-listener.any.js new file mode 100644 index 0000000000..b1d7ffb3e0 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-add-remove-listener.any.js @@ -0,0 +1,21 @@ +// META: title=EventTarget's addEventListener + removeEventListener + +"use strict"; + +function listener(evt) { + evt.preventDefault(); + return false; +} + +test(() => { + const et = new EventTarget(); + et.addEventListener("x", listener, false); + let event = new Event("x", { cancelable: true }); + let ret = et.dispatchEvent(event); + assert_false(ret); + + et.removeEventListener("x", listener); + event = new Event("x", { cancelable: true }); + ret = et.dispatchEvent(event); + assert_true(ret); +}, "Removing an event listener without explicit capture arg should succeed"); diff --git a/testing/web-platform/tests/dom/events/EventTarget-addEventListener.any.js b/testing/web-platform/tests/dom/events/EventTarget-addEventListener.any.js new file mode 100644 index 0000000000..e22da4aff8 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-addEventListener.any.js @@ -0,0 +1,9 @@ +// META: title=EventTarget.addEventListener + +// Step 1. +test(function() { + const et = new EventTarget(); + assert_equals(et.addEventListener("x", null, false), undefined); + assert_equals(et.addEventListener("x", null, true), undefined); + assert_equals(et.addEventListener("x", null), undefined); +}, "Adding a null event listener should succeed"); diff --git a/testing/web-platform/tests/dom/events/EventTarget-constructible.any.js b/testing/web-platform/tests/dom/events/EventTarget-constructible.any.js new file mode 100644 index 0000000000..b0e7614e62 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-constructible.any.js @@ -0,0 +1,62 @@ +"use strict"; + +test(() => { + const target = new EventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + let callCount = 0; + + function listener(e) { + assert_equals(e, event); + ++callCount; + } + + target.addEventListener("foo", listener); + + target.dispatchEvent(event); + assert_equals(callCount, 1); + + target.dispatchEvent(event); + assert_equals(callCount, 2); + + target.removeEventListener("foo", listener); + target.dispatchEvent(event); + assert_equals(callCount, 2); +}, "A constructed EventTarget can be used as expected"); + +test(() => { + class NicerEventTarget extends EventTarget { + on(...args) { + this.addEventListener(...args); + } + + off(...args) { + this.removeEventListener(...args); + } + + dispatch(type, detail) { + this.dispatchEvent(new CustomEvent(type, { detail })); + } + } + + const target = new NicerEventTarget(); + const event = new Event("foo", { bubbles: true, cancelable: false }); + const detail = "some data"; + let callCount = 0; + + function listener(e) { + assert_equals(e.detail, detail); + ++callCount; + } + + target.on("foo", listener); + + target.dispatch("foo", detail); + assert_equals(callCount, 1); + + target.dispatch("foo", detail); + assert_equals(callCount, 2); + + target.off("foo", listener); + target.dispatch("foo", detail); + assert_equals(callCount, 2); +}, "EventTarget can be subclassed"); diff --git a/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent-returnvalue.html b/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent-returnvalue.html new file mode 100644 index 0000000000..c4466e0d6c --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent-returnvalue.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>EventTarget.dispatchEvent: return value</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-dispatch"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-preventdefault"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-returnvalue"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-defaultprevented"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<table id="table" border="1" style="display: none"> + <tbody id="table-body"> + <tr id="table-row"> + <td id="table-cell">Shady Grove</td> + <td>Aeolian</td> + </tr> + <tr id="parent"> + <td id="target">Over the river, Charlie</td> + <td>Dorian</td> + </tr> + </tbody> +</table> +<script> +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var default_prevented; + var return_value; + + parent.addEventListener(event_type, function(e) {}, true); + target.addEventListener(event_type, function(e) { + evt.preventDefault(); + default_prevented = evt.defaultPrevented; + return_value = evt.returnValue; + }, true); + target.addEventListener(event_type, function(e) {}, true); + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + assert_true(parent.dispatchEvent(evt)); + assert_false(target.dispatchEvent(evt)); + assert_true(default_prevented); + assert_false(return_value); +}, "Return value of EventTarget.dispatchEvent() affected by preventDefault()."); + +test(function() { + var event_type = "foo"; + var target = document.getElementById("target"); + var parent = document.getElementById("parent"); + var default_prevented; + var return_value; + + parent.addEventListener(event_type, function(e) {}, true); + target.addEventListener(event_type, function(e) { + evt.returnValue = false; + default_prevented = evt.defaultPrevented; + return_value = evt.returnValue; + }, true); + target.addEventListener(event_type, function(e) {}, true); + + var evt = document.createEvent("Event"); + evt.initEvent(event_type, true, true); + + assert_true(parent.dispatchEvent(evt)); + assert_false(target.dispatchEvent(evt)); + assert_true(default_prevented); + assert_false(return_value); +}, "Return value of EventTarget.dispatchEvent() affected by returnValue."); +</script> diff --git a/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent.html b/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent.html new file mode 100644 index 0000000000..783561f5fb --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-dispatchEvent.html @@ -0,0 +1,104 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>EventTarget.dispatchEvent</title> +<link rel="author" title="Olli Pettay" href="mailto:Olli.Pettay@gmail.com"> +<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/dom/nodes/Document-createEvent.js"></script> +<div id="log"></div> +<script> +setup({ + "allow_uncaught_exception": true, +}) + +test(function() { + assert_throws_js(TypeError, function() { document.dispatchEvent(null) }) +}, "Calling dispatchEvent(null).") + +for (var alias in aliases) { + test(function() { + var e = document.createEvent(alias) + assert_equals(e.type, "", "Event type should be empty string before initialization") + assert_throws_dom("InvalidStateError", function() { document.dispatchEvent(e) }) + }, "If the event's initialized flag is not set, an InvalidStateError must be thrown (" + alias + ").") +} + +var dispatch_dispatch = async_test("If the event's dispatch flag is set, an InvalidStateError must be thrown.") +dispatch_dispatch.step(function() { + var e = document.createEvent("Event") + e.initEvent("type", false, false) + + var target = document.createElement("div") + target.addEventListener("type", dispatch_dispatch.step_func(function() { + assert_throws_dom("InvalidStateError", function() { + target.dispatchEvent(e) + }) + assert_throws_dom("InvalidStateError", function() { + document.dispatchEvent(e) + }) + }), false) + + assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true") + + dispatch_dispatch.done() +}) + +test(function() { + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17713 + // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17714 + + var e = document.createEvent("Event") + e.initEvent("type", false, false) + + var called = [] + + var target = document.createElement("div") + target.addEventListener("type", function() { + called.push("First") + throw new Error() + }, false) + + target.addEventListener("type", function() { + called.push("Second") + }, false) + + assert_equals(target.dispatchEvent(e), true, "dispatchEvent must return true") + assert_array_equals(called, ["First", "Second"], + "Should have continued to call other event listeners") +}, "Exceptions from event listeners must not be propagated.") + +async_test(function() { + var results = [] + var outerb = document.createElement("b") + var middleb = outerb.appendChild(document.createElement("b")) + var innerb = middleb.appendChild(document.createElement("b")) + outerb.addEventListener("x", this.step_func(function() { + middleb.addEventListener("x", this.step_func(function() { + results.push("middle") + }), true) + results.push("outer") + }), true) + innerb.dispatchEvent(new Event("x")) + assert_array_equals(results, ["outer", "middle"]) + this.done() +}, "Event listeners added during dispatch should be called"); + +async_test(function() { + var results = [] + var b = document.createElement("b") + b.addEventListener("x", this.step_func(function() { + results.push(1) + }), true) + b.addEventListener("x", this.step_func(function() { + results.push(2) + }), false) + b.addEventListener("x", this.step_func(function() { + results.push(3) + }), true) + b.dispatchEvent(new Event("x")) + assert_array_equals(results, [1, 3, 2]) + this.done() +}, "Capturing event listeners should be called before non-capturing ones") +</script> diff --git a/testing/web-platform/tests/dom/events/EventTarget-removeEventListener.any.js b/testing/web-platform/tests/dom/events/EventTarget-removeEventListener.any.js new file mode 100644 index 0000000000..289dfcfbab --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-removeEventListener.any.js @@ -0,0 +1,8 @@ +// META: title=EventTarget.removeEventListener + +// Step 1. +test(function() { + assert_equals(globalThis.removeEventListener("x", null, false), undefined); + assert_equals(globalThis.removeEventListener("x", null, true), undefined); + assert_equals(globalThis.removeEventListener("x", null), undefined); +}, "removing a null event listener should succeed"); diff --git a/testing/web-platform/tests/dom/events/EventTarget-this-of-listener.html b/testing/web-platform/tests/dom/events/EventTarget-this-of-listener.html new file mode 100644 index 0000000000..506564c413 --- /dev/null +++ b/testing/web-platform/tests/dom/events/EventTarget-this-of-listener.html @@ -0,0 +1,182 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>EventTarget listeners this value</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + node.addEventListener("someevent", function () { + ++callCount; + assert_equals(this, node); + }); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "the this value inside the event listener callback should be the node"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = { + handleEvent() { + ++callCount; + assert_equals(this, handler); + } + }; + + node.addEventListener("someevent", handler); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "the this value inside the event listener object handleEvent should be the object"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = { + handleEvent() { + assert_unreached("should not call the old handleEvent method"); + } + }; + + node.addEventListener("someevent", handler); + handler.handleEvent = function () { + ++callCount; + assert_equals(this, handler); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "dispatchEvent should invoke the current handleEvent method of the object"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = {}; + + node.addEventListener("someevent", handler); + handler.handleEvent = function () { + ++callCount; + assert_equals(this, handler); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "addEventListener should not require handleEvent to be defined on object listeners"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + function handler() { + ++callCount; + assert_equals(this, node); + } + + handler.handleEvent = () => { + assert_unreached("should not call the handleEvent method on a function"); + }; + + node.addEventListener("someevent", handler); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "handleEvent properties added to a function before addEventListener are not reached"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + function handler() { + ++callCount; + assert_equals(this, node); + } + + node.addEventListener("someevent", handler); + + handler.handleEvent = () => { + assert_unreached("should not call the handleEvent method on a function"); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "handleEvent properties added to a function after addEventListener are not reached"); + +</script> diff --git a/testing/web-platform/tests/dom/events/KeyEvent-initKeyEvent.html b/testing/web-platform/tests/dom/events/KeyEvent-initKeyEvent.html new file mode 100644 index 0000000000..3fffaba014 --- /dev/null +++ b/testing/web-platform/tests/dom/events/KeyEvent-initKeyEvent.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>KeyEvent.initKeyEvent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +// The legacy KeyEvent.initKeyEvent shouldn't be defined in the wild anymore. +// https://www.w3.org/TR/1999/WD-DOM-Level-2-19990923/events.html#Events-Event-initKeyEvent +test(function() { + const event = document.createEvent("KeyboardEvent"); + assert_true(event?.initKeyEvent === undefined); +}, "KeyboardEvent.initKeyEvent shouldn't be defined (created by createEvent(\"KeyboardEvent\")"); + +test(function() { + const event = new KeyboardEvent("keypress"); + assert_true(event?.initKeyEvent === undefined); +}, "KeyboardEvent.initKeyEvent shouldn't be defined (created by constructor)"); + +test(function() { + assert_true(KeyboardEvent.prototype.initKeyEvent === undefined); +}, "KeyboardEvent.prototype.initKeyEvent shouldn't be defined"); +</script> diff --git a/testing/web-platform/tests/dom/events/event-disabled-dynamic.html b/testing/web-platform/tests/dom/events/event-disabled-dynamic.html new file mode 100644 index 0000000000..3f995b02f1 --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-disabled-dynamic.html @@ -0,0 +1,21 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test that disabled is honored immediately in presence of dynamic changes</title> +<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io"> +<link rel="author" title="Andreas Farre" href="mailto:afarre@mozilla.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/#enabling-and-disabling-form-controls:-the-disabled-attribute"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1405087"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<input type="button" value="Click" disabled> +<script> +async_test(t => { + // NOTE: This test will timeout if it fails. + window.addEventListener('load', t.step_func(() => { + let e = document.querySelector('input'); + e.disabled = false; + e.onclick = t.step_func_done(() => {}); + e.click(); + })); +}, "disabled is honored properly in presence of dynamic changes"); +</script> diff --git a/testing/web-platform/tests/dom/events/event-global-extra.window.js b/testing/web-platform/tests/dom/events/event-global-extra.window.js new file mode 100644 index 0000000000..0f14961c40 --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global-extra.window.js @@ -0,0 +1,90 @@ +const otherWindow = document.body.appendChild(document.createElement("iframe")).contentWindow; + +["EventTarget", "XMLHttpRequest"].forEach(constructorName => { + async_test(t => { + const eventTarget = new otherWindow[constructorName](); + eventTarget.addEventListener("hi", t.step_func_done(e => { + assert_equals(otherWindow.event, undefined); + assert_equals(e, window.event); + })); + eventTarget.dispatchEvent(new Event("hi")); + }, "window.event for constructors from another global: " + constructorName); +}); + +// XXX: It would be good to test a subclass of EventTarget once we sort out +// https://github.com/heycam/webidl/issues/540 + +async_test(t => { + const element = document.body.appendChild(otherWindow.document.createElement("meh")); + element.addEventListener("yo", t.step_func_done(e => { + assert_equals(e, window.event); + })); + element.dispatchEvent(new Event("yo")); +}, "window.event and element from another document"); + +async_test(t => { + const doc = otherWindow.document, + element = doc.body.appendChild(doc.createElement("meh")), + child = element.appendChild(doc.createElement("bleh")); + element.addEventListener("yoyo", t.step_func(e => { + document.body.appendChild(element); + assert_equals(element.ownerDocument, document); + assert_equals(window.event, e); + assert_equals(otherWindow.event, undefined); + }), true); + element.addEventListener("yoyo", t.step_func(e => { + assert_equals(element.ownerDocument, document); + assert_equals(window.event, e); + assert_equals(otherWindow.event, undefined); + }), true); + child.addEventListener("yoyo", t.step_func_done(e => { + assert_equals(child.ownerDocument, document); + assert_equals(window.event, e); + assert_equals(otherWindow.event, undefined); + })); + child.dispatchEvent(new Event("yoyo")); +}, "window.event and moving an element post-dispatch"); + +test(t => { + const host = document.createElement("div"), + shadow = host.attachShadow({ mode: "open" }), + child = shadow.appendChild(document.createElement("trala")), + furtherChild = child.appendChild(document.createElement("waddup")); + let counter = 0; + host.addEventListener("hi", t.step_func(e => { + assert_equals(window.event, e); + assert_equals(counter++, 3); + })); + child.addEventListener("hi", t.step_func(e => { + assert_equals(window.event, undefined); + assert_equals(counter++, 2); + })); + furtherChild.addEventListener("hi", t.step_func(e => { + host.appendChild(child); + assert_equals(window.event, undefined); + assert_equals(counter++, 0); + })); + furtherChild.addEventListener("hi", t.step_func(e => { + assert_equals(window.event, undefined); + assert_equals(counter++, 1); + })); + furtherChild.dispatchEvent(new Event("hi", { composed: true, bubbles: true })); + assert_equals(counter, 4); +}, "window.event should not be affected by nodes moving post-dispatch"); + +async_test(t => { + const frame = document.body.appendChild(document.createElement("iframe")); + frame.src = "resources/event-global-extra-frame.html"; + frame.onload = t.step_func_done((load_event) => { + const event = new Event("hi"); + document.addEventListener("hi", frame.contentWindow.listener); // listener intentionally not wrapped in t.step_func + document.addEventListener("hi", t.step_func(e => { + assert_equals(event, e); + assert_equals(window.event, e); + })); + document.dispatchEvent(event); + assert_equals(frameState.event, event); + assert_equals(frameState.windowEvent, event); + assert_equals(frameState.parentEvent, load_event); + }); +}, "Listener from a different global"); diff --git a/testing/web-platform/tests/dom/events/event-global-is-still-set-when-coercing-beforeunload-result.html b/testing/web-platform/tests/dom/events/event-global-is-still-set-when-coercing-beforeunload-result.html new file mode 100644 index 0000000000..a64c8b6b8b --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global-is-still-set-when-coercing-beforeunload-result.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>window.event is still set when 'beforeunload' result is coerced to string</title> +<link rel="help" href="https://dom.spec.whatwg.org/#ref-for-window-current-event%E2%91%A1"> +<link rel="help" href="https://webidl.spec.whatwg.org/#call-a-user-objects-operation"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe id="iframe" src="resources/event-global-is-still-set-when-coercing-beforeunload-result-frame.html"></iframe> +<body> +<script> +window.onload = () => { + async_test(t => { + iframe.onload = t.step_func_done(() => { + assert_equals(typeof window.currentEventInToString, "object"); + assert_equals(window.currentEventInToString.type, "beforeunload"); + }); + + iframe.contentWindow.location.href = "about:blank"; + }); +}; +</script> diff --git a/testing/web-platform/tests/dom/events/event-global-is-still-set-when-reporting-exception-onerror.html b/testing/web-platform/tests/dom/events/event-global-is-still-set-when-reporting-exception-onerror.html new file mode 100644 index 0000000000..ceaac4fe2b --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global-is-still-set-when-reporting-exception-onerror.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>window.onerror handler restores window.event after it reports an exception</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<iframe src="resources/empty-document.html"></iframe> +<iframe src="resources/empty-document.html"></iframe> + +<script> +setup({ allow_uncaught_exception: true }); + +async_test(t => { + window.onload = t.step_func_done(onLoadEvent => { + frames[0].onerror = new frames[1].Function(` + top.eventDuringSecondOnError = top.window.event; + top.frames[0].eventDuringSecondOnError = top.frames[0].event; + top.frames[1].eventDuringSecondOnError = top.frames[1].event; + `); + + window.onerror = new frames[0].Function(` + top.eventDuringFirstOnError = top.window.event; + top.frames[0].eventDuringFirstOnError = top.frames[0].event; + top.frames[1].eventDuringFirstOnError = top.frames[1].event; + + foo; // cause second onerror + `); + + const myEvent = new ErrorEvent("error", { error: new Error("myError") }); + window.dispatchEvent(myEvent); + + assert_equals(top.eventDuringFirstOnError, onLoadEvent); + assert_equals(frames[0].eventDuringFirstOnError, myEvent); + assert_equals(frames[1].eventDuringFirstOnError, undefined); + + assert_equals(top.eventDuringSecondOnError, onLoadEvent); + assert_equals(frames[0].eventDuringSecondOnError, myEvent); + assert_equals(frames[1].eventDuringSecondOnError.error.name, "ReferenceError"); + }); +}); +</script> diff --git a/testing/web-platform/tests/dom/events/event-global-set-before-handleEvent-lookup.window.js b/testing/web-platform/tests/dom/events/event-global-set-before-handleEvent-lookup.window.js new file mode 100644 index 0000000000..8f934bcea9 --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global-set-before-handleEvent-lookup.window.js @@ -0,0 +1,19 @@ +// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke (steps 8.2 - 12) +// https://webidl.spec.whatwg.org/#call-a-user-objects-operation (step 10.1) + +test(() => { + const eventTarget = new EventTarget; + + let currentEvent; + eventTarget.addEventListener("foo", { + get handleEvent() { + currentEvent = window.event; + return () => {}; + } + }); + + const event = new Event("foo"); + eventTarget.dispatchEvent(event); + + assert_equals(currentEvent, event); +}, "window.event is set before 'handleEvent' lookup"); diff --git a/testing/web-platform/tests/dom/events/event-global.html b/testing/web-platform/tests/dom/events/event-global.html new file mode 100644 index 0000000000..3e8d25ecb5 --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global.html @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<title>window.event tests</title> +<link rel="author" title="Mike Taylor" href="mailto:miketaylr@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +setup({allow_uncaught_exception: true}); + +test(t => { + assert_own_property(window, "event"); + assert_equals(window.event, undefined); +}, "event exists on window, which is initially set to undefined"); + +async_test(t => { + let target = document.createElement("div"); + assert_equals(window.event, undefined, "undefined before dispatch"); + + let clickEvent = new Event("click"); + target.addEventListener("click", t.step_func_done(e => { + assert_equals(window.event, clickEvent, "window.event set to current event during dispatch"); + })); + + target.dispatchEvent(clickEvent); + assert_equals(window.event, undefined, "undefined after dispatch"); +}, "window.event is only defined during dispatch"); + +async_test(t => { + let parent = document.createElement("div"); + let root = parent.attachShadow({mode: "closed"}); + let span = document.createElement("span"); + root.appendChild(span); + + span.addEventListener("test", t.step_func(e => { + assert_equals(window.event, undefined); + assert_not_equals(window.event, e); + })); + + parent.addEventListener("test", t.step_func_done(e => { + assert_equals(window.event, e); + assert_not_equals(window.event, undefined); + })); + + parent.dispatchEvent(new Event("test", {composed: true})); +}, "window.event is undefined if the target is in a shadow tree (event dispatched outside shadow tree)"); + +async_test(t => { + let parent = document.createElement("div"); + let root = parent.attachShadow({mode: "closed"}); + let span = document.createElement("span"); + root.appendChild(span); + let shadowNode = root.firstElementChild; + + shadowNode.addEventListener("test", t.step_func((e) => { + assert_not_equals(window.event, e); + assert_equals(window.event, undefined); + })); + + parent.addEventListener("test", t.step_func_done(e => { + assert_equals(window.event, e); + assert_not_equals(window.event, undefined); + })); + + shadowNode.dispatchEvent(new Event("test", {composed: true, bubbles: true})); +}, "window.event is undefined if the target is in a shadow tree (event dispatched inside shadow tree)"); + +async_test(t => { + let parent = document.createElement("div"); + let root = parent.attachShadow({mode: "open"}); + document.body.append(parent) + let span = document.createElement("span"); + root.append(span); + let shadowNode = root.firstElementChild; + + shadowNode.addEventListener("error", t.step_func(e => { + assert_not_equals(window.event, e); + assert_equals(window.event, undefined); + })); + + let windowOnErrorCalled = false; + window.onerror = t.step_func_done(() => { + windowOnErrorCalled = true; + assert_equals(typeof window.event, "object"); + assert_equals(window.event.type, "error"); + }); + + shadowNode.dispatchEvent(new ErrorEvent("error", {composed: true, bubbles: true})); + assert_true(windowOnErrorCalled); +}, "window.event is undefined inside window.onerror if the target is in a shadow tree (ErrorEvent dispatched inside shadow tree)"); + +async_test(t => { + let target1 = document.createElement("div"); + let target2 = document.createElement("div"); + + target2.addEventListener("dude", t.step_func(() => { + assert_equals(window.event.type, "dude"); + })); + + target1.addEventListener("cool", t.step_func_done(() => { + assert_equals(window.event.type, "cool", "got expected event from global event during dispatch"); + target2.dispatchEvent(new Event("dude")); + assert_equals(window.event.type, "cool", "got expected event from global event after handling a different event handler callback"); + })); + + target1.dispatchEvent(new Event("cool")); +}, "window.event is set to the current event during dispatch"); + +async_test(t => { + let target = document.createElement("div"); + + target.addEventListener("click", t.step_func_done(e => { + assert_equals(e, window.event); + })); + + target.dispatchEvent(new Event("click")); +}, "window.event is set to the current event, which is the event passed to dispatch"); +</script> diff --git a/testing/web-platform/tests/dom/events/event-global.worker.js b/testing/web-platform/tests/dom/events/event-global.worker.js new file mode 100644 index 0000000000..116cf32932 --- /dev/null +++ b/testing/web-platform/tests/dom/events/event-global.worker.js @@ -0,0 +1,14 @@ +importScripts("/resources/testharness.js"); +test(t => { + let seen = false; + const event = new Event("hi"); + assert_equals(self.event, undefined); + self.addEventListener("hi", t.step_func(e => { + seen = true; + assert_equals(self.event, undefined); + assert_equals(e, event); + })); + self.dispatchEvent(event); + assert_true(seen); +}, "There's no self.event (that's why we call it window.event) in workers"); +done(); diff --git a/testing/web-platform/tests/dom/events/focus-event-document-move.html b/testing/web-platform/tests/dom/events/focus-event-document-move.html new file mode 100644 index 0000000000..2943761ce1 --- /dev/null +++ b/testing/web-platform/tests/dom/events/focus-event-document-move.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<link rel="author" href="mailto:masonf@chromium.org"> +<link rel="help" href="https://crbug.com/747207"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<script> + function handleDown(node) { + var d2 = new Document(); + d2.appendChild(node); + } +</script> + +<!-- No crash should occur if a node is moved during mousedown. --> +<div id='click' onmousedown='handleDown(this)'>Click me</div> + +<script> + const target = document.getElementById('click'); + async_test(t => { + let actions = new test_driver.Actions() + .pointerMove(0, 0, {origin: target}) + .pointerDown() + .pointerUp() + .send() + .then(t.step_func_done(() => { + assert_equals(null,document.getElementById('click')); + })) + .catch(e => t.step_func(() => assert_unreached('Error'))); + },'Moving a node during mousedown should not crash'); +</script> diff --git a/testing/web-platform/tests/dom/events/keypress-dispatch-crash.html b/testing/web-platform/tests/dom/events/keypress-dispatch-crash.html new file mode 100644 index 0000000000..3207adbd8c --- /dev/null +++ b/testing/web-platform/tests/dom/events/keypress-dispatch-crash.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="author" title="Robert Flack" href="mailto:flackr@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1209098"> + +<!-- No crash should occur if a keypress is dispatched to a constructed document. --> + +<script> +var newDoc = document.implementation.createDocument( "", null); +var testNode = newDoc.createElement('div'); +newDoc.append(testNode); + +var syntheticEvent = document.createEvent('KeyboardEvents'); +syntheticEvent.initKeyboardEvent("keypress"); +testNode.dispatchEvent(syntheticEvent) +</script> diff --git a/testing/web-platform/tests/dom/events/legacy-pre-activation-behavior.window.js b/testing/web-platform/tests/dom/events/legacy-pre-activation-behavior.window.js new file mode 100644 index 0000000000..e9e84bfad1 --- /dev/null +++ b/testing/web-platform/tests/dom/events/legacy-pre-activation-behavior.window.js @@ -0,0 +1,10 @@ +test(t => { + const input = document.body.appendChild(document.createElement('input')); + input.type = "radio"; + t.add_cleanup(() => input.remove()); + const clickEvent = new MouseEvent('click', { button: 0, which: 1 }); + input.addEventListener('change', t.step_func(() => { + assert_equals(clickEvent.eventPhase, Event.NONE); + })); + input.dispatchEvent(clickEvent); +}, "Use NONE phase during legacy-pre-activation behavior"); diff --git a/testing/web-platform/tests/dom/events/mouse-event-retarget.html b/testing/web-platform/tests/dom/events/mouse-event-retarget.html new file mode 100644 index 0000000000..c9ce6240d4 --- /dev/null +++ b/testing/web-platform/tests/dom/events/mouse-event-retarget.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<title>Script created MouseEvent properly retargets and adjusts offsetX</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> +body { + margin: 8px; + padding: 0; +} +</style> + +<div id="target">Hello</div> + +<script> +async_test(t => { + target.addEventListener('click', ev => { + t.step(() => assert_equals(ev.offsetX, 42)); + t.done(); + }); + + const ev = new MouseEvent('click', { clientX: 50 }); + target.dispatchEvent(ev); +}, "offsetX is correctly adjusted"); +</script> diff --git a/testing/web-platform/tests/dom/events/no-focus-events-at-clicking-editable-content-in-link.html b/testing/web-platform/tests/dom/events/no-focus-events-at-clicking-editable-content-in-link.html new file mode 100644 index 0000000000..dc08636c46 --- /dev/null +++ b/testing/web-platform/tests/dom/events/no-focus-events-at-clicking-editable-content-in-link.html @@ -0,0 +1,80 @@ +<!doctype html> +<html> +<head> +<meta chareset="utf-8"> +<title>Clicking editable content in link shouldn't cause redundant focus related events</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +</head> +<body> +<a href="#"><span contenteditable>Hello</span></a> +<a href="#" contenteditable><span>Hello</span></a> +<script> +function promiseTicks() { + return new Promise(resolve => { + requestAnimationFrame(() => { + requestAnimationFrame(resolve); + }); + }); +} + +async function clickElementAndCollectFocusEvents(x, y, options) { + await promiseTicks(); + let events = []; + for (const eventType of ["focus", "blur", "focusin", "focusout"]) { + document.addEventListener(eventType, event => { + events.push(`type: ${event.type}, target: ${event.target.nodeName}`); + }, {capture: true}); + } + + const waitForClickEvent = new Promise(resolve => { + addEventListener("click", resolve, {capture: true, once: true}); + }); + + await new test_driver + .Actions() + .pointerMove(x, y, options) + .pointerDown() + .pointerUp() + .send(); + + await waitForClickEvent; + await promiseTicks(); + return events; +} + +promise_test(async t => { + document.activeElement?.blur(); + const editingHost = document.querySelector("span[contenteditable]"); + editingHost.blur(); + const focusEvents = + await clickElementAndCollectFocusEvents(5, 5, {origin: editingHost}); + assert_array_equals( + focusEvents, + [ + "type: focus, target: SPAN", + "type: focusin, target: SPAN", + ], + "Click event shouldn't cause redundant focus events"); +}, "Click editable element in link"); + +promise_test(async t => { + document.activeElement?.blur(); + const editingHost = document.querySelector("a[contenteditable]"); + editingHost.blur(); + const focusEvents = + await clickElementAndCollectFocusEvents(5, 5, {origin: editingHost}); + assert_array_equals( + focusEvents, + [ + "type: focus, target: A", + "type: focusin, target: A", + ], + "Click event shouldn't cause redundant focus events"); +}, "Click editable link"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html new file mode 100644 index 0000000000..5574fe0acb --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-body.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>non-passive mousewheel event listener on body</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'mousewheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html new file mode 100644 index 0000000000..6fbf692cd7 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-div.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>non-passive mousewheel event listener on div</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<style> + html, body { + overflow: hidden; + margin: 0; + } + #div { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: scroll; + } +</style> +<div class=remove-on-cleanup id=div> + <div style="height: 200vh"></div> +</div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('div'), + eventName: 'mousewheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html new file mode 100644 index 0000000000..7d07393c69 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-document.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>non-passive mousewheel event listener on document</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'mousewheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html new file mode 100644 index 0000000000..e85fbacaba --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-root.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>non-passive mousewheel event listener on root</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'mousewheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html new file mode 100644 index 0000000000..29b09f8561 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-mousewheel-event-listener-on-window.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>non-passive mousewheel event listener on window</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'mousewheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-body.html new file mode 100644 index 0000000000..f417bdd0a6 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-body.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchmove event listener on body</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'touchmove', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-div.html new file mode 100644 index 0000000000..11c9345407 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-div.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchmove event listener on div</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('touchDiv'), + eventName: 'touchmove', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-document.html new file mode 100644 index 0000000000..8b95a8d492 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-document.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchmove event listener on document</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'touchmove', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-root.html new file mode 100644 index 0000000000..c41ab72bd8 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-root.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchmove event listener on root</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'touchmove', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-window.html new file mode 100644 index 0000000000..3d6675c566 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchmove-event-listener-on-window.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<link rel="help" href="https://github.com/WICG/interventions/issues/35"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-body.html new file mode 100644 index 0000000000..f6e6ecb06d --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-body.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchstart event listener on body</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-div.html new file mode 100644 index 0000000000..2e7c6e6b3b --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-div.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchstart event listener on div</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('touchDiv'), + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-document.html new file mode 100644 index 0000000000..22fcbdc322 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-document.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchstart event listener on document</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-root.html new file mode 100644 index 0000000000..56c51349a0 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-root.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchstart event listener on root</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-window.html new file mode 100644 index 0000000000..4e9d424a9d --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-touchstart-event-listener-on-window.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>non-passive touchstart event listener on window</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'touchstart', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html new file mode 100644 index 0000000000..070cadc291 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-body.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>non-passive wheel event listener on body</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'wheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html new file mode 100644 index 0000000000..c49d18ac13 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-div.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>non-passive wheel event listener on div</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<style> + html, body { + overflow: hidden; + margin: 0; + } + #div { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: scroll; + } +</style> +<div class=remove-on-cleanup id=div> + <div style="height: 200vh"></div> +</div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('div'), + eventName: 'wheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html new file mode 100644 index 0000000000..31a55cad43 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-document.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>non-passive wheel event listener on document</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'wheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html new file mode 100644 index 0000000000..b7bacbfc7c --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-root.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>non-passive wheel event listener on root</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'wheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html new file mode 100644 index 0000000000..c236059df4 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/non-passive-wheel-event-listener-on-window.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>non-passive wheel event listener on window</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'wheel', + passive: false, + expectCancelable: true, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html new file mode 100644 index 0000000000..9db12cfbdc --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-body.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>passive mousewheel event listener on body</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'mousewheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html new file mode 100644 index 0000000000..373670856b --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-div.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<title>passive mousewheel event listener on div</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<style> + html, body { + overflow: hidden; + margin: 0; + } + #div { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: scroll; + } +</style> +<div class=remove-on-cleanup id=div> + <div style="height: 200vh"></div> +</div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('div'), + eventName: 'mousewheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html new file mode 100644 index 0000000000..71262280b6 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-document.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>passive mousewheel event listener on document</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'mousewheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html new file mode 100644 index 0000000000..fc641d172e --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-root.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>passive mousewheel event listener on root</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'mousewheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html new file mode 100644 index 0000000000..f60955c7c4 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-mousewheel-event-listener-on-window.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>passive mousewheel event listener on window</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<link rel="help" href="https://github.com/w3c/uievents/issues/331"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'mousewheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-body.html new file mode 100644 index 0000000000..2349bad258 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-body.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchmove event listener on body</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'touchmove', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-div.html new file mode 100644 index 0000000000..a61b34851e --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-div.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchmove event listener on div</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('touchDiv'), + eventName: 'touchmove', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-document.html new file mode 100644 index 0000000000..b49971b5b0 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-document.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchmove event listener on document</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'touchmove', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-root.html new file mode 100644 index 0000000000..b851704590 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-root.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchmove event listener on root</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'touchmove', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-window.html new file mode 100644 index 0000000000..351d6ace84 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchmove-event-listener-on-window.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchmove event listener on window</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-body.html new file mode 100644 index 0000000000..c3d2b577fd --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-body.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchstart event listener on body</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-div.html new file mode 100644 index 0000000000..103e7f0d23 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-div.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchstart event listener on div</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('touchDiv'), + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-document.html new file mode 100644 index 0000000000..2e4de2405f --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-document.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchstart event listener on document</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-root.html new file mode 100644 index 0000000000..0f52e9a16f --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-root.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchstart event listener on root</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-window.html new file mode 100644 index 0000000000..c47af8101f --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-touchstart-event-listener-on-window.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>passive touchstart event listener on window</title> +<link rel="help" href="https://w3c.github.io/touch-events/#cancelability"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/wait-for.js"></script> +<script src="resources/touching.js"></script> +<style> +#touchDiv { + width: 100px; + height: 100px; +} +</style> +<div id="touchDiv"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'touchstart', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html new file mode 100644 index 0000000000..fe0869b022 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-body.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>passive wheel event listener on body</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.body, + eventName: 'wheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html new file mode 100644 index 0000000000..e2ca6e795a --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-div.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>passive wheel event listener on div</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<style> + html, body { + overflow: hidden; + margin: 0; + } + #div { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + overflow: scroll; + } +</style> +<div class=remove-on-cleanup id=div> + <div style="height: 200vh"></div> +</div> +<script> + document.body.onload = () => runTest({ + target: document.getElementById('div'), + eventName: 'wheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html new file mode 100644 index 0000000000..61b716f7bb --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-document.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>passive wheel event listener on document</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document, + eventName: 'wheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html new file mode 100644 index 0000000000..6b383bc871 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-root.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>passive wheel event listener on root</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: document.documentElement, + eventName: 'wheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html new file mode 100644 index 0000000000..a1e901f552 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/passive-wheel-event-listener-on-window.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>passive wheel event listener on window</title> +<link rel="help" href="https://w3c.github.io/uievents/#cancelability-of-wheel-events"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="resources/scrolling.js"></script> +<div class=remove-on-cleanup style="height: 200vh"></div> +<script> + document.body.onload = () => runTest({ + target: window, + eventName: 'wheel', + passive: true, + expectCancelable: false, + }); +</script> diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/scrolling.js b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/scrolling.js new file mode 100644 index 0000000000..88e10f5efd --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/scrolling.js @@ -0,0 +1,34 @@ +function raf() { + return new Promise((resolve) => { + // rAF twice. + window.requestAnimationFrame(() => { + window.requestAnimationFrame(resolve); + }); + }); +} + +async function runTest({target, eventName, passive, expectCancelable}) { + await raf(); + + let cancelable = null; + let arrived = false; + target.addEventListener(eventName, function (event) { + cancelable = event.cancelable; + arrived = true; + }, {passive:passive, once:true}); + + promise_test(async (t) => { + t.add_cleanup(() => { + document.querySelector('.remove-on-cleanup')?.remove(); + }); + const pos_x = Math.floor(window.innerWidth / 2); + const pos_y = Math.floor(window.innerHeight / 2); + const delta_x = 0; + const delta_y = 100; + + await new test_driver.Actions() + .scroll(pos_x, pos_y, delta_x, delta_y).send(); + await t.step_wait(() => arrived, `Didn't get event ${eventName} on ${target.localName}`); + assert_equals(cancelable, expectCancelable); + }); +} diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/touching.js b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/touching.js new file mode 100644 index 0000000000..620d26804b --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/touching.js @@ -0,0 +1,34 @@ +function waitForCompositorCommit() { + return new Promise((resolve) => { + // rAF twice. + window.requestAnimationFrame(() => { + window.requestAnimationFrame(resolve); + }); + }); +} + +function injectInput(touchDiv) { + return new test_driver.Actions() + .addPointer("touch_pointer", "touch") + .pointerMove(0, 0, {origin: touchDiv}) + .pointerDown() + .pointerMove(30, 30) + .pointerUp() + .send(); +} + +function runTest({target, eventName, passive, expectCancelable}) { + let touchDiv = document.getElementById("touchDiv"); + let cancelable = null; + let arrived = false; + target.addEventListener(eventName, function (event) { + cancelable = event.cancelable; + arrived = true; + }, {passive}); + promise_test(async () => { + await waitForCompositorCommit(); + await injectInput(touchDiv); + await waitFor(() => arrived); + assert_equals(cancelable, expectCancelable); + }); +} diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/wait-for.js b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/wait-for.js new file mode 100644 index 0000000000..0bf3e55834 --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/resources/wait-for.js @@ -0,0 +1,15 @@ +function waitFor(condition, MAX_FRAME = 500) { + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for MAX_FRAME frames or until condition is + // met. + if (frames >= MAX_FRAME) + reject(new Error(`Condition did not become true after ${MAX_FRAME} frames`)); + else if (condition()) + resolve(); + else + requestAnimationFrame(() => tick(frames + 1)); + } + tick(0); + }); +} diff --git a/testing/web-platform/tests/dom/events/non-cancelable-when-passive/synthetic-events-cancelable.html b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/synthetic-events-cancelable.html new file mode 100644 index 0000000000..4287770b8d --- /dev/null +++ b/testing/web-platform/tests/dom/events/non-cancelable-when-passive/synthetic-events-cancelable.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>Synthetic events are always cancelable by default</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dictdef-eventinit"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +const eventsMap = { + wheel: 'WheelEvent', + mousewheel: 'WheelEvent', + touchstart: 'TouchEvent', + touchmove: 'TouchEvent', + touchend: 'TouchEvent', + touchcancel: 'TouchEvent', +} +function isCancelable(eventName, interfaceName) { + test(() => { + assert_implements(interfaceName in self, `${interfaceName} should be supported`); + let defaultPrevented = null; + addEventListener(eventName, event => { + event.preventDefault(); + defaultPrevented = event.defaultPrevented; + }); + const event = new self[interfaceName](eventName); + assert_false(event.cancelable, 'cancelable'); + const dispatchEventReturnValue = dispatchEvent(event); + assert_false(defaultPrevented, 'defaultPrevented'); + assert_true(dispatchEventReturnValue, 'dispatchEvent() return value'); + }, `Synthetic ${eventName} event with interface ${interfaceName} is not cancelable`); +} +for (const eventName in eventsMap) { + isCancelable(eventName, eventsMap[eventName]); + isCancelable(eventName, 'Event'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/passive-by-default.html b/testing/web-platform/tests/dom/events/passive-by-default.html new file mode 100644 index 0000000000..02029f4dac --- /dev/null +++ b/testing/web-platform/tests/dom/events/passive-by-default.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<title>Default passive event listeners on window, document, document element, body</title> +<link rel="help" href="https://dom.spec.whatwg.org/#default-passive-value"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> + <div id="div"></div> +<script> + function isListenerPassive(eventName, eventTarget, passive, expectPassive) { + test(() => { + let defaultPrevented = null; + let handler = event => { + event.preventDefault(); + defaultPrevented = event.defaultPrevented; + eventTarget.removeEventListener(eventName, handler); + }; + if (passive === 'omitted') { + eventTarget.addEventListener(eventName, handler); + } else { + eventTarget.addEventListener(eventName, handler, {passive}); + } + let dispatchEventReturnValue = eventTarget.dispatchEvent(new Event(eventName, {cancelable: true})); + assert_equals(defaultPrevented, !expectPassive, 'defaultPrevented'); + assert_equals(dispatchEventReturnValue, expectPassive, 'dispatchEvent() return value'); + }, `${eventName} listener is ${expectPassive ? '' : 'non-'}passive ${passive === 'omitted' ? 'by default' : `with {passive:${passive}}`} for ${eventTarget.constructor.name}`); + } + + const eventNames = { + touchstart: true, + touchmove: true, + wheel: true, + mousewheel: true, + touchend: false + }; + const passiveEventTargets = [window, document, document.documentElement, document.body]; + const div = document.getElementById('div'); + + for (const eventName in eventNames) { + for (const eventTarget of passiveEventTargets) { + isListenerPassive(eventName, eventTarget, 'omitted', eventNames[eventName]); + isListenerPassive(eventName, eventTarget, undefined, eventNames[eventName]); + isListenerPassive(eventName, eventTarget, false, false); + isListenerPassive(eventName, eventTarget, true, true); + } + isListenerPassive(eventName, div, 'omitted', false); + isListenerPassive(eventName, div, undefined, false); + isListenerPassive(eventName, div, false, false); + isListenerPassive(eventName, div, true, true); + } +</script> diff --git a/testing/web-platform/tests/dom/events/relatedTarget.window.js b/testing/web-platform/tests/dom/events/relatedTarget.window.js new file mode 100644 index 0000000000..ebc83ceb20 --- /dev/null +++ b/testing/web-platform/tests/dom/events/relatedTarget.window.js @@ -0,0 +1,81 @@ +// https://dom.spec.whatwg.org/#concept-event-dispatch + +const host = document.createElement("div"), + child = host.appendChild(document.createElement("p")), + shadow = host.attachShadow({ mode: "closed" }), + slot = shadow.appendChild(document.createElement("slot")); + +test(() => { + for (target of [shadow, slot]) { + for (relatedTarget of [new XMLHttpRequest(), self, host]) { + const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); + target.dispatchEvent(event); + assert_equals(event.target, null); + assert_equals(event.relatedTarget, null); + } + } +}, "Reset if target pointed to a shadow tree"); + +test(() => { + for (relatedTarget of [shadow, slot]) { + for (target of [new XMLHttpRequest(), self, host]) { + const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); + target.dispatchEvent(event); + assert_equals(event.target, target); + assert_equals(event.relatedTarget, host); + } + } +}, "Retarget a shadow-tree relatedTarget"); + +test(t => { + const shadowChild = shadow.appendChild(document.createElement("div")); + shadowChild.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); + const event = new FocusEvent("demo", { relatedTarget: new XMLHttpRequest() }); + shadowChild.dispatchEvent(event); + assert_equals(shadowChild.parentNode, document.body); + assert_equals(event.target, null); + assert_equals(event.relatedTarget, null); + shadowChild.remove(); +}, "Reset if target pointed to a shadow tree pre-dispatch"); + +test(t => { + const shadowChild = shadow.appendChild(document.createElement("div")); + document.body.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); + const event = new FocusEvent("demo", { relatedTarget: shadowChild }); + document.body.dispatchEvent(event); + assert_equals(shadowChild.parentNode, document.body); + assert_equals(event.target, document.body); + assert_equals(event.relatedTarget, host); + shadowChild.remove(); +}, "Retarget a shadow-tree relatedTarget, part 2"); + +test(t => { + const event = new FocusEvent("heya", { relatedTarget: shadow, cancelable: true }), + callback = t.unreached_func(); + host.addEventListener("heya", callback); + t.add_cleanup(() => host.removeEventListener("heya", callback)); + event.preventDefault(); + assert_true(event.defaultPrevented); + assert_false(host.dispatchEvent(event)); + assert_equals(event.target, null); + assert_equals(event.relatedTarget, null); + // Check that the dispatch flag is cleared + event.initEvent("x"); + assert_equals(event.type, "x"); +}, "Reset targets on early return"); + +test(t => { + const input = document.body.appendChild(document.createElement("input")), + event = new MouseEvent("click", { relatedTarget: shadow }); + let seen = false; + t.add_cleanup(() => input.remove()); + input.type = "checkbox"; + input.oninput = t.step_func(() => { + assert_equals(event.target, null); + assert_equals(event.relatedTarget, null); + assert_equals(event.composedPath().length, 0); + seen = true; + }); + assert_true(input.dispatchEvent(event)); + assert_true(seen); +}, "Reset targets before activation behavior"); diff --git a/testing/web-platform/tests/dom/events/replace-event-listener-null-browsing-context-crash.html b/testing/web-platform/tests/dom/events/replace-event-listener-null-browsing-context-crash.html new file mode 100644 index 0000000000..f41955eedd --- /dev/null +++ b/testing/web-platform/tests/dom/events/replace-event-listener-null-browsing-context-crash.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>Event listeners: replace listener after moving between documents</title> +<link rel="author" title="Nate Chapin" href="mailto:japhet@chromium.org"> +<link rel="help" href="https://w3c.github.io/touch-events/#dom-globaleventhandlers-ontouchcancel"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1083793"> +<meta name="assert" content="Overwriting an attribute event listener after adopting the owning node to a different document should not crash"/> +<progress id="p"> +<iframe id="i"></iframe> +<script> +var p = document.getElementById("p"); +i.contentDocument.adoptNode(p); +p.setAttribute("ontouchcancel", ""); +document.body.appendChild(p); +p.setAttribute("ontouchcancel", ""); +</script> + diff --git a/testing/web-platform/tests/dom/events/resources/empty-document.html b/testing/web-platform/tests/dom/events/resources/empty-document.html new file mode 100644 index 0000000000..b9cd130a07 --- /dev/null +++ b/testing/web-platform/tests/dom/events/resources/empty-document.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<body> diff --git a/testing/web-platform/tests/dom/events/resources/event-global-extra-frame.html b/testing/web-platform/tests/dom/events/resources/event-global-extra-frame.html new file mode 100644 index 0000000000..241dda8b66 --- /dev/null +++ b/testing/web-platform/tests/dom/events/resources/event-global-extra-frame.html @@ -0,0 +1,9 @@ +<script> +function listener(e) { + parent.frameState = { + event: e, + windowEvent: window.event, + parentEvent: parent.event + } +} +</script> diff --git a/testing/web-platform/tests/dom/events/resources/event-global-is-still-set-when-coercing-beforeunload-result-frame.html b/testing/web-platform/tests/dom/events/resources/event-global-is-still-set-when-coercing-beforeunload-result-frame.html new file mode 100644 index 0000000000..5df4fa2793 --- /dev/null +++ b/testing/web-platform/tests/dom/events/resources/event-global-is-still-set-when-coercing-beforeunload-result-frame.html @@ -0,0 +1,6 @@ +<!doctype html> +<meta charset="utf-8"> +<body> +<script> +window.onbeforeunload = () => ({ toString: () => { parent.currentEventInToString = window.event; } }); +</script> diff --git a/testing/web-platform/tests/dom/events/resources/prefixed-animation-event-tests.js b/testing/web-platform/tests/dom/events/resources/prefixed-animation-event-tests.js new file mode 100644 index 0000000000..021b6bb9df --- /dev/null +++ b/testing/web-platform/tests/dom/events/resources/prefixed-animation-event-tests.js @@ -0,0 +1,366 @@ +'use strict' + +// Runs a set of tests for a given prefixed/unprefixed animation event (e.g. +// animationstart/webkitAnimationStart). +// +// The eventDetails object must have the following form: +// { +// isTransition: false, <-- can be omitted, default false +// unprefixedType: 'animationstart', +// prefixedType: 'webkitAnimationStart', +// animationCssStyle: '1ms', <-- must NOT include animation name or +// transition property +// } +function runAnimationEventTests(eventDetails) { + const { + isTransition, + unprefixedType, + prefixedType, + animationCssStyle + } = eventDetails; + + // Derive the DOM event handler names, e.g. onanimationstart. + const unprefixedHandler = `on${unprefixedType}`; + const prefixedHandler = `on${prefixedType.toLowerCase()}`; + + const style = document.createElement('style'); + document.head.appendChild(style); + if (isTransition) { + style.sheet.insertRule( + `.baseStyle { width: 100px; transition: width ${animationCssStyle}; }`); + style.sheet.insertRule('.transition { width: 200px !important; }'); + } else { + style.sheet.insertRule('@keyframes anim {}'); + } + + function triggerAnimation(div) { + if (isTransition) { + div.classList.add('transition'); + } else { + div.style.animation = `anim ${animationCssStyle}`; + } + } + + test(t => { + const div = createDiv(t); + + assert_equals(div[unprefixedHandler], null, + `${unprefixedHandler} should initially be null`); + assert_equals(div[prefixedHandler], null, + `${prefixedHandler} should initially be null`); + + // Setting one should not affect the other. + div[unprefixedHandler] = () => { }; + + assert_not_equals(div[unprefixedHandler], null, + `setting ${unprefixedHandler} should make it non-null`); + assert_equals(div[prefixedHandler], null, + `setting ${unprefixedHandler} should not affect ${prefixedHandler}`); + + div[prefixedHandler] = () => { }; + + assert_not_equals(div[prefixedHandler], null, + `setting ${prefixedHandler} should make it non-null`); + assert_not_equals(div[unprefixedHandler], div[prefixedHandler], + 'the setters should be different'); + }, `${unprefixedHandler} and ${prefixedHandler} are not aliases`); + + // The below tests primarily test the interactions of prefixed animation + // events in the algorithm for invoking events: + // https://dom.spec.whatwg.org/#concept-event-listener-invoke + + promise_test(async t => { + const div = createDiv(t); + + let receivedEventCount = 0; + addTestScopedEventHandler(t, div, prefixedHandler, () => { + receivedEventCount++; + }); + addTestScopedEventListener(t, div, prefixedType, () => { + receivedEventCount++; + }); + + // The HTML spec[0] specifies that the prefixed event handlers have an + // 'Event handler event type' of the appropriate prefixed event type. E.g. + // onwebkitanimationend creates a listener for the event type + // 'webkitAnimationEnd'. + // + // [0]: https://html.spec.whatwg.org/multipage/webappapis.html#event-handlers-on-elements,-document-objects,-and-window-objects + div.dispatchEvent(new AnimationEvent(prefixedType)); + assert_equals(receivedEventCount, 2, + 'prefixed listener and handler received event'); + }, `dispatchEvent of a ${prefixedType} event does trigger a ` + + `prefixed event handler or listener`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedEvent = false; + addTestScopedEventHandler(t, div, unprefixedHandler, () => { + receivedEvent = true; + }); + addTestScopedEventListener(t, div, unprefixedType, () => { + receivedEvent = true; + }); + + div.dispatchEvent(new AnimationEvent(prefixedType)); + assert_false(receivedEvent, + 'prefixed listener or handler received event'); + }, `dispatchEvent of a ${prefixedType} event does not trigger an ` + + `unprefixed event handler or listener`); + + + promise_test(async t => { + const div = createDiv(t); + + let receivedEvent = false; + addTestScopedEventHandler(t, div, prefixedHandler, () => { + receivedEvent = true; + }); + addTestScopedEventListener(t, div, prefixedType, () => { + receivedEvent = true; + }); + + // The rewrite rules from + // https://dom.spec.whatwg.org/#concept-event-listener-invoke step 8 do not + // apply because isTrusted will be false. + div.dispatchEvent(new AnimationEvent(unprefixedType)); + assert_false(receivedEvent, 'prefixed listener or handler received event'); + }, `dispatchEvent of an ${unprefixedType} event does not trigger a ` + + `prefixed event handler or listener`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedEvent = false; + addTestScopedEventHandler(t, div, prefixedHandler, () => { + receivedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedType); + assert_true(receivedEvent, `received ${prefixedHandler} event`); + }, `${prefixedHandler} event handler should trigger for an animation`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedPrefixedEvent = false; + addTestScopedEventHandler(t, div, prefixedHandler, () => { + receivedPrefixedEvent = true; + }); + let receivedUnprefixedEvent = false; + addTestScopedEventHandler(t, div, unprefixedHandler, () => { + receivedUnprefixedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedType); + assert_true(receivedUnprefixedEvent, `received ${unprefixedHandler} event`); + assert_false(receivedPrefixedEvent, `received ${prefixedHandler} event`); + }, `${prefixedHandler} event handler should not trigger if an unprefixed ` + + `event handler also exists`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedPrefixedEvent = false; + addTestScopedEventHandler(t, div, prefixedHandler, () => { + receivedPrefixedEvent = true; + }); + let receivedUnprefixedEvent = false; + addTestScopedEventListener(t, div, unprefixedType, () => { + receivedUnprefixedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + assert_true(receivedUnprefixedEvent, `received ${unprefixedHandler} event`); + assert_false(receivedPrefixedEvent, `received ${prefixedHandler} event`); + }, `${prefixedHandler} event handler should not trigger if an unprefixed ` + + `listener also exists`); + + promise_test(async t => { + // We use a parent/child relationship to be able to register both prefixed + // and unprefixed event handlers without the deduplication logic kicking in. + const parent = createDiv(t); + const child = createDiv(t); + parent.appendChild(child); + // After moving the child, we have to clean style again. + getComputedStyle(child).transition; + getComputedStyle(child).width; + + let observedUnprefixedType; + addTestScopedEventHandler(t, parent, unprefixedHandler, e => { + observedUnprefixedType = e.type; + }); + let observedPrefixedType; + addTestScopedEventHandler(t, child, prefixedHandler, e => { + observedPrefixedType = e.type; + }); + + triggerAnimation(child); + await waitForEventThenAnimationFrame(t, unprefixedType); + + assert_equals(observedUnprefixedType, unprefixedType); + assert_equals(observedPrefixedType, prefixedType); + }, `event types for prefixed and unprefixed ${unprefixedType} event ` + + `handlers should be named appropriately`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedEvent = false; + addTestScopedEventListener(t, div, prefixedType, () => { + receivedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + assert_true(receivedEvent, `received ${prefixedType} event`); + }, `${prefixedType} event listener should trigger for an animation`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedPrefixedEvent = false; + addTestScopedEventListener(t, div, prefixedType, () => { + receivedPrefixedEvent = true; + }); + let receivedUnprefixedEvent = false; + addTestScopedEventListener(t, div, unprefixedType, () => { + receivedUnprefixedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + assert_true(receivedUnprefixedEvent, `received ${unprefixedType} event`); + assert_false(receivedPrefixedEvent, `received ${prefixedType} event`); + }, `${prefixedType} event listener should not trigger if an unprefixed ` + + `listener also exists`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedPrefixedEvent = false; + addTestScopedEventListener(t, div, prefixedType, () => { + receivedPrefixedEvent = true; + }); + let receivedUnprefixedEvent = false; + addTestScopedEventHandler(t, div, unprefixedHandler, () => { + receivedUnprefixedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + assert_true(receivedUnprefixedEvent, `received ${unprefixedType} event`); + assert_false(receivedPrefixedEvent, `received ${prefixedType} event`); + }, `${prefixedType} event listener should not trigger if an unprefixed ` + + `event handler also exists`); + + promise_test(async t => { + // We use a parent/child relationship to be able to register both prefixed + // and unprefixed event listeners without the deduplication logic kicking in. + const parent = createDiv(t); + const child = createDiv(t); + parent.appendChild(child); + // After moving the child, we have to clean style again. + getComputedStyle(child).transition; + getComputedStyle(child).width; + + let observedUnprefixedType; + addTestScopedEventListener(t, parent, unprefixedType, e => { + observedUnprefixedType = e.type; + }); + let observedPrefixedType; + addTestScopedEventListener(t, child, prefixedType, e => { + observedPrefixedType = e.type; + }); + + triggerAnimation(child); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + + assert_equals(observedUnprefixedType, unprefixedType); + assert_equals(observedPrefixedType, prefixedType); + }, `event types for prefixed and unprefixed ${unprefixedType} event ` + + `listeners should be named appropriately`); + + promise_test(async t => { + const div = createDiv(t); + + let receivedEvent = false; + addTestScopedEventListener(t, div, prefixedType.toLowerCase(), () => { + receivedEvent = true; + }); + addTestScopedEventListener(t, div, prefixedType.toUpperCase(), () => { + receivedEvent = true; + }); + + triggerAnimation(div); + await waitForEventThenAnimationFrame(t, unprefixedHandler); + assert_false(receivedEvent, `received ${prefixedType} event`); + }, `${prefixedType} event listener is case sensitive`); +} + +// Below are utility functions. + +// Creates a div element, appends it to the document body and removes the +// created element during test cleanup. +function createDiv(test) { + const element = document.createElement('div'); + element.classList.add('baseStyle'); + document.body.appendChild(element); + test.add_cleanup(() => { + element.remove(); + }); + + // Flush style before returning. Some browsers only do partial style re-calc, + // so ask for all important properties to make sure they are applied. + getComputedStyle(element).transition; + getComputedStyle(element).width; + + return element; +} + +// Adds an event handler for |handlerName| (calling |callback|) to the given +// |target|, that will automatically be cleaned up at the end of the test. +function addTestScopedEventHandler(test, target, handlerName, callback) { + assert_regexp_match( + handlerName, /^on/, 'Event handler names must start with "on"'); + assert_equals(target[handlerName], null, + `${handlerName} must be supported and not previously set`); + target[handlerName] = callback; + // We need this cleaned up even if the event handler doesn't run. + test.add_cleanup(() => { + if (target[handlerName]) + target[handlerName] = null; + }); +} + +// Adds an event listener for |type| (calling |callback|) to the given +// |target|, that will automatically be cleaned up at the end of the test. +function addTestScopedEventListener(test, target, type, callback) { + target.addEventListener(type, callback); + // We need this cleaned up even if the event handler doesn't run. + test.add_cleanup(() => { + target.removeEventListener(type, callback); + }); +} + +// Returns a promise that will resolve once the passed event (|eventName|) has +// triggered and one more animation frame has happened. Automatically chooses +// between an event handler or event listener based on whether |eventName| +// begins with 'on'. +// +// We always listen on window as we don't want to interfere with the test via +// triggering the prefixed event deduplication logic. +function waitForEventThenAnimationFrame(test, eventName) { + return new Promise((resolve, _) => { + const eventFunc = eventName.startsWith('on') + ? addTestScopedEventHandler : addTestScopedEventListener; + eventFunc(test, window, eventName, () => { + // rAF once to give the event under test time to come through. + requestAnimationFrame(resolve); + }); + }); +} diff --git a/testing/web-platform/tests/dom/events/scrolling/iframe-chains.html b/testing/web-platform/tests/dom/events/scrolling/iframe-chains.html new file mode 100644 index 0000000000..fb7d674aae --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/iframe-chains.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<style> + +body { margin: 0; padding: 10px; } +.space { height: 2000px; } + +#scroller { + border: 3px solid green; + position: absolute; + z-index: 0; + overflow: auto; + padding: 10px; + width: 250px; + height: 150px; +} + +.ifr { + border: 3px solid blue; + width: 200px; + height: 100px; +} + +</style> +</head> +<body> +<div id=scroller> + <iframe srcdoc="SCROLL ME" class=ifr></iframe> + <div class=space></div> +</div> +<div class=space></div> +<script> + +promise_test(async t => { + await new test_driver.Actions().scroll(50, 50, 0, 50).send(); + // Allow the possibility the scroll is not fully synchronous + await t.step_wait(() => scroller.scrollTop === 50); +}, "Wheel scroll in iframe chains to containing element."); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/scrolling/input-text-scroll-event-when-using-arrow-keys.html b/testing/web-platform/tests/dom/events/scrolling/input-text-scroll-event-when-using-arrow-keys.html new file mode 100644 index 0000000000..f84e446527 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/input-text-scroll-event-when-using-arrow-keys.html @@ -0,0 +1,71 @@ +<!doctype html> +<html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +</head> +<body onload=runTest()> + <p>Moving the cursor using the arrow keys into an + input element fires scroll events when text has to scroll into view. + Uses arrow keys to move forward and backwards in the input + element.</p> + <input type="text" style='width: 50px' + value="Fooooooooooooooooooooooooooooooooooooooooooooooooo"/> + <textarea rows="4" cols="4"> + Fooooooooooooooooooooooooooooooooooooooooooooooooo + </textarea> + + <script> + async function moveCursorRightInsideElement(element, value){ + var arrowRight = '\uE014'; + for(var i=0;i<value;i++){ + await test_driver.send_keys(element, arrowRight); + } + } + + function runTest(){ + promise_test(async(t) => { return new Promise(async (resolve, reject) => { + var input = document.getElementsByTagName('input')[0]; + function handleScroll(){ + resolve("Scroll Event successfully fired!"); + } + input.addEventListener('scroll', handleScroll, false); + // move cursor to the right until the text scrolls + while(input.scrollLeft === 0){ + await moveCursorRightInsideElement(input, 1); + } + // if there is no scroll event fired then test will fail by timeout + })}, + /* + Moving the cursor using the arrow keys into an input element + fires scroll events when text has to scroll into view. + Uses arrow keys to move right in the input element. + */ + "Scroll event fired for <input> element."); + + promise_test(async(t) => { return new Promise(async (resolve, reject) => { + var textarea = document.getElementsByTagName('textarea')[0]; + function handleScroll(){ + resolve("Scroll Event successfully fired!"); + } + textarea.addEventListener('scroll', handleScroll, false); + // move cursor to the right until the text scrolls + while(textarea.scrollLeft === 0){ + await moveCursorRightInsideElement(textarea, 1); + } + // if there is no scroll event fired then test will fail by timeout + })}, + /* + Moving the cursor using the arrow keys into a textarea element + fires scroll events when text has to scroll into view. + Uses arrow keys to move right in the textarea element. + */ + "Scroll event fired for <textarea> element."); + } + </script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/events/scrolling/overscroll-deltas.html b/testing/web-platform/tests/dom/events/scrolling/overscroll-deltas.html new file mode 100644 index 0000000000..6f0b77f22e --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/overscroll-deltas.html @@ -0,0 +1,85 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 500px; + height: 500px; + background: red; +} +html, body { + /* Prevent any built-in browser overscroll features from consuming the scroll + * deltas */ + overscroll-behavior: none; +} + +</style> + +<body style="margin:0;" onload=runTest()> +<div id="targetDiv"> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var overscrolled_x_deltas = []; +var overscrolled_y_deltas = []; +var scrollend_received = false; + +function onOverscroll(event) { + overscrolled_x_deltas.push(event.deltaX); + overscrolled_y_deltas.push(event.deltaY); +} + +function onScrollend(event) { + scrollend_received = true; +} + +document.addEventListener("overscroll", onOverscroll); +document.addEventListener("scrollend", onScrollend); + +function runTest() { + promise_test (async (t) => { + await waitForCompositorCommit(); + + // Scroll up on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return scrollend_received; }, + 'Document did not receive scrollend event.'); + + // Even though we request 300 pixels of scroll, the API above doesn't + // guarantee how much scroll delta will be generated - different browsers + // can consume different amounts for "touch slop" (for example). Ensure the + // overscroll reaches at least 100 pixels which is a fairly conservative + // value. + assert_greater_than(overscrolled_y_deltas.length, 0, "There should be at least one overscroll events when overscrolling."); + assert_equals(overscrolled_x_deltas.filter(function(x){ return x!=0; }).length, 0, "The deltaX attribute must be 0 when there is no scrolling in x direction."); + assert_less_than_equal(Math.max(...overscrolled_y_deltas), 0, "The deltaY attribute must be <= 0 when there is overscrolling in up direction."); + assert_less_than_equal(Math.min(...overscrolled_y_deltas),-100, "The deltaY attribute must be the number of pixels overscrolled."); + + await waitForCompositorCommit(); + overscrolled_x_deltas = []; + overscrolled_y_deltas = []; + scrollend_received = false; + + // Scroll left on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return scrollend_received; }, + 'Document did not receive scrollend event.'); + + // TODO(bokan): It looks like Chrome inappropriately filters some scroll + // events despite |overscroll-behavior| being set to none. The overscroll + // amount here has been loosened but this should be fixed in Chrome. + // https://crbug.com/1112183. + assert_greater_than(overscrolled_y_deltas.length, 0, "There should be at least one overscroll events when overscrolling."); + assert_equals(overscrolled_y_deltas.filter(function(x){ return x!=0; }).length, 0, "The deltaY attribute must be 0 when there is no scrolling in y direction."); + assert_less_than_equal(Math.max(...overscrolled_x_deltas), 0, "The deltaX attribute must be <= 0 when there is overscrolling in left direction."); + assert_less_than_equal(Math.min(...overscrolled_x_deltas),-50, "The deltaX attribute must be the number of pixels overscrolled."); + + }, 'Tests that the document gets overscroll event with right deltaX/Y attributes.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-document.html b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-document.html new file mode 100644 index 0000000000..c054ffca9c --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-document.html @@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscroll(event) { + assert_false(event.cancelable); + // overscroll events are bubbled when the target node is document. + assert_true(event.bubbles); + overscrolled_x_delta = event.deltaX; + overscrolled_y_delta = event.deltaY; +} +document.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to target_div. + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + await waitForCompositorCommit(); + + // Scroll up on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return overscrolled_y_delta < 0; }, + 'Document did not receive overscroll event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + + // Scroll left on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return overscrolled_x_delta < 0; }, + 'Document did not receive overscroll event after scroll left on target.'); + assert_equals(target_div.scrollLeft, 0); + }, 'Tests that the document gets overscroll event when no element scrolls ' + + 'after touch scrolling.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html new file mode 100644 index 0000000000..750080e656 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html @@ -0,0 +1,92 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#overscrollXDiv { + width: 600px; + height: 600px; + overflow: scroll; + overscroll-behavior-x: contain; +} +#overscrollYDiv { + width: 500px; + height: 500px; + overflow: scroll; + overscroll-behavior-y: none; +} +#targetDiv { + width: 400px; + height: 400px; + overflow: scroll; +} +.content { + width:800px; + height:800px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="overscrollXDiv"> + <div class=content> + <div id="overscrollYDiv"> + <div class=content> + <div id="targetDiv"> + <div class="content"> + </div> + </div> + </div> + </div> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscrollX(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_x_delta = event.deltaX; +} +function onOverscrollY(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_y_delta = event.deltaY; +} +// Test that both "onoverscroll" and addEventListener("overscroll"... work. +document.getElementById('overscrollXDiv').onoverscroll = onOverscrollX; +document.getElementById('overscrollYDiv'). + addEventListener("overscroll", onOverscrollY); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to document or target_div. + document.addEventListener("overscroll", + t.unreached_func("Document got unexpected overscroll event.")); + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + await waitForCompositorCommit(); + // Scroll up on target div and wait for the element with overscroll-y to get + // overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return overscrolled_y_delta < 0; }, + 'Expected element did not receive overscroll event after scroll up on ' + + 'target.'); + assert_equals(target_div.scrollTop, 0); + + // Scroll left on target div and wait for the element with overscroll-x to + // get overscroll event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return overscrolled_x_delta < 0; }, + 'Expected element did not receive overscroll event after scroll left ' + + 'on target.'); + assert_equals(target_div.scrollLeft, 0); + }, 'Tests that the last element in the cut scroll chain gets overscroll ' + + 'event when no element scrolls by touch.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html new file mode 100644 index 0000000000..cfc782a809 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#scrollableDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="scrollableDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var scrolling_div = document.getElementById('scrollableDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscroll(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_x_delta = event.deltaX; + overscrolled_y_delta = event.deltaY; +} +scrolling_div.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to document. + document.addEventListener("overscroll", + t.unreached_func("Document got unexpected overscroll event.")); + await waitForCompositorCommit(); + + // Do a horizontal scroll and wait for overscroll event. + await touchScrollInTarget(300, scrolling_div , 'right'); + await waitFor(() => { return overscrolled_x_delta > 0; }, + 'Scroller did not receive overscroll event after horizontal scroll.'); + assert_equals(scrolling_div.scrollWidth - scrolling_div.scrollLeft, + scrolling_div.clientWidth); + + overscrolled_x_delta = 0; + overscrolled_y_delta = 0; + + // Do a vertical scroll and wait for overscroll event. + await touchScrollInTarget(300, scrolling_div, 'down'); + await waitFor(() => { return overscrolled_y_delta > 0; }, + 'Scroller did not receive overscroll event after vertical scroll.'); + assert_equals(scrolling_div.scrollHeight - scrolling_div.scrollTop, + scrolling_div.clientHeight); + }, 'Tests that the scrolled element gets overscroll event after fully scrolling by touch.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-window.html b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-window.html new file mode 100644 index 0000000000..ef5ae3daef --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/overscroll-event-fired-to-window.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var window_received_overscroll = false; + +function onOverscroll(event) { + assert_false(event.cancelable); + // overscroll events targetting document are bubbled to the window. + assert_true(event.bubbles); + window_received_overscroll = true; +} +window.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to target_div. + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + // Scroll up on target div and wait for the window to get overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return window_received_overscroll; }, + 'Window did not receive overscroll event after scroll up on target.'); + }, 'Tests that the window gets overscroll event when no element scrolls' + + 'after touch scrolling.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scroll_support.js b/testing/web-platform/tests/dom/events/scrolling/scroll_support.js new file mode 100644 index 0000000000..169393e4c3 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scroll_support.js @@ -0,0 +1,163 @@ +async function waitForScrollendEvent(test, target, timeoutMs = 500) { + return new Promise((resolve, reject) => { + const timeoutCallback = test.step_timeout(() => { + reject(`No Scrollend event received for target ${target}`); + }, timeoutMs); + target.addEventListener('scrollend', (evt) => { + clearTimeout(timeoutCallback); + resolve(evt); + }, { once: true }); + }); +} + +const MAX_FRAME = 700; +const MAX_UNCHANGED_FRAMES = 20; + +// Returns a promise that resolves when the given condition is met or rejects +// after MAX_FRAME animation frames. +// TODO(crbug.com/1400399): deprecate. We should not use frame based waits in +// WPT as frame rates may vary greatly in different testing environments. +function waitFor(condition, error_message = 'Reaches the maximum frames.') { + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for MAX_FRAM frames or until condition + // is met. + if (frames >= MAX_FRAME) + reject(error_message); + else if (condition()) + resolve(); + else + requestAnimationFrame(tick.bind(this, frames + 1)); + } + tick(0); + }); +} + +// TODO(crbug.com/1400446): Test driver should defer sending events until the +// browser is ready. Also the term compositor-commit is misleading as not all +// user-agents use a compositor process. +function waitForCompositorCommit() { + return new Promise((resolve) => { + // rAF twice. + window.requestAnimationFrame(() => { + window.requestAnimationFrame(resolve); + }); + }); +} + +// TODO(crbug.com/1400399): Deprecate as frame rates may vary greatly in +// different test environments. +function waitForAnimationEnd(getValue) { + var last_changed_frame = 0; + var last_position = getValue(); + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for MAX_FRAME or until + // MAX_UNCHANGED_FRAMES with no change have been observed. + if (frames >= MAX_FRAME || frames - last_changed_frame > MAX_UNCHANGED_FRAMES) { + resolve(); + } else { + current_value = getValue(); + if (last_position != current_value) { + last_changed_frame = frames; + last_position = current_value; + } + requestAnimationFrame(tick.bind(this, frames + 1)); + } + } + tick(0); + }) +} + +// Scrolls in target according to move_path with pauses in between +function touchScrollInTargetSequentiallyWithPause(target, move_path, pause_time_in_ms = 100) { + const test_driver_actions = new test_driver.Actions() + .addPointer("pointer1", "touch") + .pointerMove(0, 0, {origin: target}) + .pointerDown(); + + const substeps = 5; + let x = 0; + let y = 0; + // Do each move in 5 steps + for(let move of move_path) { + let step_x = (move.x - x) / substeps; + let step_y = (move.y - y) / substeps; + for(let step = 0; step < substeps; step++) { + x += step_x; + y += step_y; + test_driver_actions.pointerMove(x, y, {origin: target}); + } + test_driver_actions.pause(pause_time_in_ms); + } + + return test_driver_actions.pointerUp().send(); +} + +function touchScrollInTarget(pixels_to_scroll, target, direction, pause_time_in_ms = 100) { + var x_delta = 0; + var y_delta = 0; + const num_movs = 5; + if (direction == "down") { + y_delta = -1 * pixels_to_scroll / num_movs; + } else if (direction == "up") { + y_delta = pixels_to_scroll / num_movs; + } else if (direction == "right") { + x_delta = -1 * pixels_to_scroll / num_movs; + } else if (direction == "left") { + x_delta = pixels_to_scroll / num_movs; + } else { + throw("scroll direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'"); + } + return new test_driver.Actions() + .addPointer("pointer1", "touch") + .pointerMove(0, 0, {origin: target}) + .pointerDown() + .pointerMove(x_delta, y_delta, {origin: target}) + .pointerMove(2 * x_delta, 2 * y_delta, {origin: target}) + .pointerMove(3 * x_delta, 3 * y_delta, {origin: target}) + .pointerMove(4 * x_delta, 4 * y_delta, {origin: target}) + .pointerMove(5 * x_delta, 5 * y_delta, {origin: target}) + .pause(pause_time_in_ms) + .pointerUp() + .send(); +} + +// Trigger fling by doing pointerUp right after pointerMoves. +function touchFlingInTarget(pixels_to_scroll, target, direction) { + touchScrollInTarget(pixels_to_scroll, target, direction, 0 /* pause_time */); +} + +function mouseActionsInTarget(target, origin, delta, pause_time_in_ms = 100) { + return new test_driver.Actions() + .addPointer("pointer1", "mouse") + .pointerMove(origin.x, origin.y, { origin: target }) + .pointerDown() + .pointerMove(origin.x + delta.x, origin.y + delta.y, { origin: target }) + .pointerMove(origin.x + delta.x * 2, origin.y + delta.y * 2, { origin: target }) + .pause(pause_time_in_ms) + .pointerUp() + .send(); +} + +// Returns a promise that resolves when the given condition holds for 10 +// animation frames or rejects if the condition changes to false within 10 +// animation frames. +// TODO(crbug.com/1400399): Deprecate as frame rates may very greatly in +// different test environments. +function conditionHolds(condition, error_message = 'Condition is not true anymore.') { + const MAX_FRAME = 10; + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for 10 frames or until condition is + // violated. + if (frames >= MAX_FRAME) + resolve(); + else if (!condition()) + reject(error_message); + else + requestAnimationFrame(tick.bind(this, frames + 1)); + } + tick(0); + }); +} diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html new file mode 100644 index 0000000000..77bf029ced --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-sequence-of-scrolls.tentative.html @@ -0,0 +1,63 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 500px; + height: 4000px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +const target_div = document.getElementById('targetDiv'); +let scrollend_arrived = false; +let scrollend_event_count = 0; + +function onScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + scrollend_arrived = true; + scrollend_event_count += 1; +} + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to document. + document.addEventListener("scrollend", + t.unreached_func("document got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll down & up & down on target div and wait for the target_div to get scrollend event. + target_div.addEventListener("scrollend", onScrollEnd); + const move_path = [ + { x: 0, y: -300}, // down + { x: 0, y: -100}, // up + { x: 0, y: -400}, // down + { x: 0, y: -200}, // up + ]; + await touchScrollInTargetSequentiallyWithPause(target_div, move_path, 150); + + await waitFor(() => {return scrollend_arrived;}, + 'target_div did not receive scrollend event after sequence of scrolls on target.'); + assert_equals(scrollend_event_count, 1); + }, "Move down, up and down again, receive scrollend event only once"); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-snap.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-snap.html new file mode 100644 index 0000000000..03079ddc6c --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-after-snap.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +div { + position: absolute; +} +#scroller { + width: 500px; + height: 500px; + overflow: scroll; + scroll-snap-type: both mandatory; + border: solid black 5px; +} +#space { + width: 2000px; + height: 2000px; +} +.target { + width: 200px; + height: 200px; + scroll-snap-align: start; + background-color: blue; +} +</style> + +<body style="margin:0" onload=runTests()> + <div id="scroller"> + <div id="space"></div> + <div class="target" style="left: 0px; top: 0px;"></div> + <div class="target" style="left: 80px; top: 80px;"></div> + <div class="target" style="left: 200px; top: 200px;"></div> + </div> +</body> + +<script> +var scroller = document.getElementById("scroller"); +var space = document.getElementById("space"); +const MAX_FRAME_COUNT = 700; +const MAX_UNCHANGED_FRAME = 20; + +function scrollTop() { + return scroller.scrollTop; +} + +var scroll_arrived_after_scroll_end = false; +var scroll_end_arrived = false; +scroller.addEventListener("scroll", () => { + if (scroll_end_arrived) + scroll_arrived_after_scroll_end = true; +}); +scroller.addEventListener("scrollend", () => { + scroll_end_arrived = true; +}); + +function runTests() { + promise_test (async () => { + await waitForCompositorCommit(); + await touchScrollInTarget(100, scroller, 'down'); + // Wait for the scroll snap animation to finish. + await waitForAnimationEnd(scrollTop); + await waitFor(() => { return scroll_end_arrived; }); + // Verify that scroll snap animation has finished before firing scrollend event. + assert_false(scroll_arrived_after_scroll_end); + }, "Tests that scrollend is fired after scroll snap animation completion."); + + promise_test (async () => { + // Reset scroll state. + scroller.scrollTo(0, 0); + await waitForCompositorCommit(); + scroll_end_arrived = false; + scroll_arrived_after_scroll_end = false; + + await touchFlingInTarget(50, scroller, 'down'); + // Wait for the scroll snap animation to finish. + await waitForAnimationEnd(scrollTop); + await waitFor(() => { return scroll_end_arrived; }); + // Verify that scroll snap animation has finished before firing scrollend event. + assert_false(scroll_arrived_after_scroll_end); + }, "Tests that scrollend is fired after fling snap animation completion."); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-programmatic-scroll.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-programmatic-scroll.html new file mode 100644 index 0000000000..c6569e0beb --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-programmatic-scroll.html @@ -0,0 +1,135 @@ +<!DOCTYPE HTML> +<meta name="timeout" content="long"> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +html { + height: 3000px; + width: 3000px; +} +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> +<script> +var element_scrollend_arrived = false; +var document_scrollend_arrived = false; + +function onElementScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + element_scrollend_arrived = true; +} + +function onDocumentScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + document_scrollend_arrived = true; +} + +function callScrollFunction([scrollTarget, scrollFunction, args]) { + scrollTarget[scrollFunction](args); +} + +function runTest() { + let root_element = document.scrollingElement; + let target_div = document.getElementById("targetDiv"); + + promise_test (async (t) => { + await waitForCompositorCommit(); + target_div.addEventListener("scrollend", onElementScrollEnd); + document.addEventListener("scrollend", onDocumentScrollEnd); + + let test_cases = [ + [target_div, 200, 200, [target_div, "scrollTo", { top: 200, left: 200, behavior: "auto" }]], + [target_div, 0, 0, [target_div, "scrollTo", { top: 0, left: 0, behavior: "smooth" }]], + [root_element, 200, 200, [root_element, "scrollTo", { top: 200, left: 200, behavior: "auto" }]], + [root_element, 0, 0, [root_element, "scrollTo", { top: 0, left: 0, behavior: "smooth" }]], + [target_div, 200, 200, [target_div, "scrollBy", { top: 200, left: 200, behavior: "auto" }]], + [target_div, 0, 0, [target_div, "scrollBy", { top: -200, left: -200, behavior: "smooth" }]], + [root_element, 200, 200, [root_element, "scrollBy", { top: 200, left: 200, behavior: "auto" }]], + [root_element, 0, 0, [root_element, "scrollBy", { top: -200, left: -200, behavior: "smooth" }]] + ]; + + for(i = 0; i < test_cases.length; i++) { + let t = test_cases[i]; + let target = t[0]; + let expected_x = t[1]; + let expected_y = t[2]; + let scroll_datas = t[3]; + + callScrollFunction(scroll_datas); + await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + scroll_datas[1] + " did not receive scrollend event."); + if (target == root_element) + assert_false(element_scrollend_arrived); + else + assert_false(document_scrollend_arrived); + assert_equals(target.scrollLeft, expected_x, target.tagName + "." + scroll_datas[1] + " scrollLeft"); + assert_equals(target.scrollTop, expected_y, target.tagName + "." + scroll_datas[1] + " scrollTop"); + + element_scrollend_arrived = false; + document_scrollend_arrived = false; + } + }, "Tests scrollend event for calling scroll functions."); + + promise_test(async (t) => { + await waitForCompositorCommit(); + + let test_cases = [ + [target_div, "scrollTop"], + [target_div, "scrollLeft"], + [root_element, "scrollTop"], + [root_element, "scrollLeft"] + ]; + for (i = 0; i < test_cases.length; i++) { + let t = test_cases[i]; + let target = t[0]; + let attribute = t[1]; + let position = 200; + + target.style.scrollBehavior = "smooth"; + target[attribute] = position; + await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + attribute + " did not receive scrollend event."); + if (target == root_element) + assert_false(element_scrollend_arrived); + else + assert_false(document_scrollend_arrived); + assert_equals(target[attribute], position, target.tagName + "." + attribute + " "); + element_scrollend_arrived = false; + document_scrollend_arrived = false; + + await waitForCompositorCommit(); + target.style.scrollBehavior = "auto"; + target[attribute] = 0; + await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + "." + attribute + " did not receive scrollend event."); + if (target == root_element) + assert_false(element_scrollend_arrived); + else + assert_false(document_scrollend_arrived); + assert_equals(target[attribute], 0, target.tagName + "." + attribute + " "); + element_scrollend_arrived = false; + document_scrollend_arrived = false; + } + }, "Tests scrollend event for changing scroll attributes."); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-scrollIntoView.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-scrollIntoView.html new file mode 100644 index 0000000000..8782b1dfee --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-for-scrollIntoView.html @@ -0,0 +1,124 @@ +<!DOCTYPE HTML> +<meta name="timeout" content="long"> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +html { + height: 3000px; + width: 3000px; +} +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> +<script> +var element_scrollend_arrived = false; +var document_scrollend_arrived = false; + +function onElementScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + element_scrollend_arrived = true; +} + +function onDocumentScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + document_scrollend_arrived = true; +} + +function callScrollFunction([scrollTarget, scrollFunction, args]) { + scrollTarget[scrollFunction](args); +} + +function runTest() { + let root_element = document.scrollingElement; + let target_div = document.getElementById("targetDiv"); + let inner_div = document.getElementById("innerDiv"); + + // Get expected position for root_element scrollIntoView. + root_element.scrollTo(10000, 10000); + let max_root_x = root_element.scrollLeft; + let max_root_y = root_element.scrollTop; + root_element.scrollTo(0, 0); + + target_div.scrollTo(10000, 10000); + let max_element_x = target_div.scrollLeft; + let max_element_y = target_div.scrollTop; + target_div.scrollTo(0, 0); + + promise_test (async (t) => { + await waitForCompositorCommit(); + target_div.addEventListener("scrollend", onElementScrollEnd); + document.addEventListener("scrollend", onDocumentScrollEnd); + + let test_cases = [ + [target_div, max_element_x, max_element_y, [inner_div, "scrollIntoView", { inline: "end", block: "end", behavior: "auto" }]], + [target_div, 0, 0, [inner_div, "scrollIntoView", { inline: "start", block: "start", behavior: "smooth" }]], + [root_element, max_root_x, max_root_y, [root_element, "scrollIntoView", { inline: "end", block: "end", behavior: "smooth" }]], + [root_element, 0, 0, [root_element, "scrollIntoView", { inline: "start", block: "start", behavior: "smooth" }]] + ]; + + for(i = 0; i < test_cases.length; i++) { + let t = test_cases[i]; + let target = t[0]; + let expected_x = t[1]; + let expected_y = t[2]; + let scroll_datas = t[3]; + + callScrollFunction(scroll_datas); + await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, target.tagName + ".scrollIntoView did not receive scrollend event."); + if (target == root_element) + assert_false(element_scrollend_arrived); + else + assert_false(document_scrollend_arrived); + assert_equals(target.scrollLeft, expected_x, target.tagName + ".scrollIntoView scrollLeft"); + assert_equals(target.scrollTop, expected_y, target.tagName + ".scrollIntoView scrollTop"); + + element_scrollend_arrived = false; + document_scrollend_arrived = false; + } + }, "Tests scrollend event for scrollIntoView."); + + promise_test(async (t) => { + document.body.removeChild(target_div); + let out_div = document.createElement("div"); + out_div.style = "width: 100px; height:100px; overflow:scroll; scroll-behavior:smooth;"; + out_div.appendChild(target_div); + document.body.appendChild(out_div); + await waitForCompositorCommit(); + + element_scrollend_arrived = false; + document_scrollend_arrived = false; + inner_div.scrollIntoView({ inline: "end", block: "end", behavior: "auto" }); + await waitFor(() => { return element_scrollend_arrived || document_scrollend_arrived; }, "Nested scrollIntoView did not receive scrollend event."); + assert_equals(root_element.scrollLeft, 0, "Nested scrollIntoView root_element scrollLeft"); + assert_equals(root_element.scrollTop, 0, "Nested scrollIntoView root_element scrollTop"); + assert_equals(out_div.scrollLeft, 100, "Nested scrollIntoView out_div scrollLeft"); + assert_equals(out_div.scrollTop, 100, "Nested scrollIntoView out_div scrollTop"); + assert_equals(target_div.scrollLeft, max_element_x, "Nested scrollIntoView target_div scrollLeft"); + assert_equals(target_div.scrollTop, max_element_y, "Nested scrollIntoView target_div scrollTop"); + assert_false(document_scrollend_arrived); + }, "Tests scrollend event for nested scrollIntoView."); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-document.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-document.html new file mode 100644 index 0000000000..3090455388 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-document.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + vertical_scrollend_arrived = true; +} + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to target_div. + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll left on target div and wait for the doc to get scrollend event. + document.addEventListener("scrollend", onHorizontalScrollEnd); + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Document did not receive scrollend event after scroll left on target.'); + assert_equals(target_div.scrollLeft, 0); + document.removeEventListener("scrollend", onHorizontalScrollEnd); + + // Scroll up on target div and wait for the doc to get scrollend event. + document.addEventListener("scrollend", onVerticalScrollEnd); + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return vertical_scrollend_arrived; }, + 'Document did not receive scrollend event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the document gets scrollend event when no element scrolls by ' + + 'touch.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html new file mode 100644 index 0000000000..acad168e56 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html @@ -0,0 +1,102 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#overscrollXDiv { + width: 600px; + height: 600px; + overflow: scroll; + overscroll-behavior-x: contain; +} +#overscrollYDiv { + width: 500px; + height: 500px; + overflow: scroll; + overscroll-behavior-y: none; +} +#targetDiv { + width: 400px; + height: 400px; + overflow: scroll; +} +.content { + width:800px; + height:800px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="overscrollXDiv"> + <div class=content> + <div id="overscrollYDiv"> + <div class=content> + <div id="targetDiv"> + <div class="content"> + </div> + </div> + </div> + </div> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + vertical_scrollend_arrived = true; +} +// Test that both "onscrollend" and addEventListener("scrollend"... work. +document.getElementById('overscrollXDiv').onscrollend = onHorizontalScrollEnd; +document.getElementById('overscrollYDiv'). + addEventListener("scrollend", onVerticalScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to document or target_div. + document.addEventListener("scrollend", + t.unreached_func("Document got unexpected scrollend event.")); + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll left on target div and wait for the element with overscroll-x to + // get scrollend event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Expected element did not receive scrollend event after scroll left ' + + 'on target.'); + assert_equals(target_div.scrollLeft, 0); + + let touchEndPromise = new Promise((resolve) => { + target_div.addEventListener("touchend", resolve); + }); + await touchScrollInTarget(300, target_div, 'up'); + + // The scrollend event should never be fired before the gesture has completed. + await touchEndPromise; + + // Ensure we wait at least a tick after the touch end. + await waitForCompositorCommit(); + + // We should not trigger a scrollend event for a scroll that did not change + // the scroll position. + assert_equals(vertical_scrollend_arrived, false); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the last element in the cut scroll chain gets scrollend ' + + 'event when no element scrolls by touch.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html new file mode 100644 index 0000000000..7343396942 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#scrollableDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="scrollableDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var scrolling_div = document.getElementById('scrollableDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + vertical_scrollend_arrived = true; +} +scrolling_div.addEventListener("scrollend", onHorizontalScrollEnd); +scrolling_div.addEventListener("scrollend", onVerticalScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to document. + document.addEventListener("scrollend", + t.unreached_func("Document got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Do a horizontal scroll and wait for scrollend event. + await touchScrollInTarget(300, scrolling_div, 'right'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Scroller did not receive scrollend event after horizontal scroll.'); + assert_equals(scrolling_div.scrollWidth - scrolling_div.scrollLeft, + scrolling_div.clientWidth); + + // Do a vertical scroll and wait for scrollend event. + await touchScrollInTarget(300, scrolling_div, 'down'); + await waitFor(() => { return vertical_scrollend_arrived; }, + 'Scroller did not receive scrollend event after vertical scroll.'); + assert_equals(scrolling_div.scrollHeight - scrolling_div.scrollTop, + scrolling_div.clientHeight); + }, 'Tests that the scrolled element gets scrollend event at the end of touch scrolling.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-window.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-window.html new file mode 100644 index 0000000000..ef72f56d2b --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-fired-to-window.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var scrollend_arrived = false; +function onScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events targetting document are bubbled to the window. + assert_true(event.bubbles); + scrollend_arrived = true; +} +window.addEventListener("scrollend", onScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to target_div. + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll up on target div and wait for the doc to get scrollend event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return scrollend_arrived; }, + 'Window did not receive scrollend event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the window gets scrollend event when no element scrolls ' + + 'after touch scrolling.'); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-for-user-scroll.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-for-user-scroll.html new file mode 100644 index 0000000000..5146c5f719 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-for-user-scroll.html @@ -0,0 +1,199 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> + #targetDiv { + width: 200px; + height: 200px; + overflow: scroll; + } + + #innerDiv { + width: 400px; + height: 400px; + } +</style> +</head> +<body style="margin:0" onload=runTest()> + <div id="targetDiv"> + <div id="innerDiv"> + </div> + </div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); + +async function resetTargetScrollState(test) { + if (target_div.scrollTop != 0 || target_div.scrollLeft != 0) { + target_div.scrollTop = 0; + target_div.scrollLeft = 0; + return waitForScrollendEvent(test, target_div); + } +} + +async function verifyScrollStopped(test) { + const unscaled_pause_time_in_ms = 100; + const x = target_div.scrollLeft; + const y = target_div.scrollTop; + return new Promise(resolve => { + test.step_timeout(() => { + assert_equals(x, target_div.scrollLeft); + assert_equals(y, target_div.scrollTop); + resolve(); + }, unscaled_pause_time_in_ms); + }); +} + +async function verifyNoScrollendOnDocument(test) { + const callback = + test.unreached_func("window got unexpected scrollend event."); + window.addEventListener('scrollend', callback); +} + +async function createScrollendPromise(test) { + return waitForScrollendEvent(test, target_div).then(evt => { + assert_false(evt.cancelable, 'Event is not cancelable'); + assert_false(evt.bubbles, 'Event targeting element does not bubble'); + }); +} + +function runTest() { + promise_test(async (t) => { + // Skip the test on a Mac as they do not support touch screens. + const isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0; + if (isMac) + return; + + await resetTargetScrollState(t); + await waitForCompositorCommit(); + + const targetScrollendPromise = createScrollendPromise(t); + verifyNoScrollendOnDocument(t); + + // Perform a touch drag on target div and wait for target_div to get + // a scrollend event. + await new test_driver.Actions() + .addPointer('TestPointer', 'touch') + .pointerMove(0, 0, {origin: target_div}) // 0, 0 is center of element. + .pointerDown() + .addTick() + .pointerMove(0, -40, {origin: target_div}) // Drag up to move down. + .addTick() + .pause(200) // Prevent inertial scroll. + .pointerUp() + .send(); + + await targetScrollendPromise; + + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t); + }, 'Tests that the target_div gets scrollend event when touch dragging.'); + + promise_test(async (t) => { + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = target_div.offsetWidth - target_div.clientWidth; + if (scrollbar_width == 0) + return; + + await resetTargetScrollState(t); + await waitForCompositorCommit(); + + const targetScrollendPromise = createScrollendPromise(t); + verifyNoScrollendOnDocument(t); + + const bounds = target_div.getBoundingClientRect(); + const x = bounds.right - scrollbar_width / 2; + const y = bounds.bottom - 20; + await new test_driver.Actions() + .addPointer('TestPointer', 'mouse') + .pointerMove(x, y, {origin: 'viewport'}) + .pointerDown() + .addTick() + .pointerUp() + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t); + }, 'Tests that the target_div gets scrollend event when clicking ' + + 'scrollbar.'); + + // Same issue as previous test. + promise_test(async (t) => { + // Skip test on platforms that do not have a visible scrollbar (e.g. + // overlay scrollbar). + const scrollbar_width = target_div.offsetWidth - target_div.clientWidth; + if (scrollbar_width == 0) + return; + + resetTargetScrollState(t); + const targetScrollendPromise = createScrollendPromise(t); + verifyNoScrollendOnDocument(t); + + const bounds = target_div.getBoundingClientRect(); + const x = bounds.right - scrollbar_width / 2; + const y = bounds.top + 30; + const dy = 30; + await new test_driver.Actions() + .addPointer('TestPointer', 'mouse') + .pointerMove(x, y, { origin: 'viewport' }) + .pointerDown() + .pointerMove(x, y + dy, { origin: 'viewport' }) + .addTick() + .pointerUp() + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t); + }, 'Tests that the target_div gets scrollend event when dragging the ' + + 'scrollbar thumb.'); + + promise_test(async (t) => { + resetTargetScrollState(t); + const targetScrollendPromise = createScrollendPromise(t); + verifyNoScrollendOnDocument(t); + + const x = 0; + const y = 0; + const dx = 0; + const dy = 40; + const duration_ms = 10; + await new test_driver.Actions() + .scroll(x, y, dx, dy, { origin: target_div }, duration_ms) + .send(); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t); + }, 'Tests that the target_div gets scrollend event when mouse wheel ' + + 'scrolling.'); + + promise_test(async (t) => { + await resetTargetScrollState(t); + await waitForCompositorCommit(); + + verifyNoScrollendOnDocument(t); + const targetScrollendPromise = createScrollendPromise(t); + + target_div.focus(); + window.test_driver.send_keys(target_div, '\ue015'); + + await targetScrollendPromise; + assert_true(target_div.scrollTop > 0); + await verifyScrollStopped(t); + }, 'Tests that the target_div gets scrollend event when sending DOWN key ' + + 'to the target.'); +} + +</script> +</html> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-handler-content-attributes.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-handler-content-attributes.html new file mode 100644 index 0000000000..47f563c39b --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-handler-content-attributes.html @@ -0,0 +1,108 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +html, body { + margin: 0 +} + +body { + height: 3000px; + width: 3000px; +} + +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body onload=runTest() onscrollend="failOnScrollEnd(event)"> +<div id="targetDiv" onscrollend="onElementScrollEnd(event)"> + <div id="innerDiv"> + </div> +</div> +</body> +<script> +let element_scrollend_arrived = false; + +function onElementScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + element_scrollend_arrived = true; +} + +function failOnScrollEnd(event) { + assert_true(false, "Scrollend should not be called on: " + event.target); +} + +function runTest() { + let target_div = document.getElementById("targetDiv"); + + promise_test (async (t) => { + await waitForCompositorCommit(); + + target_div.scrollTo({top: 200, left: 200}); + await waitFor(() => { return element_scrollend_arrived; }, + target_div.tagName + " did not receive scrollend event."); + assert_equals(target_div.scrollLeft, 200, target_div.tagName + " scrollLeft"); + assert_equals(target_div.scrollTop, 200, target_div.tagName + " scrollTop"); + }, "Tests scrollend event is handled by event handler content attribute."); + + promise_test (async (t) => { + await waitForCompositorCommit(); + + document.scrollingElement.scrollTo({top: 200, left: 200}); + // The document body onscrollend event handler content attribute will fail + // here, if it is fired. + await waitForCompositorCommit(); + assert_equals(document.scrollingElement.scrollLeft, 200, + "Document scrolled on horizontal axis"); + assert_equals(document.scrollingElement.scrollTop, 200, + "Document scrolled on vertical axis"); + }, "Tests scrollend event is not fired to document body event handler content attribute."); + + promise_test (async (t) => { + await waitForCompositorCommit(); + + // Reset the scroll position. + document.scrollingElement.scrollTo({top: 0, left: 0}); + + let scrollend_event = new Promise(resolve => document.onscrollend = resolve); + document.scrollingElement.scrollTo({top: 200, left: 200}); + await scrollend_event; + + assert_equals(document.scrollingElement.scrollTop, 200, + "Document scrolled on horizontal axis"); + assert_equals(document.scrollingElement.scrollLeft, 200, + "Document scrolled on vertical axis"); + }, "Tests scrollend event is fired to document event handler property"); + + promise_test (async (t) => { + await waitForCompositorCommit(); + + // Reset the scroll position. + target_div.scrollTo({top: 0, left: 0}); + + let scrollend_event = new Promise(resolve => target_div.onscrollend = resolve); + target_div.scrollTo({top: 200, left: 200}); + await scrollend_event; + + assert_equals(target_div.scrollLeft, 200, + target_div.tagName + " scrolled on horizontal axis"); + assert_equals(target_div.scrollLeft, 200, + target_div.tagName + " scrolled on vertical axis"); + }, "Tests scrollend event is fired to element event handler property"); +} +</script> diff --git a/testing/web-platform/tests/dom/events/scrolling/scrollend-event-not-fired-after-removing-scroller.tentative.html b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-not-fired-after-removing-scroller.tentative.html new file mode 100644 index 0000000000..95447fbd12 --- /dev/null +++ b/testing/web-platform/tests/dom/events/scrolling/scrollend-event-not-fired-after-removing-scroller.tentative.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#rootDiv { + width: 500px; + height: 500px; +} + +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 500px; + height: 4000px; +} +</style> + +<body style="margin:0" onload=runTest()> +</body> + +<script> +let scrollend_arrived = false; + +async function setupHtmlAndScrollAndRemoveElement(element_to_remove_id) { + document.body.innerHTML=` + <div id="rootDiv"> + <div id="targetDiv"> + <div id="innerDiv"> + </div> + </div> + </div> + `; + await waitForCompositorCommit(); + + const target_div = document.getElementById('targetDiv'); + const element_to_remove = document.getElementById(element_to_remove_id); + let reached_half_scroll = false; + scrollend_arrived = false; + + target_div.addEventListener("scrollend", () => { + scrollend_arrived = true; + }); + + target_div.onscroll = () => { + // Remove the element after reached half of the scroll offset, + if(target_div.scrollTop >= 1000) { + reached_half_scroll = true; + element_to_remove.remove(); + } + }; + + target_div.scrollTo({top:2000, left:0, behavior:"smooth"}); + await waitFor(() => {return reached_half_scroll; }, + "target_div never reached scroll offset of 1000"); + await waitForCompositorCommit(); +} + +function runTest() { + promise_test (async (t) => { + await setupHtmlAndScrollAndRemoveElement("rootDiv"); + await conditionHolds(() => { return !scrollend_arrived; }); + }, "No scrollend is received after removing parent div"); + + promise_test (async (t) => { + await setupHtmlAndScrollAndRemoveElement("targetDiv"); + await conditionHolds(() => { return !scrollend_arrived; }); + }, "No scrollend is received after removing scrolling element"); + + promise_test (async (t) => { + await setupHtmlAndScrollAndRemoveElement("innerDiv"); + await waitFor(() => { return scrollend_arrived; }, + 'target_div did not receive scrollend event after vertical scroll.'); + }, "scrollend is received after removing descendant div"); +} +</script> diff --git a/testing/web-platform/tests/dom/events/shadow-relatedTarget.html b/testing/web-platform/tests/dom/events/shadow-relatedTarget.html new file mode 100644 index 0000000000..713555b7d8 --- /dev/null +++ b/testing/web-platform/tests/dom/events/shadow-relatedTarget.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- + This test is adopted from Olli Pettay's test case at + http://mozilla.pettay.fi/shadow_focus.html +--> +<div id="host"></div> +<input id="lightInput"> +<script> +const root = host.attachShadow({ mode: "closed" }); +root.innerHTML = "<input id='shadowInput'>"; + +async_test((test) => { + root.getElementById("shadowInput").focus(); + window.addEventListener("focus", test.step_func_done((e) => { + assert_equals(e.relatedTarget, host); + }, "relatedTarget should be pointing to shadow host."), true); + lightInput.focus(); +}, "relatedTarget should not leak at capturing phase, at window object."); + +async_test((test) => { + root.getElementById("shadowInput").focus(); + lightInput.addEventListener("focus", test.step_func_done((e) => { + assert_equals(e.relatedTarget, host); + }, "relatedTarget should be pointing to shadow host."), true); + lightInput.focus(); +}, "relatedTarget should not leak at target."); + +</script> diff --git a/testing/web-platform/tests/dom/events/webkit-animation-end-event.html b/testing/web-platform/tests/dom/events/webkit-animation-end-event.html new file mode 100644 index 0000000000..4186f6b7a9 --- /dev/null +++ b/testing/web-platform/tests/dom/events/webkit-animation-end-event.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Prefixed CSS Animation end events</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="resources/prefixed-animation-event-tests.js"></script> +<script> +'use strict'; + +runAnimationEventTests({ + unprefixedType: 'animationend', + prefixedType: 'webkitAnimationEnd', + animationCssStyle: '1ms', +}); +</script> diff --git a/testing/web-platform/tests/dom/events/webkit-animation-iteration-event.html b/testing/web-platform/tests/dom/events/webkit-animation-iteration-event.html new file mode 100644 index 0000000000..fb251972a3 --- /dev/null +++ b/testing/web-platform/tests/dom/events/webkit-animation-iteration-event.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Prefixed CSS Animation iteration events</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="resources/prefixed-animation-event-tests.js"></script> +<script> +'use strict'; + +runAnimationEventTests({ + unprefixedType: 'animationiteration', + prefixedType: 'webkitAnimationIteration', + // Use a long duration to avoid missing the animation due to slow machines, + // but set a negative delay so that the iteration boundary happens shortly + // after the animation starts. + animationCssStyle: '100s -99.9s 2', +}); +</script> diff --git a/testing/web-platform/tests/dom/events/webkit-animation-start-event.html b/testing/web-platform/tests/dom/events/webkit-animation-start-event.html new file mode 100644 index 0000000000..ad1036644a --- /dev/null +++ b/testing/web-platform/tests/dom/events/webkit-animation-start-event.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Prefixed CSS Animation start events</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="resources/prefixed-animation-event-tests.js"></script> +<script> +'use strict'; + +runAnimationEventTests({ + unprefixedType: 'animationstart', + prefixedType: 'webkitAnimationStart', + animationCssStyle: '1ms', +}); +</script> diff --git a/testing/web-platform/tests/dom/events/webkit-transition-end-event.html b/testing/web-platform/tests/dom/events/webkit-transition-end-event.html new file mode 100644 index 0000000000..2741824e30 --- /dev/null +++ b/testing/web-platform/tests/dom/events/webkit-transition-end-event.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Prefixed CSS Transition End event</title> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="resources/prefixed-animation-event-tests.js"></script> +<script> +'use strict'; + +runAnimationEventTests({ + isTransition: true, + unprefixedType: 'transitionend', + prefixedType: 'webkitTransitionEnd', + animationCssStyle: '1ms', +}); +</script> diff --git a/testing/web-platform/tests/dom/historical.html b/testing/web-platform/tests/dom/historical.html new file mode 100644 index 0000000000..1bc209ec0e --- /dev/null +++ b/testing/web-platform/tests/dom/historical.html @@ -0,0 +1,222 @@ +<!DOCTYPE html> +<title>Historical DOM features must be removed</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +function isInterfaceRemoved(name) { + test(function() { + assert_false(name in window) + assert_equals(window[name], undefined) + }, "Historical DOM features must be removed: " + name) +} +var removedInterfaces = [ + "DOMConfiguration", + "DOMCursor", + "DOMError", + "DOMErrorHandler", + "DOMImplementationList", + "DOMImplementationSource", + "DOMLocator", + "DOMObject", + "DOMRequest", + "DOMSettableTokenList", + "DOMUserData", + "Entity", + "EntityReference", + "EventException", // DOM Events + "NameList", + "Notation", + "TypeInfo", + "UserDataHandler", + "RangeException", // DOM Range + "SVGPathSegList" +] +removedInterfaces.forEach(isInterfaceRemoved) + +function isRemovedFromDocument(name) { + test(function() { + var doc = document.implementation.createDocument(null,null,null) + assert_false(name in document) + assert_equals(document[name], undefined) + assert_false(name in doc) + assert_equals(doc[name], undefined) + }, "Historical DOM features must be removed: " + name) +} +var documentRemoved = [ + "createEntityReference", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "strictErrorChecking", + "domConfig", + "normalizeDocument", + "renameNode", + "defaultCharset", + "height", + "width", + // https://github.com/whatwg/html/commit/a64aea7fdb221bba027d95dc3cabda09e0b3e5dc + "commands", + // https://github.com/whatwg/html/commit/797b4d273955a0fe3cc2e2d0ca5d578f37c0f126 + "cssElementMap", + // https://github.com/whatwg/html/commit/e236f46820b93d6fe2e2caae0363331075c6c4fb + "async", + // https://github.com/whatwg/dom/pull/815 + "origin", +] +documentRemoved.forEach(isRemovedFromDocument) + +test(function() { + // https://github.com/whatwg/html/commit/e236f46820b93d6fe2e2caae0363331075c6c4fb + assert_false("load" in document); + assert_equals(document["load"], undefined) +}, "document.load"); + +test(function() { + // https://github.com/whatwg/html/commit/523f7a8773d2ab8a1eb0da6510651e8c5d2a7531 + var doc = document.implementation.createDocument(null, null, null); + assert_false("load" in doc); + assert_equals(doc["load"], undefined) +}, "XMLDocument.load"); + +test(function() { + assert_false("getFeature" in document.implementation) + assert_equals(document.implementation["getFeature"], undefined) +}, "DOMImplementation.getFeature() must be removed.") + +function isRemovedFromElement(name) { + test(function() { + var ele = document.createElementNS("test", "test") + assert_false(name in document.body) + assert_equals(document.body[name], undefined) + assert_false(name in ele) + assert_equals(ele[name], undefined) + }, "Historical DOM features must be removed: " + name) +} +var elementRemoved = [ + "schemaTypeInfo", + "setIdAttribute", + "setIdAttributeNS", + "setIdAttributeNode" +] +elementRemoved.forEach(isRemovedFromElement) + +function isRemovedFromAttr(name) { + test(function() { + var attr = document.createAttribute("test") + assert_false(name in attr) + assert_equals(attr[name], undefined) + }, "Attr member must be removed: " + name) +} +var attrRemoved = [ + "schemaTypeInfo", + "isId" +] +attrRemoved.forEach(isRemovedFromAttr) + +function isRemovedFromDoctype(name) { + test(function() { + var doctype = document.implementation.createDocumentType("test", "", "") + assert_false(name in doctype) + assert_equals(doctype[name], undefined) + }, "DocumentType member must be removed: " + name) +} +var doctypeRemoved = [ + "entities", + "notations", + "internalSubset" +] +doctypeRemoved.forEach(isRemovedFromDoctype) + +function isRemovedFromText(name) { + test(function() { + var text = document.createTextNode("test") + assert_false(name in text) + assert_equals(text[name], undefined) + }, "Text member must be removed: " + name) +} +var textRemoved = [ + "isElementContentWhitespace", + "replaceWholeText" +] +textRemoved.forEach(isRemovedFromText) + +function isRemovedFromNode(name) { + test(function() { + var doc = document.implementation.createDocument(null,null,null) + var doctype = document.implementation.createDocumentType("test", "", "") + var text = document.createTextNode("test") + assert_false(name in doc) + assert_equals(doc[name], undefined) + assert_false(name in doctype) + assert_equals(doctype[name], undefined) + assert_false(name in text) + assert_equals(text[name], undefined) + }, "Node member must be removed: " + name) +} +var nodeRemoved = [ + "hasAttributes", + "attributes", + "namespaceURI", + "prefix", + "localName", + "isSupported", + "getFeature", + "getUserData", + "setUserData", + "rootNode", +] +nodeRemoved.forEach(isRemovedFromNode) + +function isRemovedFromWindow(name) { + test(function() { + assert_false(name in window) + assert_equals(window[name], undefined) + }, "Window member must be removed: " + name) +} +var windowRemoved = [ + "attachEvent", + "content", + "sidebar", +] +windowRemoved.forEach(isRemovedFromWindow) + +function isRemovedFromEvent(name) { + test(() => { + assert_false(name in Event) + assert_equals(Event[name], undefined) + }, "Event should not have this constant: " + name) +} +var EventRemoved = [ + "MOUSEDOWN", + "MOUSEUP", + "MOUSEOVER", + "MOUSEOUT", + "MOUSEMOVE", + "MOUSEDRAG", + "CLICK", + "DBLCLICK", + "KEYDOWN", + "KEYUP", + "KEYPRESS", + "DRAGDROP", + "FOCUS", + "BLUR", + "SELECT", + "CHANGE" +] +EventRemoved.forEach(isRemovedFromEvent) + +var EventPrototypeRemoved = [ + "getPreventDefault", + "path" +] +EventPrototypeRemoved.forEach(name => { + test(() => { + assert_false(name in Event.prototype) + assert_equals(Event.prototype[name], undefined) + assert_false(name in new Event("test")) + assert_equals((new Event("test"))[name], undefined) + }, "Event.prototype should not have this property: " + name) +}) +</script> diff --git a/testing/web-platform/tests/dom/idlharness-shadowrealm.window.js b/testing/web-platform/tests/dom/idlharness-shadowrealm.window.js new file mode 100644 index 0000000000..cb03c07c9b --- /dev/null +++ b/testing/web-platform/tests/dom/idlharness-shadowrealm.window.js @@ -0,0 +1,2 @@ +// META: script=/resources/idlharness-shadowrealm.js +idl_test_shadowrealm(["dom"], ["html"]); diff --git a/testing/web-platform/tests/dom/idlharness.any.js b/testing/web-platform/tests/dom/idlharness.any.js new file mode 100644 index 0000000000..26da3ab3bf --- /dev/null +++ b/testing/web-platform/tests/dom/idlharness.any.js @@ -0,0 +1,25 @@ +// META: global=worker +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: timeout=long + +// Note: This test doesn't cover the Window context, see idlharness.window.js +// for that coverage and why it can't be merged into this test. + +'use strict'; + +idl_test( + ['dom'], + ['html'], + idl_array => { + idl_array.add_objects({ + EventTarget: ['new EventTarget()'], + Event: ['new Event("foo")'], + CustomEvent: ['new CustomEvent("foo")'], + AbortController: ['new AbortController()'], + AbortSignal: ['new AbortController().signal'], + }); + } +); + +done(); diff --git a/testing/web-platform/tests/dom/idlharness.window.js b/testing/web-platform/tests/dom/idlharness.window.js new file mode 100644 index 0000000000..2c7bfd727e --- /dev/null +++ b/testing/web-platform/tests/dom/idlharness.window.js @@ -0,0 +1,52 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js +// META: script=/common/subset-tests-by-key.js +// META: variant=?include=Node +// META: variant=?exclude=Node +// META: timeout=long + +// Note: This isn't merged into idlharness.any.js because of the use of variants, +// i.e., include=Node wouldn't make sense for workers. + +'use strict'; + +idl_test( + ['dom', 'fullscreen'], + ['html'], + idl_array => { + self.xmlDoc = document.implementation.createDocument(null, '', null); + self.detachedRange = document.createRange(); + detachedRange.detach(); + self.element = xmlDoc.createElementNS(null, 'test'); + element.setAttribute('bar', 'baz'); + + idl_array.add_objects({ + EventTarget: ['new EventTarget()'], + Event: ['document.createEvent("Event")', 'new Event("foo")'], + CustomEvent: ['new CustomEvent("foo")'], + AbortController: ['new AbortController()'], + AbortSignal: ['new AbortController().signal'], + Document: ['new Document()'], + XMLDocument: ['xmlDoc'], + DOMImplementation: ['document.implementation'], + DocumentFragment: ['document.createDocumentFragment()'], + DocumentType: ['document.doctype'], + Element: ['element'], + Attr: ['document.querySelector("[id]").attributes[0]'], + Text: ['document.createTextNode("abc")'], + ProcessingInstruction: ['xmlDoc.createProcessingInstruction("abc", "def")'], + Comment: ['document.createComment("abc")'], + Range: ['document.createRange()', 'detachedRange'], + NodeIterator: ['document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)'], + TreeWalker: ['document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)'], + NodeList: ['document.querySelectorAll("script")'], + HTMLCollection: ['document.body.children'], + DOMTokenList: ['document.body.classList'], + XPathEvaluator: ['new XPathEvaluator()'], + XPathExpression: ['document.createExpression("//*")'], + XPathNSResolver: ['document.createNSResolver(document.body)'], + XPathResult: ['document.evaluate("//*", document.body)'], + XSLTProcessor: ['new XSLTProcessor()'], + }); + } +); diff --git a/testing/web-platform/tests/dom/interface-objects.html b/testing/web-platform/tests/dom/interface-objects.html new file mode 100644 index 0000000000..936d63517e --- /dev/null +++ b/testing/web-platform/tests/dom/interface-objects.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<title>Interfaces</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testInterfaceDeletable(iface) { + test(function() { + assert_true(!!window[iface], "Interface should exist.") + assert_true(delete window[iface], "The delete operator should return true.") + assert_equals(window[iface], undefined, "Interface should be gone.") + }, "Should be able to delete " + iface + ".") +} +var interfaces = [ + "Event", + "CustomEvent", + "EventTarget", + "AbortController", + "AbortSignal", + "Node", + "Document", + "DOMImplementation", + "DocumentFragment", + "ProcessingInstruction", + "DocumentType", + "Element", + "Attr", + "CharacterData", + "Text", + "Comment", + "NodeIterator", + "TreeWalker", + "NodeFilter", + "NodeList", + "HTMLCollection", + "DOMTokenList" +]; +test(function() { + for (var p in window) { + interfaces.forEach(function(i) { + assert_not_equals(p, i) + }) + } +}, "Interface objects properties should not be Enumerable") +interfaces.forEach(testInterfaceDeletable); +</script> diff --git a/testing/web-platform/tests/dom/lists/DOMTokenList-Iterable.html b/testing/web-platform/tests/dom/lists/DOMTokenList-Iterable.html new file mode 100644 index 0000000000..4cf84b12a2 --- /dev/null +++ b/testing/web-platform/tests/dom/lists/DOMTokenList-Iterable.html @@ -0,0 +1,34 @@ +<!doctype html> +<meta charset="utf-8"> +<title>DOMTokenList Iterable Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<span class="foo Foo foo "></span> +<script> + var elementClasses; + setup(function() { + elementClasses = document.querySelector("span").classList; + }) + test(function() { + assert_true('length' in elementClasses); + }, 'DOMTokenList has length method.'); + test(function() { + assert_true('values' in elementClasses); + }, 'DOMTokenList has values method.'); + test(function() { + assert_true('entries' in elementClasses); + }, 'DOMTokenList has entries method.'); + test(function() { + assert_true('forEach' in elementClasses); + }, 'DOMTokenList has forEach method.'); + test(function() { + assert_true(Symbol.iterator in elementClasses); + }, 'DOMTokenList has Symbol.iterator.'); + test(function() { + var classList = []; + for (var className of elementClasses){ + classList.push(className); + } + assert_array_equals(classList, ['foo', 'Foo']); + }, 'DOMTokenList is iterable via for-of loop.'); +</script> diff --git a/testing/web-platform/tests/dom/lists/DOMTokenList-coverage-for-attributes.html b/testing/web-platform/tests/dom/lists/DOMTokenList-coverage-for-attributes.html new file mode 100644 index 0000000000..e5f060b8ac --- /dev/null +++ b/testing/web-platform/tests/dom/lists/DOMTokenList-coverage-for-attributes.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DOMTokenList coverage for attributes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +"use strict"; + +var pairs = [ + // Defined in DOM + {attr: "classList", sup: ["anyElement"]}, + // Defined in HTML except for a which is also SVG + {attr: "relList", sup: ["a", "area", "link"]}, + // Defined in HTML + {attr: "htmlFor", sup: ["output"]}, + {attr: "sandbox", sup: ["iframe"]}, + {attr: "sizes", sup: ["link"]} +]; +var namespaces = [ + "http://www.w3.org/1999/xhtml", + "http://www.w3.org/2000/svg", + "http://www.w3.org/1998/Math/MathML", + "http://example.com/", + "" +]; + +var elements = ["a", "area", "link", "iframe", "output", "td", "th"]; +function testAttr(pair, new_el){ + return (pair.attr === "classList" || + (pair.attr === "relList" && new_el.localName === "a" && + new_el.namespaceURI === "http://www.w3.org/2000/svg") || + (new_el.namespaceURI === "http://www.w3.org/1999/xhtml" && + pair.sup.indexOf(new_el.localName) != -1)); +} + +pairs.forEach(function(pair) { + namespaces.forEach(function(ns) { + elements.forEach(function(el) { + var new_el = document.createElementNS(ns, el); + if (testAttr(pair, new_el)) { + test(function() { + assert_class_string(new_el[pair.attr], "DOMTokenList"); + }, new_el.localName + "." + pair.attr + " in " + new_el.namespaceURI + " namespace should be DOMTokenList."); + } + else { + test(function() { + assert_equals(new_el[pair.attr], undefined); + }, new_el.localName + "." + pair.attr + " in " + new_el.namespaceURI + " namespace should be undefined."); + } + }); + }); +}); + +</script> diff --git a/testing/web-platform/tests/dom/lists/DOMTokenList-iteration.html b/testing/web-platform/tests/dom/lists/DOMTokenList-iteration.html new file mode 100644 index 0000000000..f713ad4aa0 --- /dev/null +++ b/testing/web-platform/tests/dom/lists/DOMTokenList-iteration.html @@ -0,0 +1,71 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMTokenList iteration: keys, values, etc.</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<span class=" a a b "></span> +<script> + test(() => { + var list = document.querySelector("span").classList; + assert_array_equals([...list], ["a", "b"]); + }, "classList"); + + test(() => { + var keys = document.querySelector("span").classList.keys(); + assert_false(keys instanceof Array, "must not be Array"); + keys = [...keys]; + assert_array_equals(keys, [0, 1]); + }, "classList.keys"); + + test(() => { + var values = document.querySelector("span").classList.values(); + assert_false(values instanceof Array, "must not be Array"); + values = [...values]; + assert_array_equals(values, ["a", "b"]); + }, "classList.values"); + + test(() => { + var entries = document.querySelector("span").classList.entries(); + assert_false(entries instanceof Array, "must not be Array"); + entries = [...entries]; + var keys = [...document.querySelector("span").classList.keys()]; + var values = [...document.querySelector("span").classList.values()]; + assert_equals(entries.length, keys.length, "entries.length == keys.length"); + assert_equals(entries.length, values.length, + "entries.length == values.length"); + for (var i = 0; i < entries.length; ++i) { + assert_array_equals(entries[i], [keys[i], values[i]], + "entries[" + i + "]"); + } + }, "classList.entries"); + + test(() => { + var list = document.querySelector("span").classList; + var values = [...list.values()]; + var keys = [...list.keys()]; + var entries = [...list.entries()]; + + var cur = 0; + var thisObj = {}; + list.forEach(function(value, key, listObj) { + assert_equals(listObj, list, "Entry " + cur + " listObj"); + assert_equals(this, thisObj, "Entry " + cur + " this"); + assert_equals(value, values[cur], "Entry " + cur + " value"); + assert_equals(key, keys[cur], "Entry " + cur + " key"); + cur++; + }, thisObj); + assert_equals(cur, entries.length, "length"); + }, "classList.forEach"); + + test(() => { + var list = document.querySelector("span").classList; + assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator], + "[Symbol.iterator]"); + assert_equals(list.keys, Array.prototype.keys, ".keys"); + if (Array.prototype.values) { + assert_equals(list.values, Array.prototype.values, ".values"); + } + assert_equals(list.entries, Array.prototype.entries, ".entries"); + assert_equals(list.forEach, Array.prototype.forEach, ".forEach"); + }, "classList inheritance from Array.prototype"); +</script> diff --git a/testing/web-platform/tests/dom/lists/DOMTokenList-stringifier.html b/testing/web-platform/tests/dom/lists/DOMTokenList-stringifier.html new file mode 100644 index 0000000000..b125388e02 --- /dev/null +++ b/testing/web-platform/tests/dom/lists/DOMTokenList-stringifier.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>DOMTokenList stringifier</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domtokenlist-stringifier"> +<link rel=author title=Ms2ger href="mailto:Ms2ger@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<span class=" a a b "></span> +<script> +test(function() { + assert_equals(String(document.createElement("span").classList), "", + "String(classList) should return the empty list for an undefined class attribute"); + var span = document.querySelector("span"); + assert_equals(span.getAttribute("class"), " a a b ", + "getAttribute should return the literal value"); + assert_equals(span.className, " a a b ", + "className should return the literal value"); + assert_equals(String(span.classList), " a a b ", + "String(classList) should return the literal value"); + assert_equals(span.classList.toString(), " a a b ", + "classList.toString() should return the literal value"); + assert_class_string(span.classList, "DOMTokenList"); +}); +</script> diff --git a/testing/web-platform/tests/dom/lists/DOMTokenList-value.html b/testing/web-platform/tests/dom/lists/DOMTokenList-value.html new file mode 100644 index 0000000000..b0e39111d9 --- /dev/null +++ b/testing/web-platform/tests/dom/lists/DOMTokenList-value.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DOMTokenList value</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domtokenlist-value"> +<link rel=author title=Tangresh href="mailto:dmenzi@tangresh.ch"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<span class=" a a b "></span> +<script> +test(function() { + assert_equals(String(document.createElement("span").classList.value), "", + "classList.value should return the empty list for an undefined class attribute"); + var span = document.querySelector("span"); + assert_equals(span.classList.value, " a a b ", + "value should return the literal value"); + span.classList.value = " foo bar foo "; + assert_equals(span.classList.value, " foo bar foo ", + "assigning value should set the literal value"); + assert_equals(span.classList.length, 2, + "length should be the number of tokens"); + assert_class_string(span.classList, "DOMTokenList"); + assert_class_string(span.classList.value, "String"); +}); +</script> diff --git a/testing/web-platform/tests/dom/lists/README.md b/testing/web-platform/tests/dom/lists/README.md new file mode 100644 index 0000000000..59c821a7da --- /dev/null +++ b/testing/web-platform/tests/dom/lists/README.md @@ -0,0 +1 @@ +See `../nodes/Element-classlist.html` for more DOMTokenList tests. diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-appendChild.html b/testing/web-platform/tests/dom/nodes/CharacterData-appendChild.html new file mode 100644 index 0000000000..eb4f36c681 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-appendChild.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.appendChild applied to CharacterData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-appendchild"> +<link rel=help href="https://dom.spec.whatwg.org/#introduction-to-the-dom"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function create(type) { + switch (type) { + case "Text": return document.createTextNode("test"); break; + case "Comment": return document.createComment("test"); break; + case "ProcessingInstruction": return document.createProcessingInstruction("target", "test"); break; + } +} + +function testNode(type1, type2) { + test(function() { + var node1 = create(type1); + var node2 = create(type2); + assert_throws_dom("HierarchyRequestError", function () { + node1.appendChild(node2); + }, "CharacterData type " + type1 + " must not have children"); + }, type1 + ".appendChild(" + type2 + ")"); +} + +var types = ["Text", "Comment", "ProcessingInstruction"]; +types.forEach(function(type1) { + types.forEach(function(type2) { + testNode(type1, type2); + }); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-appendData.html b/testing/web-platform/tests/dom/nodes/CharacterData-appendData.html new file mode 100644 index 0000000000..a5d4072244 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-appendData.html @@ -0,0 +1,70 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.appendData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-appenddata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.appendData("bar") + assert_equals(node.data, "testbar") + }, type + ".appendData('bar')") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.appendData("") + assert_equals(node.data, "test") + }, type + ".appendData('')") + + test(function() { + var node = create() + assert_equals(node.data, "test") + node.appendData(", append more 資料,測試資料"); + assert_equals(node.data, "test, append more 資料,測試資料"); + assert_equals(node.length, 25); + }, type + ".appendData(non-ASCII)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.appendData(null) + assert_equals(node.data, "testnull") + }, type + ".appendData(null)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.appendData(undefined) + assert_equals(node.data, "testundefined") + }, type + ".appendData(undefined)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.appendData("", "bar") + assert_equals(node.data, "test") + }, type + ".appendData('', 'bar')") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_js(TypeError, function() { node.appendData() }); + assert_equals(node.data, "test") + }, type + ".appendData()") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-data.html b/testing/web-platform/tests/dom/nodes/CharacterData-data.html new file mode 100644 index 0000000000..b3b29ea4d7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-data.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.data</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + assert_equals(node.length, 4) + }, type + ".data initial value") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = null; + assert_equals(node.data, "") + assert_equals(node.length, 0) + }, type + ".data = null") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = undefined; + assert_equals(node.data, "undefined") + assert_equals(node.length, 9) + }, type + ".data = undefined") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = 0; + assert_equals(node.data, "0") + assert_equals(node.length, 1) + }, type + ".data = 0") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = ""; + assert_equals(node.data, "") + assert_equals(node.length, 0) + }, type + ".data = ''") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "--"; + assert_equals(node.data, "--") + assert_equals(node.length, 2) + }, type + ".data = '--'") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "資料"; + assert_equals(node.data, "資料") + assert_equals(node.length, 2) + }, type + ".data = '資料'") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST"; + assert_equals(node.data, "🌠 test 🌠 TEST") + assert_equals(node.length, 15) // Counting UTF-16 code units + }, type + ".data = '🌠 test 🌠 TEST'") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-deleteData.html b/testing/web-platform/tests/dom/nodes/CharacterData-deleteData.html new file mode 100644 index 0000000000..84f4d5b415 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-deleteData.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.deleteData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-deletedata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_dom("INDEX_SIZE_ERR", function() { node.deleteData(5, 10) }) + assert_throws_dom("INDEX_SIZE_ERR", function() { node.deleteData(5, 0) }) + assert_throws_dom("INDEX_SIZE_ERR", function() { node.deleteData(-1, 10) }) + assert_throws_dom("INDEX_SIZE_ERR", function() { node.deleteData(-1, 0) }) + }, type + ".deleteData() out of bounds") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(0, 2) + assert_equals(node.data, "st") + }, type + ".deleteData() at the start") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(2, 10) + assert_equals(node.data, "te") + }, type + ".deleteData() at the end") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(1, 1) + assert_equals(node.data, "tst") + }, type + ".deleteData() in the middle") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(2, 0) + assert_equals(node.data, "test") + + node.deleteData(0, 0) + assert_equals(node.data, "test") + }, type + ".deleteData() with zero count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(2, -1) + assert_equals(node.data, "te") + }, type + ".deleteData() with small negative count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.deleteData(1, -0x100000000 + 2) + assert_equals(node.data, "tt") + }, type + ".deleteData() with large negative count") + + test(function() { + var node = create() + node.data = "This is the character data test, append more 資料,更多測試資料"; + + node.deleteData(40, 5); + assert_equals(node.data, "This is the character data test, append 資料,更多測試資料"); + node.deleteData(45, 2); + assert_equals(node.data, "This is the character data test, append 資料,更多資料"); + }, type + ".deleteData() with non-ascii data") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.deleteData(5, 8); // Counting UTF-16 code units + assert_equals(node.data, "🌠 teST"); + }, type + ".deleteData() with non-BMP data") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-insertData.html b/testing/web-platform/tests/dom/nodes/CharacterData-insertData.html new file mode 100644 index 0000000000..62c0ca1018 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-insertData.html @@ -0,0 +1,90 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.insertData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-insertdata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_dom("INDEX_SIZE_ERR", function() { node.insertData(5, "x") }) + assert_throws_dom("INDEX_SIZE_ERR", function() { node.insertData(5, "") }) + }, type + ".insertData() out of bounds") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_dom("INDEX_SIZE_ERR", function() { node.insertData(-1, "x") }) + assert_throws_dom("INDEX_SIZE_ERR", function() { node.insertData(-0x100000000 + 5, "x") }) + }, type + ".insertData() negative out of bounds") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.insertData(-0x100000000 + 2, "X") + assert_equals(node.data, "teXst") + }, type + ".insertData() negative in bounds") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.insertData(0, "") + assert_equals(node.data, "test") + }, type + ".insertData('')") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.insertData(0, "X") + assert_equals(node.data, "Xtest") + }, type + ".insertData() at the start") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.insertData(2, "X") + assert_equals(node.data, "teXst") + }, type + ".insertData() in the middle") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.insertData(4, "ing") + assert_equals(node.data, "testing") + }, type + ".insertData() at the end") + + test(function() { + var node = create() + node.data = "This is the character data, append more 資料,測試資料"; + + node.insertData(26, " test"); + assert_equals(node.data, "This is the character data test, append more 資料,測試資料"); + node.insertData(48, "更多"); + assert_equals(node.data, "This is the character data test, append more 資料,更多測試資料"); + }, type + ".insertData() with non-ascii data") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.insertData(5, "--"); // Counting UTF-16 code units + assert_equals(node.data, "🌠 te--st 🌠 TEST"); + }, type + ".insertData() with non-BMP data") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-remove.html b/testing/web-platform/tests/dom/nodes/CharacterData-remove.html new file mode 100644 index 0000000000..aef9d56bfa --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-remove.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.remove</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-remove"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="ChildNode-remove.js"></script> +<div id=log></div> +<script> +var text, text_parent, + comment, comment_parent, + pi, pi_parent; +setup(function() { + text = document.createTextNode("text"); + text_parent = document.createElement("div"); + comment = document.createComment("comment"); + comment_parent = document.createElement("div"); + pi = document.createProcessingInstruction("foo", "bar"); + pi_parent = document.createElement("div"); +}); +testRemove(text, text_parent, "text"); +testRemove(comment, comment_parent, "comment"); +testRemove(pi, pi_parent, "PI"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-replaceData.html b/testing/web-platform/tests/dom/nodes/CharacterData-replaceData.html new file mode 100644 index 0000000000..537751d832 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-replaceData.html @@ -0,0 +1,163 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.replaceData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-replacedata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + // Step 2. + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_dom("IndexSizeError", function() { node.replaceData(5, 1, "x") }) + assert_throws_dom("IndexSizeError", function() { node.replaceData(5, 0, "") }) + assert_throws_dom("IndexSizeError", function() { node.replaceData(-1, 1, "x") }) + assert_throws_dom("IndexSizeError", function() { node.replaceData(-1, 0, "") }) + assert_equals(node.data, "test") + }, type + ".replaceData() with invalid offset") + + // Step 3. + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(2, 10, "yo") + assert_equals(node.data, "teyo") + }, type + ".replaceData() with clamped count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(2, -1, "yo") + assert_equals(node.data, "teyo") + }, type + ".replaceData() with negative clamped count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 0, "yo") + assert_equals(node.data, "yotest") + }, type + ".replaceData() before the start") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 2, "y") + assert_equals(node.data, "yst") + }, type + ".replaceData() at the start (shorter)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 2, "yo") + assert_equals(node.data, "yost") + }, type + ".replaceData() at the start (equal length)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 2, "yoa") + assert_equals(node.data, "yoast") + }, type + ".replaceData() at the start (longer)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(1, 2, "o") + assert_equals(node.data, "tot") + }, type + ".replaceData() in the middle (shorter)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(1, 2, "yo") + assert_equals(node.data, "tyot") + }, type + ".replaceData() in the middle (equal length)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(1, 1, "waddup") + assert_equals(node.data, "twaddupst") + node.replaceData(1, 1, "yup") + assert_equals(node.data, "tyupaddupst") + }, type + ".replaceData() in the middle (longer)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(1, 20, "yo") + assert_equals(node.data, "tyo") + }, type + ".replaceData() at the end (shorter)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(2, 20, "yo") + assert_equals(node.data, "teyo") + }, type + ".replaceData() at the end (same length)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(4, 20, "yo") + assert_equals(node.data, "testyo") + }, type + ".replaceData() at the end (longer)") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 4, "quux") + assert_equals(node.data, "quux") + }, type + ".replaceData() the whole string") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.replaceData(0, 4, "") + assert_equals(node.data, "") + }, type + ".replaceData() with the empty string") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "This is the character data test, append 資料,更多資料"; + + node.replaceData(33, 6, "other"); + assert_equals(node.data, "This is the character data test, other 資料,更多資料"); + node.replaceData(44, 2, "文字"); + assert_equals(node.data, "This is the character data test, other 資料,更多文字"); + }, type + ".replaceData() with non-ASCII data") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.replaceData(5, 8, "--"); // Counting UTF-16 code units + assert_equals(node.data, "🌠 te--ST"); + }, type + ".replaceData() with non-BMP data") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-substringData.html b/testing/web-platform/tests/dom/nodes/CharacterData-substringData.html new file mode 100644 index 0000000000..b353526480 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-substringData.html @@ -0,0 +1,137 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>CharacterData.substringData</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-substringdata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_js(TypeError, function() { node.substringData() }) + assert_throws_js(TypeError, function() { node.substringData(0) }) + }, type + ".substringData() with too few arguments") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, 1, "test"), "t") + }, type + ".substringData() with too many arguments") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_throws_dom("IndexSizeError", function() { node.substringData(5, 0) }) + assert_throws_dom("IndexSizeError", function() { node.substringData(6, 0) }) + assert_throws_dom("IndexSizeError", function() { node.substringData(-1, 0) }) + }, type + ".substringData() with invalid offset") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, 1), "t") + assert_equals(node.substringData(1, 1), "e") + assert_equals(node.substringData(2, 1), "s") + assert_equals(node.substringData(3, 1), "t") + assert_equals(node.substringData(4, 1), "") + }, type + ".substringData() with in-bounds offset") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, 0), "") + assert_equals(node.substringData(1, 0), "") + assert_equals(node.substringData(2, 0), "") + assert_equals(node.substringData(3, 0), "") + assert_equals(node.substringData(4, 0), "") + }, type + ".substringData() with zero count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0x100000000 + 0, 1), "t") + assert_equals(node.substringData(0x100000000 + 1, 1), "e") + assert_equals(node.substringData(0x100000000 + 2, 1), "s") + assert_equals(node.substringData(0x100000000 + 3, 1), "t") + assert_equals(node.substringData(0x100000000 + 4, 1), "") + }, type + ".substringData() with very large offset") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(-0x100000000 + 2, 1), "s") + }, type + ".substringData() with negative offset") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData("test", 3), "tes") + }, type + ".substringData() with string offset") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, 1), "t") + assert_equals(node.substringData(0, 2), "te") + assert_equals(node.substringData(0, 3), "tes") + assert_equals(node.substringData(0, 4), "test") + }, type + ".substringData() with in-bounds count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, 5), "test") + assert_equals(node.substringData(2, 20), "st") + }, type + ".substringData() with large count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(2, 0x100000000 + 1), "s") + }, type + ".substringData() with very large count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + assert_equals(node.substringData(0, -1), "test") + assert_equals(node.substringData(0, -0x100000000 + 2), "te") + }, type + ".substringData() with negative count") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "This is the character data test, other 資料,更多文字" + + assert_equals(node.substringData(12, 4), "char") + assert_equals(node.substringData(39, 2), "資料") + }, type + ".substringData() with non-ASCII data") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + assert_equals(node.substringData(5, 8), "st 🌠 TE") // Counting UTF-16 code units + }, type + ".substringData() with non-BMP data") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/CharacterData-surrogates.html b/testing/web-platform/tests/dom/nodes/CharacterData-surrogates.html new file mode 100644 index 0000000000..ff1014c5fd --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/CharacterData-surrogates.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Splitting and joining surrogate pairs in CharacterData methods</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-substringdata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-replacedata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-insertdata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-deletedata"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testNode(create, type) { + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + assert_equals(node.substringData(1, 8), "\uDF20 test \uD83C") + }, type + ".substringData() splitting surrogate pairs") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.replaceData(1, 4, "--"); + assert_equals(node.data, "\uD83C--st 🌠 TEST"); + + node.replaceData(1, 2, "\uDF1F "); + assert_equals(node.data, "🌟 st 🌠 TEST"); + + node.replaceData(5, 2, "---"); + assert_equals(node.data, "🌟 st---\uDF20 TEST"); + + node.replaceData(6, 2, " \uD83D"); + assert_equals(node.data, "🌟 st- 🜠 TEST"); + }, type + ".replaceData() splitting and creating surrogate pairs") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.deleteData(1, 4); + assert_equals(node.data, "\uD83Cst 🌠 TEST"); + + node.deleteData(1, 4); + assert_equals(node.data, "🌠 TEST"); + }, type + ".deleteData() splitting and creating surrogate pairs") + + test(function() { + var node = create() + assert_equals(node.data, "test") + + node.data = "🌠 test 🌠 TEST" + + node.insertData(1, "--"); + assert_equals(node.data, "\uD83C--\uDF20 test 🌠 TEST"); + + node.insertData(1, "\uDF1F "); + assert_equals(node.data, "🌟 --\uDF20 test 🌠 TEST"); + + node.insertData(5, " \uD83D"); + assert_equals(node.data, "🌟 -- 🜠 test 🌠 TEST"); + }, type + ".insertData() splitting and creating surrogate pairs") +} + +testNode(function() { return document.createTextNode("test") }, "Text") +testNode(function() { return document.createComment("test") }, "Comment") +</script> diff --git a/testing/web-platform/tests/dom/nodes/ChildNode-after.html b/testing/web-platform/tests/dom/nodes/ChildNode-after.html new file mode 100644 index 0000000000..b5bf7ab5c2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ChildNode-after.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ChildNode.after</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-after"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function test_after(child, nodeName, innerHTML) { + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after(); + assert_equals(parent.innerHTML, innerHTML); + }, nodeName + '.after() without any argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after(null); + var expected = innerHTML + 'null'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with null as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after(undefined); + var expected = innerHTML + 'undefined'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with undefined as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after(''); + assert_equals(parent.lastChild.data, ''); + }, nodeName + '.after() with the empty string as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after('text'); + var expected = innerHTML + 'text'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with only text as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.after(x); + var expected = innerHTML + '<x></x>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with only one element as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.after(x, 'text'); + var expected = innerHTML + '<x></x>text'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with one element and text as arguments.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.after('text', child); + var expected = 'text' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with context object itself as the argument.'); + + test(function() { + var parent = document.createElement('div') + var x = document.createElement('x'); + parent.appendChild(x); + parent.appendChild(child); + child.after(child, x); + var expected = innerHTML + '<x></x>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with context object itself and node as the arguments, switching positions.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(y); + parent.appendChild(child); + parent.appendChild(x); + child.after(x, y, z); + var expected = innerHTML + '<x></x><y></y><z></z>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with all siblings of child as arguments.'); + + test(function() { + var parent = document.createElement('div') + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(child); + parent.appendChild(x); + parent.appendChild(y); + parent.appendChild(z); + child.after(x, y); + var expected = innerHTML + '<x></x><y></y><z></z>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with some siblings of child as arguments; no changes in tree; viable sibling is first child.'); + + test(function() { + var parent = document.createElement('div') + var v = document.createElement('v'); + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(child); + parent.appendChild(v); + parent.appendChild(x); + parent.appendChild(y); + parent.appendChild(z); + child.after(v, x); + var expected = innerHTML + '<v></v><x></x><y></y><z></z>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with some siblings of child as arguments; no changes in tree.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(child); + parent.appendChild(x); + parent.appendChild(y); + child.after(y, x); + var expected = innerHTML + '<y></y><x></x>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() when pre-insert behaves like append.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(child); + parent.appendChild(x); + parent.appendChild(document.createTextNode('1')); + parent.appendChild(y); + child.after(x, '2'); + var expected = innerHTML + '<x></x>21<y></y>'; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.after() with one sibling of child and text as arguments.'); + + test(function() { + var x = document.createElement('x'); + var y = document.createElement('y'); + x.after(y); + assert_equals(x.nextSibling, null); + }, nodeName + '.after() on a child without any parent.'); +} + +test_after(document.createComment('test'), 'Comment', '<!--test-->'); +test_after(document.createElement('test'), 'Element', '<test></test>'); +test_after(document.createTextNode('test'), 'Text', 'test'); + +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ChildNode-before.html b/testing/web-platform/tests/dom/nodes/ChildNode-before.html new file mode 100644 index 0000000000..8659424465 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ChildNode-before.html @@ -0,0 +1,166 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ChildNode.before</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-before"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function test_before(child, nodeName, innerHTML) { + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before(); + assert_equals(parent.innerHTML, innerHTML); + }, nodeName + '.before() without any argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before(null); + var expected = 'null' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with null as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before(undefined); + var expected = 'undefined' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with undefined as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before(''); + assert_equals(parent.firstChild.data, ''); + }, nodeName + '.before() with the empty string as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before('text'); + var expected = 'text' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with only text as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.before(x); + var expected = '<x></x>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with only one element as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.before(x, 'text'); + var expected = '<x></x>text' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with one element and text as arguments.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.before('text', child); + var expected = 'text' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with context object itself as the argument.'); + + test(function() { + var parent = document.createElement('div') + var x = document.createElement('x'); + parent.appendChild(child); + parent.appendChild(x); + child.before(x, child); + var expected = '<x></x>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with context object itself and node as the arguments, switching positions.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(y); + parent.appendChild(child); + parent.appendChild(x); + child.before(x, y, z); + var expected = '<x></x><y></y><z></z>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with all siblings of child as arguments.'); + + test(function() { + var parent = document.createElement('div') + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(x); + parent.appendChild(y); + parent.appendChild(z); + parent.appendChild(child); + child.before(y, z); + var expected = '<x></x><y></y><z></z>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with some siblings of child as arguments; no changes in tree; viable sibling is first child.'); + + test(function() { + var parent = document.createElement('div') + var v = document.createElement('v'); + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(v); + parent.appendChild(x); + parent.appendChild(y); + parent.appendChild(z); + parent.appendChild(child); + child.before(y, z); + var expected = '<v></v><x></x><y></y><z></z>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with some siblings of child as arguments; no changes in tree.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(x); + parent.appendChild(y); + parent.appendChild(child); + child.before(y, x); + var expected = '<y></y><x></x>' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() when pre-insert behaves like prepend.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(x); + parent.appendChild(document.createTextNode('1')); + var y = document.createElement('y'); + parent.appendChild(y); + parent.appendChild(child); + child.before(x, '2'); + var expected = '1<y></y><x></x>2' + innerHTML; + assert_equals(parent.innerHTML, expected); + }, nodeName + '.before() with one sibling of child and text as arguments.'); + + test(function() { + var x = document.createElement('x'); + var y = document.createElement('y'); + x.before(y); + assert_equals(x.previousSibling, null); + }, nodeName + '.before() on a child without any parent.'); +} + +test_before(document.createComment('test'), 'Comment', '<!--test-->'); +test_before(document.createElement('test'), 'Element', '<test></test>'); +test_before(document.createTextNode('test'), 'Text', 'test'); + +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ChildNode-remove.js b/testing/web-platform/tests/dom/nodes/ChildNode-remove.js new file mode 100644 index 0000000000..c36ba0d117 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ChildNode-remove.js @@ -0,0 +1,30 @@ +function testRemove(node, parent, type) { + test(function() { + assert_true("remove" in node); + assert_equals(typeof node.remove, "function"); + assert_equals(node.remove.length, 0); + }, type + " should support remove()"); + test(function() { + assert_equals(node.parentNode, null, "Node should not have a parent"); + assert_equals(node.remove(), undefined); + assert_equals(node.parentNode, null, "Removed new node should not have a parent"); + }, "remove() should work if " + type + " doesn't have a parent"); + test(function() { + assert_equals(node.parentNode, null, "Node should not have a parent"); + parent.appendChild(node); + assert_equals(node.parentNode, parent, "Appended node should have a parent"); + assert_equals(node.remove(), undefined); + assert_equals(node.parentNode, null, "Removed node should not have a parent"); + assert_array_equals(parent.childNodes, [], "Parent should not have children"); + }, "remove() should work if " + type + " does have a parent"); + test(function() { + assert_equals(node.parentNode, null, "Node should not have a parent"); + var before = parent.appendChild(document.createComment("before")); + parent.appendChild(node); + var after = parent.appendChild(document.createComment("after")); + assert_equals(node.parentNode, parent, "Appended node should have a parent"); + assert_equals(node.remove(), undefined); + assert_equals(node.parentNode, null, "Removed node should not have a parent"); + assert_array_equals(parent.childNodes, [before, after], "Parent should have two children left"); + }, "remove() should work if " + type + " does have a parent and siblings"); +} diff --git a/testing/web-platform/tests/dom/nodes/ChildNode-replaceWith.html b/testing/web-platform/tests/dom/nodes/ChildNode-replaceWith.html new file mode 100644 index 0000000000..aab8b17f2a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ChildNode-replaceWith.html @@ -0,0 +1,110 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ChildNode.replaceWith</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-replaceWith"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function test_replaceWith(child, nodeName, innerHTML) { + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.replaceWith(); + assert_equals(parent.innerHTML, ''); + }, nodeName + '.replaceWith() without any argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.replaceWith(null); + assert_equals(parent.innerHTML, 'null'); + }, nodeName + '.replaceWith() with null as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.replaceWith(undefined); + assert_equals(parent.innerHTML, 'undefined'); + }, nodeName + '.replaceWith() with undefined as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.replaceWith(''); + assert_equals(parent.innerHTML, ''); + }, nodeName + '.replaceWith() with empty string as an argument.'); + + test(function() { + var parent = document.createElement('div'); + parent.appendChild(child); + child.replaceWith('text'); + assert_equals(parent.innerHTML, 'text'); + }, nodeName + '.replaceWith() with only text as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.replaceWith(x); + assert_equals(parent.innerHTML, '<x></x>'); + }, nodeName + '.replaceWith() with only one element as an argument.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + var z = document.createElement('z'); + parent.appendChild(y); + parent.appendChild(child); + parent.appendChild(x); + child.replaceWith(x, y, z); + assert_equals(parent.innerHTML, '<x></x><y></y><z></z>'); + }, nodeName + '.replaceWith() with sibling of child as arguments.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + parent.appendChild(x); + parent.appendChild(document.createTextNode('1')); + child.replaceWith(x, '2'); + assert_equals(parent.innerHTML, '<x></x>21'); + }, nodeName + '.replaceWith() with one sibling of child and text as arguments.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + parent.appendChild(x); + parent.appendChild(document.createTextNode('text')); + child.replaceWith(x, child); + assert_equals(parent.innerHTML, '<x></x>' + innerHTML + 'text'); + }, nodeName + '.replaceWith() with one sibling of child and child itself as arguments.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + parent.appendChild(child); + child.replaceWith(x, 'text'); + assert_equals(parent.innerHTML, '<x></x>text'); + }, nodeName + '.replaceWith() with one element and text as arguments.'); + + test(function() { + var parent = document.createElement('div'); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(x); + parent.appendChild(y); + child.replaceWith(x, y); + assert_equals(parent.innerHTML, '<x></x><y></y>'); + }, nodeName + '.replaceWith() on a parentless child with two elements as arguments.'); +} + +test_replaceWith(document.createComment('test'), 'Comment', '<!--test-->'); +test_replaceWith(document.createElement('test'), 'Element', '<test></test>'); +test_replaceWith(document.createTextNode('test'), 'Text', 'test'); + +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Comment-Text-constructor.js b/testing/web-platform/tests/dom/nodes/Comment-Text-constructor.js new file mode 100644 index 0000000000..24b4425f4b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Comment-Text-constructor.js @@ -0,0 +1,77 @@ +function test_constructor(ctor) { + test(function() { + var object = new window[ctor](); + assert_equals(Object.getPrototypeOf(object), + window[ctor].prototype, "Prototype chain: " + ctor); + assert_equals(Object.getPrototypeOf(Object.getPrototypeOf(object)), + CharacterData.prototype, "Prototype chain: CharacterData"); + assert_equals(Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(object))), + Node.prototype, "Prototype chain: Node"); + }, "new " + ctor + "(): prototype chain"); + + test(function() { + var object = new window[ctor](); + assert_true(object instanceof Node, "Should be a Node"); + assert_true(object instanceof CharacterData, "Should be a CharacterData"); + assert_true(object instanceof window[ctor], "Should be a " + ctor); + }, "new " + ctor + "(): instanceof"); + + test(function() { + var object = new window[ctor](); + assert_equals(object.data, ""); + assert_equals(object.nodeValue, ""); + assert_equals(object.ownerDocument, document); + }, "new " + ctor + "(): no arguments"); + + var testArgs = [ + [undefined, ""], + [null, "null"], + [42, "42"], + ["", ""], + ["-", "-"], + ["--", "--"], + ["-->", "-->"], + ["<!--", "<!--"], + ["\u0000", "\u0000"], + ["\u0000test", "\u0000test"], + ["&", "&"], + ]; + + testArgs.forEach(function(a) { + var argument = a[0], expected = a[1]; + test(function() { + var object = new window[ctor](argument); + assert_equals(object.data, expected); + assert_equals(object.nodeValue, expected); + assert_equals(object.ownerDocument, document); + }, "new " + ctor + "(): " + format_value(argument)); + }); + + test(function() { + var called = []; + var object = new window[ctor]({ + toString: function() { + called.push("first"); + return "text"; + } + }, { + toString: function() { + called.push("second"); + assert_unreached("Should not look at the second argument."); + } + }); + assert_equals(object.data, "text"); + assert_equals(object.nodeValue, "text"); + assert_equals(object.ownerDocument, document); + assert_array_equals(called, ["first"]); + }, "new " + ctor + "(): two arguments") + + async_test("new " + ctor + "() should get the correct ownerDocument across globals").step(function() { + var iframe = document.createElement("iframe"); + iframe.onload = this.step_func_done(function() { + var object = new iframe.contentWindow[ctor](); + assert_equals(object.ownerDocument, iframe.contentDocument); + }); + document.body.appendChild(iframe); + }); +} diff --git a/testing/web-platform/tests/dom/nodes/Comment-constructor.html b/testing/web-platform/tests/dom/nodes/Comment-constructor.html new file mode 100644 index 0000000000..5091316bd3 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Comment-constructor.html @@ -0,0 +1,11 @@ +<!doctype html> +<meta charset=utf-8> +<title>Comment constructor</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-comment"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Comment-Text-constructor.js"></script> +<div id="log"></div> +<script> +test_constructor("Comment"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument-with-null-browsing-context-crash.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument-with-null-browsing-context-crash.html new file mode 100644 index 0000000000..c9393d0a09 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument-with-null-browsing-context-crash.html @@ -0,0 +1,13 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMImplementation.createDocument()</title> +<link rel="author" title="Nate Chapin" href="mailto:japhet@chromium.org"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createdocument"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1086801"> +<meta name="assert" content="Calling on createDocument() on a DOMImplementation from a document with a null browsing context should not crash"/> +<iframe id="i"></iframe> +<script> +var doc = i.contentDocument; +i.remove(); +doc.implementation.createDocument("", ""); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument.html new file mode 100644 index 0000000000..835002b470 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocument.html @@ -0,0 +1,170 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMImplementation.createDocument(namespace, qualifiedName, doctype)</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createdocument"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelementns"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodetype"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-documentelement"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-doctype"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-createElementNS.js"></script> +<div id="log"></div> +<script> +var htmlNamespace = "http://www.w3.org/1999/xhtml" +var svgNamespace = "http://www.w3.org/2000/svg" +var mathMLNamespace = "http://www.w3.org/1998/Math/MathML" + +// Make DocumentTypes distinct +function my_format_value(val) { + if (val instanceof DocumentType) { + return "DocumentType node <!DOCTYPE " + val.name + + (val.publicId ? " " + val.publicId : "") + + (val.systemId ? " " + val.systemId : "") + + ">"; + } + return format_value(val); +} + +test(function() { + var tests = createElementNS_tests.map(function(t) { + return [t[0], t[1], null, t[2]] + }).concat([ + /* Arrays with four elements: + * the namespace argument + * the qualifiedName argument + * the doctype argument + * the expected exception, or null if none + */ + [null, null, false, TypeError], + [null, "", null, null], + [undefined, null, undefined, null], + [undefined, undefined, undefined, null], + [undefined, "", undefined, null], + ["http://example.com/", null, null, null], + ["http://example.com/", "", null, null], + ["/", null, null, null], + ["/", "", null, null], + ["http://www.w3.org/XML/1998/namespace", null, null, null], + ["http://www.w3.org/XML/1998/namespace", "", null, null], + ["http://www.w3.org/2000/xmlns/", null, null, null], + ["http://www.w3.org/2000/xmlns/", "", null, null], + ["foo:", null, null, null], + ["foo:", "", null, null], + [null, null, document.implementation.createDocumentType("foo", "", ""), null], + [null, null, document.doctype, null], // This causes a horrible WebKit bug (now fixed in trunk). + [null, null, function() { + var foo = document.implementation.createDocumentType("bar", "", ""); + document.implementation.createDocument(null, null, foo); + return foo; + }(), null], // DOCTYPE already associated with a document. + [null, null, function() { + var bar = document.implementation.createDocument(null, null, null); + return bar.implementation.createDocumentType("baz", "", ""); + }(), null], // DOCTYPE created by a different implementation. + [null, null, function() { + var bar = document.implementation.createDocument(null, null, null); + var magic = bar.implementation.createDocumentType("quz", "", ""); + bar.implementation.createDocument(null, null, magic); + return magic; + }(), null], // DOCTYPE created by a different implementation and already associated with a document. + [null, "foo", document.implementation.createDocumentType("foo", "", ""), null], + ["foo", null, document.implementation.createDocumentType("foo", "", ""), null], + ["foo", "bar", document.implementation.createDocumentType("foo", "", ""), null], + [htmlNamespace, "", null, null], + [svgNamespace, "", null, null], + [mathMLNamespace, "", null, null], + [null, "html", null, null], + [null, "svg", null, null], + [null, "math", null, null], + [null, "", document.implementation.createDocumentType("html", + "-//W3C//DTD XHTML 1.0 Transitional//EN", + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd")], + [null, "", document.implementation.createDocumentType("svg", + "-//W3C//DTD SVG 1.1//EN", + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd")], + [null, "", document.implementation.createDocumentType("math", + "-//W3C//DTD MathML 2.0//EN", + "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd")], + ]) + + tests.forEach(function(t, i) { + var namespace = t[0], qualifiedName = t[1], doctype = t[2], expected = t[3] + test(function() { + if (expected != null) { + if (typeof expected == "string") { + assert_throws_dom(expected, function() { document.implementation.createDocument(namespace, qualifiedName, doctype) }); + } else { + assert_throws_js(expected, function() { document.implementation.createDocument(namespace, qualifiedName, doctype) }); + } + } else { + var doc = document.implementation.createDocument(namespace, qualifiedName, doctype) + assert_equals(doc.nodeType, Node.DOCUMENT_NODE) + assert_equals(doc.nodeType, doc.DOCUMENT_NODE) + assert_equals(doc.nodeName, "#document") + assert_equals(doc.nodeValue, null) + assert_equals(Object.getPrototypeOf(doc), XMLDocument.prototype) + var omitRootElement = qualifiedName === null || String(qualifiedName) === "" + if (omitRootElement) { + assert_equals(doc.documentElement, null) + } else { + var element = doc.documentElement + assert_not_equals(element, null) + assert_equals(element.nodeType, Node.ELEMENT_NODE) + assert_equals(element.ownerDocument, doc) + var qualified = String(qualifiedName), names = [] + if (qualified.indexOf(":") >= 0) { + names = qualified.split(":", 2) + } else { + names = [null, qualified] + } + assert_equals(element.prefix, names[0]) + assert_equals(element.localName, names[1]) + assert_equals(element.namespaceURI, namespace === undefined ? null : namespace) + } + if (!doctype) { + assert_equals(doc.doctype, null) + } else { + assert_equals(doc.doctype, doctype) + assert_equals(doc.doctype.ownerDocument, doc) + } + assert_equals(doc.childNodes.length, !omitRootElement + !!doctype) + } + }, "createDocument test: " + t.map(my_format_value)) + + if (expected === null) { + test(function() { + var doc = document.implementation.createDocument(namespace, qualifiedName, doctype) + assert_equals(doc.location, null) + assert_equals(doc.compatMode, "CSS1Compat") + assert_equals(doc.characterSet, "UTF-8") + assert_equals(doc.contentType, namespace == htmlNamespace ? "application/xhtml+xml" + : namespace == svgNamespace ? "image/svg+xml" + : "application/xml") + assert_equals(doc.URL, "about:blank") + assert_equals(doc.documentURI, "about:blank") + assert_equals(doc.createElement("DIV").localName, "DIV"); + }, "createDocument test: metadata for " + + [namespace, qualifiedName, doctype].map(my_format_value)) + + test(function() { + var doc = document.implementation.createDocument(namespace, qualifiedName, doctype) + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); + }, "createDocument test: characterSet aliases for " + + [namespace, qualifiedName, doctype].map(my_format_value)) + } + }) +}) + +test(function() { + assert_throws_js(TypeError, function() { + document.implementation.createDocument() + }, "createDocument() should throw") + + assert_throws_js(TypeError, function() { + document.implementation.createDocument('') + }, "createDocument('') should throw") +}, "createDocument with missing arguments"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html new file mode 100644 index 0000000000..8d23e66a2b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createDocumentType.html @@ -0,0 +1,123 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMImplementation.createDocumentType(qualifiedName, publicId, systemId)</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createdocumenttype"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-name"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-publicid"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-systemid"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-ownerdocument"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var tests = [ + ["", "", "", "INVALID_CHARACTER_ERR"], + ["test:root", "1234", "", null], + ["test:root", "1234", "test", null], + ["test:root", "test", "", null], + ["test:root", "test", "test", null], + ["_:_", "", "", null], + ["_:h0", "", "", null], + ["_:test", "", "", null], + ["_:_.", "", "", null], + ["_:a-", "", "", null], + ["l_:_", "", "", null], + ["ns:_0", "", "", null], + ["ns:a0", "", "", null], + ["ns0:test", "", "", null], + ["ns:EEE.", "", "", null], + ["ns:_-", "", "", null], + ["a.b:c", "", "", null], + ["a-b:c.j", "", "", null], + ["a-b:c", "", "", null], + ["foo", "", "", null], + ["1foo", "", "", "INVALID_CHARACTER_ERR"], + ["foo1", "", "", null], + ["f1oo", "", "", null], + ["@foo", "", "", "INVALID_CHARACTER_ERR"], + ["foo@", "", "", "INVALID_CHARACTER_ERR"], + ["f@oo", "", "", "INVALID_CHARACTER_ERR"], + ["edi:{", "", "", "INVALID_CHARACTER_ERR"], + ["edi:}", "", "", "INVALID_CHARACTER_ERR"], + ["edi:~", "", "", "INVALID_CHARACTER_ERR"], + ["edi:'", "", "", "INVALID_CHARACTER_ERR"], + ["edi:!", "", "", "INVALID_CHARACTER_ERR"], + ["edi:@", "", "", "INVALID_CHARACTER_ERR"], + ["edi:#", "", "", "INVALID_CHARACTER_ERR"], + ["edi:$", "", "", "INVALID_CHARACTER_ERR"], + ["edi:%", "", "", "INVALID_CHARACTER_ERR"], + ["edi:^", "", "", "INVALID_CHARACTER_ERR"], + ["edi:&", "", "", "INVALID_CHARACTER_ERR"], + ["edi:*", "", "", "INVALID_CHARACTER_ERR"], + ["edi:(", "", "", "INVALID_CHARACTER_ERR"], + ["edi:)", "", "", "INVALID_CHARACTER_ERR"], + ["edi:+", "", "", "INVALID_CHARACTER_ERR"], + ["edi:=", "", "", "INVALID_CHARACTER_ERR"], + ["edi:[", "", "", "INVALID_CHARACTER_ERR"], + ["edi:]", "", "", "INVALID_CHARACTER_ERR"], + ["edi:\\", "", "", "INVALID_CHARACTER_ERR"], + ["edi:/", "", "", "INVALID_CHARACTER_ERR"], + ["edi:;", "", "", "INVALID_CHARACTER_ERR"], + ["edi:`", "", "", "INVALID_CHARACTER_ERR"], + ["edi:<", "", "", "INVALID_CHARACTER_ERR"], + ["edi:>", "", "", "INVALID_CHARACTER_ERR"], + ["edi:,", "", "", "INVALID_CHARACTER_ERR"], + ["edi:a ", "", "", "INVALID_CHARACTER_ERR"], + ["edi:\"", "", "", "INVALID_CHARACTER_ERR"], + ["{", "", "", "INVALID_CHARACTER_ERR"], + ["}", "", "", "INVALID_CHARACTER_ERR"], + ["'", "", "", "INVALID_CHARACTER_ERR"], + ["~", "", "", "INVALID_CHARACTER_ERR"], + ["`", "", "", "INVALID_CHARACTER_ERR"], + ["@", "", "", "INVALID_CHARACTER_ERR"], + ["#", "", "", "INVALID_CHARACTER_ERR"], + ["$", "", "", "INVALID_CHARACTER_ERR"], + ["%", "", "", "INVALID_CHARACTER_ERR"], + ["^", "", "", "INVALID_CHARACTER_ERR"], + ["&", "", "", "INVALID_CHARACTER_ERR"], + ["*", "", "", "INVALID_CHARACTER_ERR"], + ["(", "", "", "INVALID_CHARACTER_ERR"], + [")", "", "", "INVALID_CHARACTER_ERR"], + ["f:oo", "", "", null], + [":foo", "", "", "INVALID_CHARACTER_ERR"], + ["foo:", "", "", "INVALID_CHARACTER_ERR"], + ["prefix::local", "", "", "INVALID_CHARACTER_ERR"], + ["foo", "foo", "", null], + ["foo", "", "foo", null], + ["foo", "f'oo", "", null], + ["foo", "", "f'oo", null], + ["foo", 'f"oo', "", null], + ["foo", "", 'f"oo', null], + ["foo", "f'o\"o", "", null], + ["foo", "", "f'o\"o", null], + ["foo", "foo>", "", null], + ["foo", "", "foo>", null] + ] + + var doc = document.implementation.createHTMLDocument("title"); + var doTest = function(aDocument, aQualifiedName, aPublicId, aSystemId) { + var doctype = aDocument.implementation.createDocumentType(aQualifiedName, aPublicId, aSystemId); + assert_equals(doctype.name, aQualifiedName, "name") + assert_equals(doctype.nodeName, aQualifiedName, "nodeName") + assert_equals(doctype.publicId, aPublicId, "publicId") + assert_equals(doctype.systemId, aSystemId, "systemId") + assert_equals(doctype.ownerDocument, aDocument, "ownerDocument") + assert_equals(doctype.nodeValue, null, "nodeValue") + } + tests.forEach(function(t) { + var qualifiedName = t[0], publicId = t[1], systemId = t[2], expected = t[3] + test(function() { + if (expected) { + assert_throws_dom(expected, function() { + document.implementation.createDocumentType(qualifiedName, publicId, systemId) + }) + } else { + doTest(document, qualifiedName, publicId, systemId); + doTest(doc, qualifiedName, publicId, systemId); + } + }, "createDocumentType(" + format_value(qualifiedName) + ", " + format_value(publicId) + ", " + format_value(systemId) + ") should " + + (expected ? "throw " + expected : "work")); + }); +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html new file mode 100644 index 0000000000..d0cd6f1f74 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-null-browsing-context-crash.html @@ -0,0 +1,13 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMImplementation.createHTMLDocument()</title> +<link rel="author" title="Nate Chapin" href="mailto:japhet@chromium.org"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1086800"> +<meta name="assert" content="Calling on createHTMLDocument() on a DOMImplementation from a document with a null browsing context should not crash"/> +<iframe id="i"></iframe> +<script> +var doc = i.contentDocument; +i.remove(); +doc.implementation.createHTMLDocument(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-saved-implementation.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-saved-implementation.html new file mode 100644 index 0000000000..bae22660bf --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument-with-saved-implementation.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>DOMImplementation.createHTMLDocument</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +// Test the document location getter is null outside of browser context +test(function() { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + var implementation = iframe.contentDocument.implementation; + iframe.remove(); + assert_not_equals(implementation.createHTMLDocument(), null); +}, "createHTMLDocument(): from a saved and detached implementation does not return null") +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.html new file mode 100644 index 0000000000..c6e0beaf75 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<meta charset=windows-1252> +<!-- Using windows-1252 to ensure that DOMImplementation.createHTMLDocument() + doesn't inherit utf-8 from the parent document. --> +<title>DOMImplementation.createHTMLDocument</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-name"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-publicid"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-documenttype-systemid"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-documentelement"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="DOMImplementation-createHTMLDocument.js"></script> +<div id="log"></div> +<script> +createHTMLDocuments(function(doc, expectedtitle, normalizedtitle) { + assert_true(doc instanceof Document, "Should be a Document") + assert_true(doc instanceof Node, "Should be a Node") + assert_equals(doc.childNodes.length, 2, + "Document should have two child nodes") + + var doctype = doc.doctype + assert_true(doctype instanceof DocumentType, + "Doctype should be a DocumentType") + assert_true(doctype instanceof Node, "Doctype should be a Node") + assert_equals(doctype.name, "html") + assert_equals(doctype.publicId, "") + assert_equals(doctype.systemId, "") + + var documentElement = doc.documentElement + assert_true(documentElement instanceof HTMLHtmlElement, + "Document element should be a HTMLHtmlElement") + assert_equals(documentElement.childNodes.length, 2, + "Document element should have two child nodes") + assert_equals(documentElement.localName, "html") + assert_equals(documentElement.tagName, "HTML") + + var head = documentElement.firstChild + assert_true(head instanceof HTMLHeadElement, + "Head should be a HTMLHeadElement") + assert_equals(head.localName, "head") + assert_equals(head.tagName, "HEAD") + + if (expectedtitle !== undefined) { + assert_equals(head.childNodes.length, 1) + + var title = head.firstChild + assert_true(title instanceof HTMLTitleElement, + "Title should be a HTMLTitleElement") + assert_equals(title.localName, "title") + assert_equals(title.tagName, "TITLE") + assert_equals(title.childNodes.length, 1) + assert_equals(title.firstChild.data, expectedtitle) + } else { + assert_equals(head.childNodes.length, 0) + } + + var body = documentElement.lastChild + assert_true(body instanceof HTMLBodyElement, + "Body should be a HTMLBodyElement") + assert_equals(body.localName, "body") + assert_equals(body.tagName, "BODY") + assert_equals(body.childNodes.length, 0) +}) + +test(function() { + var doc = document.implementation.createHTMLDocument("test"); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.documentURI, "about:blank"); + assert_equals(doc.compatMode, "CSS1Compat"); + assert_equals(doc.characterSet, "UTF-8"); + assert_equals(doc.contentType, "text/html"); + assert_equals(doc.createElement("DIV").localName, "div"); +}, "createHTMLDocument(): metadata") + +test(function() { + var doc = document.implementation.createHTMLDocument("test"); + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); +}, "createHTMLDocument(): characterSet aliases") + +test(function() { + var doc = document.implementation.createHTMLDocument("test"); + var a = doc.createElement("a"); + // In UTF-8: 0xC3 0xA4 + a.href = "http://example.org/?\u00E4"; + assert_equals(a.href, "http://example.org/?%C3%A4"); +}, "createHTMLDocument(): URL parsing") + +// Test the document location getter is null outside of browser context +test(function() { + var doc = document.implementation.createHTMLDocument(); + assert_equals(doc.location, null); +}, "createHTMLDocument(): document location getter is null") +</script> diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.js b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.js new file mode 100644 index 0000000000..3e7e9aa9b7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-createHTMLDocument.js @@ -0,0 +1,25 @@ +function createHTMLDocuments(checkDoc) { + var tests = [ + ["", "", ""], + [null, "null", "null"], + [undefined, undefined, ""], + ["foo bar baz", "foo bar baz", "foo bar baz"], + ["foo\t\tbar baz", "foo\t\tbar baz", "foo bar baz"], + ["foo\n\nbar baz", "foo\n\nbar baz", "foo bar baz"], + ["foo\f\fbar baz", "foo\f\fbar baz", "foo bar baz"], + ["foo\r\rbar baz", "foo\r\rbar baz", "foo bar baz"], + ] + + tests.forEach(function(t, i) { + var title = t[0], expectedtitle = t[1], normalizedtitle = t[2] + test(function() { + var doc = document.implementation.createHTMLDocument(title); + checkDoc(doc, expectedtitle, normalizedtitle) + }, "createHTMLDocument test " + i + ": " + t.map(function(el) { return format_value(el) })) + }) + + test(function() { + var doc = document.implementation.createHTMLDocument(); + checkDoc(doc, undefined, "") + }, "Missing title argument"); +} diff --git a/testing/web-platform/tests/dom/nodes/DOMImplementation-hasFeature.html b/testing/web-platform/tests/dom/nodes/DOMImplementation-hasFeature.html new file mode 100644 index 0000000000..637565a60f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DOMImplementation-hasFeature.html @@ -0,0 +1,155 @@ +<!doctype html> +<meta charset=utf-8> +<title>DOMImplementation.hasFeature(feature, version)</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-hasfeature"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var tests = [ + [], + ["Core"], + ["XML"], + ["org.w3c.svg"], + ["org.w3c.dom.svg"], + ["http://www.w3.org/TR/SVG11/feature#Script"], + ["Core", "1.0"], + ["Core", "2.0"], + ["Core", "3.0"], + ["Core", "100.0"], + ["XML", "1.0"], + ["XML", "2.0"], + ["XML", "3.0"], + ["XML", "100.0"], + ["Core", "1"], + ["Core", "2"], + ["Core", "3"], + ["Core", "100"], + ["XML", "1"], + ["XML", "2"], + ["XML", "3"], + ["XML", "100"], + ["Core", "1.1"], + ["Core", "2.1"], + ["Core", "3.1"], + ["Core", "100.1"], + ["XML", "1.1"], + ["XML", "2.1"], + ["XML", "3.1"], + ["XML", "100.1"], + ["Core", ""], + ["XML", ""], + ["core", ""], + ["xml", ""], + ["CoRe", ""], + ["XmL", ""], + [" Core", ""], + [" XML", ""], + ["Core ", ""], + ["XML ", ""], + ["Co re", ""], + ["XM L", ""], + ["aCore", ""], + ["aXML", ""], + ["Corea", ""], + ["XMLa", ""], + ["Coare", ""], + ["XMaL", ""], + ["Core", " "], + ["XML", " "], + ["Core", " 1.0"], + ["Core", " 2.0"], + ["Core", " 3.0"], + ["Core", " 100.0"], + ["XML", " 1.0"], + ["XML", " 2.0"], + ["XML", " 3.0"], + ["XML", " 100.0"], + ["Core", "1.0 "], + ["Core", "2.0 "], + ["Core", "3.0 "], + ["Core", "100.0 "], + ["XML", "1.0 "], + ["XML", "2.0 "], + ["XML", "3.0 "], + ["XML", "100.0 "], + ["Core", "1. 0"], + ["Core", "2. 0"], + ["Core", "3. 0"], + ["Core", "100. 0"], + ["XML", "1. 0"], + ["XML", "2. 0"], + ["XML", "3. 0"], + ["XML", "100. 0"], + ["Core", "a1.0"], + ["Core", "a2.0"], + ["Core", "a3.0"], + ["Core", "a100.0"], + ["XML", "a1.0"], + ["XML", "a2.0"], + ["XML", "a3.0"], + ["XML", "a100.0"], + ["Core", "1.0a"], + ["Core", "2.0a"], + ["Core", "3.0a"], + ["Core", "100.0a"], + ["XML", "1.0a"], + ["XML", "2.0a"], + ["XML", "3.0a"], + ["XML", "100.0a"], + ["Core", "1.a0"], + ["Core", "2.a0"], + ["Core", "3.a0"], + ["Core", "100.a0"], + ["XML", "1.a0"], + ["XML", "2.a0"], + ["XML", "3.a0"], + ["XML", "100.a0"], + ["Core", 1], + ["Core", 2], + ["Core", 3], + ["Core", 100], + ["XML", 1], + ["XML", 2], + ["XML", 3], + ["XML", 100], + ["Core", null], + ["XML", null], + ["core", null], + ["xml", null], + ["CoRe", null], + ["XmL", null], + [" Core", null], + [" XML", null], + ["Core ", null], + ["XML ", null], + ["Co re", null], + ["XM L", null], + ["aCore", null], + ["aXML", null], + ["Corea", null], + ["XMLa", null], + ["Coare", null], + ["XMaL", null], + ["Core", undefined], + ["XML", undefined], + ["This is filler text.", ""], + [null, ""], + [undefined, ""], + ["org.w3c.svg", ""], + ["org.w3c.svg", "1.0"], + ["org.w3c.svg", "1.1"], + ["org.w3c.dom.svg", ""], + ["org.w3c.dom.svg", "1.0"], + ["org.w3c.dom.svg", "1.1"], + ["http://www.w3.org/TR/SVG11/feature#Script", "7.5"], + ]; + tests.forEach(function(data) { + test(function() { + assert_equals(document.implementation.hasFeature + .apply(document.implementation, data), true) + }, "hasFeature(" + data.map(format_value).join(", ") + ")") + }) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagName.js b/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagName.js new file mode 100644 index 0000000000..dbbe667ff5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagName.js @@ -0,0 +1,208 @@ +function test_getElementsByTagName(context, element) { + // TODO: getElementsByTagName("*") + test(function() { + assert_false(context.getElementsByTagName("html") instanceof NodeList, + "Should not return a NodeList") + assert_true(context.getElementsByTagName("html") instanceof HTMLCollection, + "Should return an HTMLCollection") + }, "Interfaces") + + test(function() { + var firstCollection = context.getElementsByTagName("html"), + secondCollection = context.getElementsByTagName("html") + assert_true(firstCollection !== secondCollection || + firstCollection === secondCollection) + }, "Caching is allowed") + + test(function() { + var l = context.getElementsByTagName("nosuchtag") + l[5] = "foopy" + assert_equals(l[5], undefined) + assert_equals(l.item(5), null) + }, "Shouldn't be able to set unsigned properties on a HTMLCollection (non-strict mode)") + + test(function() { + var l = context.getElementsByTagName("nosuchtag") + assert_throws_js(TypeError, function() { + "use strict"; + l[5] = "foopy" + }) + assert_equals(l[5], undefined) + assert_equals(l.item(5), null) + }, "Shouldn't be able to set unsigned properties on a HTMLCollection (strict mode)") + + test(function() { + var l = context.getElementsByTagName("nosuchtag") + var fn = l.item; + assert_equals(fn, HTMLCollection.prototype.item); + l.item = "pass" + assert_equals(l.item, "pass") + assert_equals(HTMLCollection.prototype.item, fn); + }, "Should be able to set expando shadowing a proto prop (item)") + + test(function() { + var l = context.getElementsByTagName("nosuchtag") + var fn = l.namedItem; + assert_equals(fn, HTMLCollection.prototype.namedItem); + l.namedItem = "pass" + assert_equals(l.namedItem, "pass") + assert_equals(HTMLCollection.prototype.namedItem, fn); + }, "Should be able to set expando shadowing a proto prop (namedItem)") + + test(function() { + var t1 = element.appendChild(document.createElement("pre")); + t1.id = "x"; + var t2 = element.appendChild(document.createElement("pre")); + t2.setAttribute("name", "y"); + var t3 = element.appendChild(document.createElementNS("", "pre")); + t3.setAttribute("id", "z"); + var t4 = element.appendChild(document.createElementNS("", "pre")); + t4.setAttribute("name", "w"); + this.add_cleanup(function() { + element.removeChild(t1) + element.removeChild(t2) + element.removeChild(t3) + element.removeChild(t4) + }); + + var list = context.getElementsByTagName('pre'); + var pre = list[0]; + assert_equals(pre.id, "x"); + + var exposedNames = { 'x': 0, 'y': 1, 'z': 2 }; + for (var exposedName in exposedNames) { + assert_equals(list[exposedName], list[exposedNames[exposedName]]); + assert_equals(list[exposedName], list.namedItem(exposedName)); + assert_true(exposedName in list, "'" + exposedName + "' in list"); + assert_true(list.hasOwnProperty(exposedName), + "list.hasOwnProperty('" + exposedName + "')"); + } + + var unexposedNames = ["w"]; + for (var unexposedName of unexposedNames) { + assert_false(unexposedName in list); + assert_false(list.hasOwnProperty(unexposedName)); + assert_equals(list[unexposedName], undefined); + assert_equals(list.namedItem(unexposedName), null); + } + + assert_array_equals(Object.getOwnPropertyNames(list).sort(), + ["0", "1", "2", "3", "x", "y", "z"]); + + var desc = Object.getOwnPropertyDescriptor(list, '0'); + assert_equals(typeof desc, "object", "descriptor should be an object"); + assert_true(desc.enumerable, "desc.enumerable"); + assert_true(desc.configurable, "desc.configurable"); + + desc = Object.getOwnPropertyDescriptor(list, 'x'); + assert_equals(typeof desc, "object", "descriptor should be an object"); + assert_false(desc.enumerable, "desc.enumerable"); + assert_true(desc.configurable, "desc.configurable"); + }, "hasOwnProperty, getOwnPropertyDescriptor, getOwnPropertyNames") + + test(function() { + assert_equals(document.createElementNS("http://www.w3.org/1999/xhtml", "i").localName, "i") // Sanity + var t = element.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "I")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_equals(t.localName, "I") + assert_equals(t.tagName, "I") + assert_equals(context.getElementsByTagName("I").length, 0) + assert_equals(context.getElementsByTagName("i").length, 0) + }, "HTML element with uppercase tagName never matches in HTML Documents") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "st")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("st"), [t]) + assert_array_equals(context.getElementsByTagName("ST"), []) + }, "Element in non-HTML namespace, no prefix, lowercase name") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "ST")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("ST"), [t]) + assert_array_equals(context.getElementsByTagName("st"), []) + }, "Element in non-HTML namespace, no prefix, uppercase name") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "te:st")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("st"), []) + assert_array_equals(context.getElementsByTagName("ST"), []) + assert_array_equals(context.getElementsByTagName("te:st"), [t]) + assert_array_equals(context.getElementsByTagName("te:ST"), []) + }, "Element in non-HTML namespace, prefix, lowercase name") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "te:ST")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("st"), []) + assert_array_equals(context.getElementsByTagName("ST"), []) + assert_array_equals(context.getElementsByTagName("te:st"), []) + assert_array_equals(context.getElementsByTagName("te:ST"), [t]) + }, "Element in non-HTML namespace, prefix, uppercase name") + + test(function() { + var t = element.appendChild(document.createElement("aÇ")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_equals(t.localName, "aÇ") + assert_array_equals(context.getElementsByTagName("AÇ"), [t], "All uppercase input") + assert_array_equals(context.getElementsByTagName("aÇ"), [t], "Ascii lowercase input") + assert_array_equals(context.getElementsByTagName("aç"), [], "All lowercase input") + }, "Element in HTML namespace, no prefix, non-ascii characters in name") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "AÇ")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("AÇ"), [t]) + assert_array_equals(context.getElementsByTagName("aÇ"), []) + assert_array_equals(context.getElementsByTagName("aç"), []) + }, "Element in non-HTML namespace, non-ascii characters in name") + + test(function() { + var t = element.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "test:aÇ")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("TEST:AÇ"), [t], "All uppercase input") + assert_array_equals(context.getElementsByTagName("test:aÇ"), [t], "Ascii lowercase input") + assert_array_equals(context.getElementsByTagName("test:aç"), [], "All lowercase input") + }, "Element in HTML namespace, prefix, non-ascii characters in name") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "TEST:AÇ")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagName("TEST:AÇ"), [t], "All uppercase input") + assert_array_equals(context.getElementsByTagName("test:aÇ"), [], "Ascii lowercase input") + assert_array_equals(context.getElementsByTagName("test:aç"), [], "All lowercase input") + }, "Element in non-HTML namespace, prefix, non-ascii characters in name") + + test(function() { + var actual = context.getElementsByTagName("*"); + var expected = []; + var get_elements = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + if (child.nodeType === child.ELEMENT_NODE) { + expected.push(child); + get_elements(child); + } + } + } + get_elements(context); + assert_array_equals(actual, expected); + }, "getElementsByTagName('*')") + + test(function() { + var t1 = element.appendChild(document.createElement("abc")); + this.add_cleanup(function() {element.removeChild(t1)}); + + var l = context.getElementsByTagName("abc"); + assert_true(l instanceof HTMLCollection); + assert_equals(l.length, 1); + + var t2 = element.appendChild(document.createElement("abc")); + assert_equals(l.length, 2); + + element.removeChild(t2); + assert_equals(l.length, 1); + }, "getElementsByTagName() should be a live collection"); +} diff --git a/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagNameNS.js b/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagNameNS.js new file mode 100644 index 0000000000..b610c49d86 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-Element-getElementsByTagNameNS.js @@ -0,0 +1,143 @@ +function test_getElementsByTagNameNS(context, element) { + test(function() { + assert_false(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "html") instanceof NodeList, "NodeList") + assert_true(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "html") instanceof HTMLCollection, "HTMLCollection") + var firstCollection = context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "html"), + secondCollection = context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "html") + assert_true(firstCollection !== secondCollection || firstCollection === secondCollection, + "Caching is allowed.") + }) + + test(function() { + var t = element.appendChild(document.createElementNS("test", "body")) + this.add_cleanup(function() {element.removeChild(t)}) + var actual = context.getElementsByTagNameNS("*", "body"); + var expected = []; + var get_elements = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + if (child.nodeType === child.ELEMENT_NODE) { + if (child.localName == "body") { + expected.push(child); + } + get_elements(child); + } + } + } + get_elements(context); + assert_array_equals(actual, expected); + }, "getElementsByTagNameNS('*', 'body')") + + test(function() { + assert_array_equals(context.getElementsByTagNameNS("", "*"), []); + var t = element.appendChild(document.createElementNS("", "body")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("", "*"), [t]); + }, "Empty string namespace") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "body")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("test", "body"), [t]); + }, "body element in test namespace, no prefix") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "test:body")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("test", "body"), [t]); + }, "body element in test namespace, prefix") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "BODY")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("test", "BODY"), [t]); + assert_array_equals(context.getElementsByTagNameNS("test", "body"), []); + }, "BODY element in test namespace, no prefix") + + test(function() { + var t = element.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "abc")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "abc"), [t]); + assert_array_equals(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "ABC"), []); + assert_array_equals(context.getElementsByTagNameNS("test", "ABC"), []); + }, "abc element in html namespace") + + test(function() { + var t = element.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "ABC")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "abc"), []); + assert_array_equals(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "ABC"), [t]); + }, "ABC element in html namespace") + + test(function() { + var t = element.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "AÇ")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "AÇ"), [t]); + assert_array_equals(context.getElementsByTagNameNS("test", "aÇ"), []); + assert_array_equals(context.getElementsByTagNameNS("test", "aç"), []); + }, "AÇ, case sensitivity") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "test:BODY")) + this.add_cleanup(function() {element.removeChild(t)}) + assert_array_equals(context.getElementsByTagNameNS("test", "BODY"), [t]); + assert_array_equals(context.getElementsByTagNameNS("test", "body"), []); + }, "BODY element in test namespace, prefix") + + test(function() { + var t = element.appendChild(document.createElementNS("test", "test:test")) + this.add_cleanup(function() {element.removeChild(t)}) + var actual = context.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "*"); + var expected = []; + var get_elements = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + if (child.nodeType === child.ELEMENT_NODE) { + if (child !== t) { + expected.push(child); + } + get_elements(child); + } + } + } + get_elements(context); + assert_array_equals(actual, expected); + }, "getElementsByTagNameNS('http://www.w3.org/1999/xhtml', '*')") + + test(function() { + var actual = context.getElementsByTagNameNS("*", "*"); + var expected = []; + var get_elements = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + if (child.nodeType === child.ELEMENT_NODE) { + expected.push(child); + get_elements(child); + } + } + } + get_elements(context); + assert_array_equals(actual, expected); + }, "getElementsByTagNameNS('*', '*')") + + test(function() { + assert_array_equals(context.getElementsByTagNameNS("**", "*"), []); + assert_array_equals(context.getElementsByTagNameNS(null, "0"), []); + assert_array_equals(context.getElementsByTagNameNS(null, "div"), []); + }, "Empty lists") + + test(function() { + var t1 = element.appendChild(document.createElementNS("test", "abc")); + this.add_cleanup(function() {element.removeChild(t1)}); + + var l = context.getElementsByTagNameNS("test", "abc"); + assert_true(l instanceof HTMLCollection); + assert_equals(l.length, 1); + + var t2 = element.appendChild(document.createElementNS("test", "abc")); + assert_equals(l.length, 2); + + element.removeChild(t2); + assert_equals(l.length, 1); + }, "getElementsByTagNameNS() should be a live collection"); +} diff --git a/testing/web-platform/tests/dom/nodes/Document-URL.html b/testing/web-platform/tests/dom/nodes/Document-URL.html new file mode 100644 index 0000000000..242def1fb3 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-URL.html @@ -0,0 +1,18 @@ +<!doctype html> +<meta charset=utf-8> +<title>Document.URL with redirect</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.src = "/common/redirect.py?location=/common/blank.html"; + document.body.appendChild(iframe); + this.add_cleanup(function() { document.body.removeChild(iframe); }); + iframe.onload = this.step_func_done(function() { + assert_equals(iframe.contentDocument.URL, + location.origin + "/common/blank.html"); + }); +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-adoptNode.html b/testing/web-platform/tests/dom/nodes/Document-adoptNode.html new file mode 100644 index 0000000000..60a4e6772a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-adoptNode.html @@ -0,0 +1,50 @@ +<!doctype html> +<meta charset=utf-8> +<title>Document.adoptNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-adoptnode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<!--creates an element with local name "x<": --><x<>x</x<> +<script> +test(function() { + var y = document.getElementsByTagName("x<")[0] + var child = y.firstChild + assert_equals(y.parentNode, document.body) + assert_equals(y.ownerDocument, document) + assert_equals(document.adoptNode(y), y) + assert_equals(y.parentNode, null) + assert_equals(y.firstChild, child) + assert_equals(y.ownerDocument, document) + assert_equals(child.ownerDocument, document) + var doc = document.implementation.createDocument(null, null, null) + assert_equals(doc.adoptNode(y), y) + assert_equals(y.parentNode, null) + assert_equals(y.firstChild, child) + assert_equals(y.ownerDocument, doc) + assert_equals(child.ownerDocument, doc) +}, "Adopting an Element called 'x<' should work.") + +test(function() { + var x = document.createElement(":good:times:") + assert_equals(document.adoptNode(x), x); + var doc = document.implementation.createDocument(null, null, null) + assert_equals(doc.adoptNode(x), x) + assert_equals(x.parentNode, null) + assert_equals(x.ownerDocument, doc) +}, "Adopting an Element called ':good:times:' should work.") + +test(function() { + var doctype = document.doctype; + assert_equals(doctype.parentNode, document) + assert_equals(doctype.ownerDocument, document) + assert_equals(document.adoptNode(doctype), doctype) + assert_equals(doctype.parentNode, null) + assert_equals(doctype.ownerDocument, document) +}, "Explicitly adopting a DocumentType should work.") + +test(function() { + var doc = document.implementation.createDocument(null, null, null) + assert_throws_dom("NOT_SUPPORTED_ERR", function() { document.adoptNode(doc) }) +}, "Adopting a Document should throw.") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-1.html b/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-1.html new file mode 100644 index 0000000000..0facd50e49 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-1.html @@ -0,0 +1,157 @@ +<!doctype html> +<title>document.characterSet (inputEncoding and charset as aliases) normalization tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="./characterset-helper.js"></script> +<style>iframe { display: none }</style> +<script> +"use strict"; + +// Taken straight from https://encoding.spec.whatwg.org/ +var encodingMap = { + "UTF-8": [ + "unicode-1-1-utf-8", + "utf-8", + "utf8", + // As we use <meta>, utf-16 will map to utf-8 per + // https://html.spec.whatwg.org/multipage/#documentEncoding + "utf-16", + "utf-16le", + "utf-16be", + ], + "IBM866": [ + "866", + "cp866", + "csibm866", + "ibm866", + ], + "ISO-8859-2": [ + "csisolatin2", + "iso-8859-2", + "iso-ir-101", + "iso8859-2", + "iso88592", + "iso_8859-2", + "iso_8859-2:1987", + "l2", + "latin2", + ], + "ISO-8859-3": [ + "csisolatin3", + "iso-8859-3", + "iso-ir-109", + "iso8859-3", + "iso88593", + "iso_8859-3", + "iso_8859-3:1988", + "l3", + "latin3", + ], + "ISO-8859-4": [ + "csisolatin4", + "iso-8859-4", + "iso-ir-110", + "iso8859-4", + "iso88594", + "iso_8859-4", + "iso_8859-4:1988", + "l4", + "latin4", + ], + "ISO-8859-5": [ + "csisolatincyrillic", + "cyrillic", + "iso-8859-5", + "iso-ir-144", + "iso8859-5", + "iso88595", + "iso_8859-5", + "iso_8859-5:1988", + ], + "ISO-8859-6": [ + "arabic", + "asmo-708", + "csiso88596e", + "csiso88596i", + "csisolatinarabic", + "ecma-114", + "iso-8859-6", + "iso-8859-6-e", + "iso-8859-6-i", + "iso-ir-127", + "iso8859-6", + "iso88596", + "iso_8859-6", + "iso_8859-6:1987", + ], + "ISO-8859-7": [ + "csisolatingreek", + "ecma-118", + "elot_928", + "greek", + "greek8", + "iso-8859-7", + "iso-ir-126", + "iso8859-7", + "iso88597", + "iso_8859-7", + "iso_8859-7:1987", + "sun_eu_greek", + ], + "ISO-8859-8": [ + "csiso88598e", + "csisolatinhebrew", + "hebrew", + "iso-8859-8", + "iso-8859-8-e", + "iso-ir-138", + "iso8859-8", + "iso88598", + "iso_8859-8", + "iso_8859-8:1988", + "visual", + ], + "ISO-8859-8-I": [ + "csiso88598i", + "iso-8859-8-i", + "logical", + ], + "ISO-8859-10": [ + "csisolatin6", + "iso-8859-10", + "iso-ir-157", + "iso8859-10", + "iso885910", + "l6", + "latin6", + ], + "ISO-8859-13": [ + "iso-8859-13", + "iso8859-13", + "iso885913", + ], + "ISO-8859-14": [ + "iso-8859-14", + "iso8859-14", + "iso885914", + ], + "ISO-8859-15": [ + "csisolatin9", + "iso-8859-15", + "iso8859-15", + "iso885915", + "iso_8859-15", + "l9", + ], + "ISO-8859-16": [ + "iso-8859-16", + ], +}; + +runCharacterSetTests(encodingMap); + +</script> +<!-- vim: set expandtab tabstop=2 shiftwidth=2: --> diff --git a/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-2.html b/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-2.html new file mode 100644 index 0000000000..7c7691bdc1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-characterSet-normalization-2.html @@ -0,0 +1,179 @@ +<!doctype html> +<title>document.characterSet (inputEncoding and charset as aliases) normalization tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="./characterset-helper.js"></script> +<style>iframe { display: none }</style> +<script> +"use strict"; + +// Taken straight from https://encoding.spec.whatwg.org/ +var encodingMap = { + "KOI8-R": [ + "cskoi8r", + "koi", + "koi8", + "koi8-r", + "koi8_r", + ], + "KOI8-U": [ + "koi8-ru", + "koi8-u", + ], + "macintosh": [ + "csmacintosh", + "mac", + "macintosh", + "x-mac-roman", + ], + "windows-874": [ + "dos-874", + "iso-8859-11", + "iso8859-11", + "iso885911", + "tis-620", + "windows-874", + ], + "windows-1250": [ + "cp1250", + "windows-1250", + "x-cp1250", + ], + "windows-1251": [ + "cp1251", + "windows-1251", + "x-cp1251", + ], + "windows-1252": [ + "ansi_x3.4-1968", + "ascii", + "cp1252", + "cp819", + "csisolatin1", + "ibm819", + "iso-8859-1", + "iso-ir-100", + "iso8859-1", + "iso88591", + "iso_8859-1", + "iso_8859-1:1987", + "l1", + "latin1", + "us-ascii", + "windows-1252", + "x-cp1252", + // As we use <meta>, x-user-defined will map to windows-1252 per + // https://html.spec.whatwg.org/multipage/#documentEncoding + "x-user-defined" + ], + "windows-1253": [ + "cp1253", + "windows-1253", + "x-cp1253", + ], + "windows-1254": [ + "cp1254", + "csisolatin5", + "iso-8859-9", + "iso-ir-148", + "iso8859-9", + "iso88599", + "iso_8859-9", + "iso_8859-9:1989", + "l5", + "latin5", + "windows-1254", + "x-cp1254", + ], + "windows-1255": [ + "cp1255", + "windows-1255", + "x-cp1255", + ], + "windows-1256": [ + "cp1256", + "windows-1256", + "x-cp1256", + ], + "windows-1257": [ + "cp1257", + "windows-1257", + "x-cp1257", + ], + "windows-1258": [ + "cp1258", + "windows-1258", + "x-cp1258", + ], + "x-mac-cyrillic": [ + "x-mac-cyrillic", + "x-mac-ukrainian", + ], + "GBK": [ + "chinese", + "csgb2312", + "csiso58gb231280", + "gb2312", + "gb_2312", + "gb_2312-80", + "gbk", + "iso-ir-58", + "x-gbk", + ], + "gb18030": [ + "gb18030", + ], + "Big5": [ + "big5", + "big5-hkscs", + "cn-big5", + "csbig5", + "x-x-big5", + ], + "EUC-JP": [ + "cseucpkdfmtjapanese", + "euc-jp", + "x-euc-jp", + ], + "ISO-2022-JP": [ + "csiso2022jp", + "iso-2022-jp", + ], + "Shift_JIS": [ + "csshiftjis", + "ms932", + "ms_kanji", + "shift-jis", + "shift_jis", + "sjis", + "windows-31j", + "x-sjis", + ], + "EUC-KR": [ + "cseuckr", + "csksc56011987", + "euc-kr", + "iso-ir-149", + "korean", + "ks_c_5601-1987", + "ks_c_5601-1989", + "ksc5601", + "ksc_5601", + "windows-949", + ], + "replacement": [ + "csiso2022kr", + "hz-gb-2312", + "iso-2022-cn", + "iso-2022-cn-ext", + "iso-2022-kr", + ], +}; + +runCharacterSetTests(encodingMap); + +</script> +<!-- vim: set expandtab tabstop=2 shiftwidth=2: --> diff --git a/testing/web-platform/tests/dom/nodes/Document-constructor-svg.svg b/testing/web-platform/tests/dom/nodes/Document-constructor-svg.svg new file mode 100644 index 0000000000..77e3d8996e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-constructor-svg.svg @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="windows-1252"?> +<!-- Using windows-1252 to ensure that new Document() doesn't inherit utf-8 + from the parent document. --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml" + width="100%" height="100%" viewBox="0 0 800 600"> +<title>Document constructor</title> +<html:script src="/resources/testharness.js"></html:script> +<html:script src="/resources/testharnessreport.js"></html:script> +<html:script><![CDATA[ +test(function() { + var doc = new Document(); + assert_true(doc instanceof Node, "Should be a Node"); + assert_true(doc instanceof Document, "Should be a Document"); + assert_false(doc instanceof XMLDocument, "Should not be an XMLDocument"); + assert_equals(Object.getPrototypeOf(doc), Document.prototype, + "Document should be the primary interface"); +}, "new Document(): interfaces") + +test(function() { + var doc = new Document(); + assert_equals(doc.firstChild, null, "firstChild"); + assert_equals(doc.lastChild, null, "lastChild"); + assert_equals(doc.doctype, null, "doctype"); + assert_equals(doc.documentElement, null, "documentElement"); + assert_array_equals(doc.childNodes, [], "childNodes"); +}, "new Document(): children") + +test(function() { + var doc = new Document(); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.documentURI, "about:blank"); + assert_equals(doc.compatMode, "CSS1Compat"); + assert_equals(doc.characterSet, "UTF-8"); + assert_equals(doc.contentType, "application/xml"); + assert_equals(doc.createElement("DIV").localName, "DIV"); +}, "new Document(): metadata") + +test(function() { + var doc = new Document(); + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); +}, "new Document(): characterSet aliases") +]]></html:script> +</svg> + diff --git a/testing/web-platform/tests/dom/nodes/Document-constructor-xml.xml b/testing/web-platform/tests/dom/nodes/Document-constructor-xml.xml new file mode 100644 index 0000000000..c9fc775806 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-constructor-xml.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="windows-1252"?> +<!-- Using windows-1252 to ensure that new Document() doesn't inherit utf-8 + from the parent document. --> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Document constructor</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-document" /> +</head> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script><![CDATA[ +test(function() { + var doc = new Document(); + assert_true(doc instanceof Node, "Should be a Node"); + assert_true(doc instanceof Document, "Should be a Document"); + assert_false(doc instanceof XMLDocument, "Should not be an XMLDocument"); + assert_equals(Object.getPrototypeOf(doc), Document.prototype, + "Document should be the primary interface"); +}, "new Document(): interfaces") + +test(function() { + var doc = new Document(); + assert_equals(doc.firstChild, null, "firstChild"); + assert_equals(doc.lastChild, null, "lastChild"); + assert_equals(doc.doctype, null, "doctype"); + assert_equals(doc.documentElement, null, "documentElement"); + assert_array_equals(doc.childNodes, [], "childNodes"); +}, "new Document(): children") + +test(function() { + var doc = new Document(); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.documentURI, "about:blank"); + assert_equals(doc.compatMode, "CSS1Compat"); + assert_equals(doc.characterSet, "UTF-8"); + assert_equals(doc.contentType, "application/xml"); + assert_equals(doc.createElement("DIV").localName, "DIV"); +}, "new Document(): metadata") + +test(function() { + var doc = new Document(); + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); +}, "new Document(): characterSet aliases") +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-constructor.html b/testing/web-platform/tests/dom/nodes/Document-constructor.html new file mode 100644 index 0000000000..e17de28471 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-constructor.html @@ -0,0 +1,56 @@ +<!doctype html> +<meta charset=windows-1252> +<!-- Using windows-1252 to ensure that new Document() doesn't inherit utf-8 + from the parent document. --> +<title>Document constructor</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var doc = new Document(); + assert_true(doc instanceof Node, "Should be a Node"); + assert_true(doc instanceof Document, "Should be a Document"); + assert_false(doc instanceof XMLDocument, "Should not be an XMLDocument"); + assert_equals(Object.getPrototypeOf(doc), Document.prototype, + "Document should be the primary interface"); +}, "new Document(): interfaces") + +test(function() { + var doc = new Document(); + assert_equals(doc.firstChild, null, "firstChild"); + assert_equals(doc.lastChild, null, "lastChild"); + assert_equals(doc.doctype, null, "doctype"); + assert_equals(doc.documentElement, null, "documentElement"); + assert_array_equals(doc.childNodes, [], "childNodes"); +}, "new Document(): children") + +test(function() { + var doc = new Document(); + assert_equals(doc.location, null); + assert_equals(doc.URL, "about:blank"); + assert_equals(doc.documentURI, "about:blank"); + assert_equals(doc.compatMode, "CSS1Compat"); + assert_equals(doc.characterSet, "UTF-8"); + assert_equals(doc.contentType, "application/xml"); + assert_equals(doc.createElement("DIV").localName, "DIV"); + assert_equals(doc.createElement("a").constructor, Element); +}, "new Document(): metadata") + +test(function() { + var doc = new Document(); + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); +}, "new Document(): characterSet aliases") + +test(function() { + var doc = new Document(); + var a = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); + assert_equals(a.constructor, HTMLAnchorElement); + // In UTF-8: 0xC3 0xA4 + a.href = "http://example.org/?\u00E4"; + assert_equals(a.href, "http://example.org/?%C3%A4"); +}, "new Document(): URL parsing") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_bmp.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_bmp.html new file mode 100644 index 0000000000..8286437416 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_bmp.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>BMP document.contentType === 'image/bmp'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "image/bmp"); + }), false); + iframe.src = "../resources/t.bmp"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_css.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_css.html new file mode 100644 index 0000000000..0eb35edd5e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_css.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>CSS document.contentType === 'text/css'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/css"); + }), false); + iframe.src = "../resources/style.css"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_datauri_02.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_datauri_02.html new file mode 100644 index 0000000000..c124cb3979 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_datauri_02.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Data URI document.contentType === 'text/html' when data URI MIME type is set</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + self.onmessage = this.step_func_done(e => { + assert_equals(e.data, "text/html"); + }); + iframe.src = "data:text/html;charset=utf-8,<!DOCTYPE html><script>parent.postMessage(document.contentType,'*')<\/script>"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_gif.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_gif.html new file mode 100644 index 0000000000..8dd66dae59 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_gif.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>GIF document.contentType === 'image/gif'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "image/gif"); + }), false); + iframe.src = "../resources/t.gif"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_html.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_html.html new file mode 100644 index 0000000000..2b2d7263eb --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_html.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>HTM document.contentType === 'text/html'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/html"); + }), false); + iframe.src = "../resources/blob.htm"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_javascripturi.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_javascripturi.html new file mode 100644 index 0000000000..956589615a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_javascripturi.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<title>Javascript URI document.contentType === 'text/html'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/html"); + assert_equals(iframe.contentDocument.documentElement.textContent, "text/html"); + }), false); + iframe.src = "javascript:document.contentType"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_jpg.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_jpg.html new file mode 100644 index 0000000000..13f57ec8b9 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_jpg.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>JPG document.contentType === 'image/jpeg'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "image/jpeg"); + }), false); + iframe.src = "../resources/t.jpg"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_01.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_01.html new file mode 100644 index 0000000000..87885efba6 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_01.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Custom document.contentType === 'text/xml' when explicitly set to this value</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/xml"); + }), false); + iframe.src = "../support/contenttype_setter.py?type=text&subtype=xml"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_02.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_02.html new file mode 100644 index 0000000000..33870147fc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_mimeheader_02.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>Custom document.contentType === 'text/html' when explicitly set to this value and an attempt is made to override this value in an HTML meta header</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/html"); + }), false); + iframe.src = "../support/contenttype_setter.py?type=text&subtype=html&mimeHead=text%2Fxml"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_png.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_png.html new file mode 100644 index 0000000000..a214ad3e98 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_png.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>PNG document.contentType === 'image/png'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "image/png"); + }), false); + iframe.src = "../resources/t.png"; + document.body.appendChild(iframe); +}); +</script>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_txt.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_txt.html new file mode 100644 index 0000000000..f40f641fb0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_txt.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>TXT document.contentType === 'text/plain'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "text/plain"); + }), false); + iframe.src = "../resources/blob.txt"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_xml.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_xml.html new file mode 100644 index 0000000000..c382de8490 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/contenttype_xml.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>XML document.contentType === 'application/xml'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement('iframe'); + iframe.addEventListener('load', this.step_func_done(function() { + assert_equals(iframe.contentDocument.contentType, "application/xml"); + }), false); + iframe.src = "../resources/blob.xml"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createDocument.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createDocument.html new file mode 100644 index 0000000000..78a952de4a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createDocument.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>document.implementation.createDocument: document.contentType === 'application/xhtml+xml'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null); + assert_equals(doc.contentType, "application/xhtml+xml"); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createHTMLDocument.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createHTMLDocument.html new file mode 100644 index 0000000000..185e3c8c92 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/createHTMLDocument.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>document.implementation.createHTMLDocument: document.contentType === 'text/html'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var doc = document.implementation.createHTMLDocument("test"); + assert_equals(doc.contentType, "text/html"); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/xhr_responseType_document.html b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/xhr_responseType_document.html new file mode 100644 index 0000000000..c2fb6c19fd --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/contentType/xhr_responseType_document.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>XHR - retrieve HTML document: document.contentType === 'application/xml'</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "../resources/blob.xml"); + xhr.responseType = "document"; + xhr.onload = this.step_func_done(function(response) { + assert_equals(xhr.readyState, 4); + assert_equals(xhr.status, 200); + assert_equals(xhr.responseXML.contentType, "application/xml"); + }); + xhr.send(null); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.htm b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.htm new file mode 100644 index 0000000000..9d235ed07c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.htm @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.txt b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.txt new file mode 100644 index 0000000000..9d235ed07c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.txt @@ -0,0 +1 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.xml b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.xml new file mode 100644 index 0000000000..0922ed14b8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/blob.xml @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<blob>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</blob>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/lib.js b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/lib.js new file mode 100644 index 0000000000..c41d336c08 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/lib.js @@ -0,0 +1 @@ +var t;
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/style.css b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/style.css new file mode 100644 index 0000000000..bb4ff575b7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/style.css @@ -0,0 +1,12 @@ +.unknown +{ + background-color:lightblue; +} +.pass +{ + background-color:lime; +} +.fail +{ + background-color:red; +} diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.bmp b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.bmp Binary files differnew file mode 100644 index 0000000000..5697c0aef4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.bmp diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.gif b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.gif Binary files differnew file mode 100644 index 0000000000..91f269207a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.gif diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.jpg b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.jpg Binary files differnew file mode 100644 index 0000000000..72b51899e4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.jpg diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.png b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.png Binary files differnew file mode 100644 index 0000000000..447d9e3012 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/resources/t.png diff --git a/testing/web-platform/tests/dom/nodes/Document-contentType/support/contenttype_setter.py b/testing/web-platform/tests/dom/nodes/Document-contentType/support/contenttype_setter.py new file mode 100644 index 0000000000..c4b1f8df27 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-contentType/support/contenttype_setter.py @@ -0,0 +1,20 @@ +def main(request, response): + type = request.GET.first(b"type", None) + subtype = request.GET.first(b"subtype", None) + if type and subtype: + response.headers[b"Content-Type"] = type + b"/" + subtype + + removeContentType = request.GET.first(b"removeContentType", None) + if removeContentType: + try: + del response.headers[b"Content-Type"] + except KeyError: + pass + + content = b'<head>' + mimeHead = request.GET.first(b"mime", None); + if mimeHead: + content += b'<meta http-equiv="Content-Type" content="%s; charset=utf-8"/>' % mimeHead + content += b"</head>" + + return content diff --git a/testing/web-platform/tests/dom/nodes/Document-createAttribute.html b/testing/web-platform/tests/dom/nodes/Document-createAttribute.html new file mode 100644 index 0000000000..b3dc8b60b9 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createAttribute.html @@ -0,0 +1,55 @@ +<!doctype html> +<meta charset=utf-8> +<title>Document.createAttribute</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=attributes.js></script> +<script src=productions.js></script> +<div id=log> +<script> +var xml_document; +setup(function() { + xml_document = document.implementation.createDocument(null, null, null); +}); + +invalid_names.forEach(function(name) { + test(function() { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + document.createAttribute(name, "test"); + }); + }, "HTML document.createAttribute(" + format_value(name) + ") should throw"); + + test(function() { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + xml_document.createAttribute(name, "test"); + }); + }, "XML document.createAttribute(" + format_value(name) + ") should throw"); +}); + +valid_names.forEach(name => { + test(() => { + let attr = document.createAttribute(name); + attr_is(attr, "", name.toLowerCase(), null, null, name.toLowerCase()); + }, `HTML document.createAttribute(${format_value(name)})`); + + test(() => { + let attr = xml_document.createAttribute(name); + attr_is(attr, "", name, null, null, name); + }, `XML document.createAttribute(${format_value(name)})`); +}); + +var tests = ["title", "TITLE", null, undefined]; +tests.forEach(function(name) { + test(function() { + var attribute = document.createAttribute(name); + attr_is(attribute, "", String(name).toLowerCase(), null, null, String(name).toLowerCase()); + assert_equals(attribute.ownerElement, null); + }, "HTML document.createAttribute(" + format_value(name) + ")"); + + test(function() { + var attribute = xml_document.createAttribute(name); + attr_is(attribute, "", String(name), null, null, String(name)); + assert_equals(attribute.ownerElement, null); + }, "XML document.createAttribute(" + format_value(name) + ")"); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createCDATASection-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createCDATASection-xhtml.xhtml new file mode 100644 index 0000000000..b0a5a7f284 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createCDATASection-xhtml.xhtml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"/> + <title>document.createCDATASection</title> + <link rel="help" href="https://dom.spec.whatwg.org/#dom-document-createcdatasection"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="Document-createComment-createTextNode.js"></script> +</head> + +<body> + <script> + "use strict"; + test_create("createCDATASection", CDATASection, 4, "#cdata-section"); + + test(() => { + assert_throws_dom("InvalidCharacterError", () => document.createCDATASection(" ]" + "]> ")); + }, "Creating a CDATA section containing the string \"]" + "]>\" must throw"); + </script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createCDATASection.html b/testing/web-platform/tests/dom/nodes/Document-createCDATASection.html new file mode 100644 index 0000000000..72b3684c75 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createCDATASection.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>document.createCDATASection must throw in HTML documents</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-createcdatasection"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +setup({ single_test: true }); + +assert_throws_dom("NotSupportedError", () => document.createCDATASection("foo")); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createComment-createTextNode.js b/testing/web-platform/tests/dom/nodes/Document-createComment-createTextNode.js new file mode 100644 index 0000000000..62a38d380d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createComment-createTextNode.js @@ -0,0 +1,22 @@ +function test_create(method, iface, nodeType, nodeName) { + ["\u000b", "a -- b", "a-", "-b", null, undefined].forEach(function(value) { + test(function() { + var c = document[method](value); + var expected = String(value); + assert_true(c instanceof iface); + assert_true(c instanceof CharacterData); + assert_true(c instanceof Node); + assert_equals(c.ownerDocument, document); + assert_equals(c.data, expected, "data"); + assert_equals(c.nodeValue, expected, "nodeValue"); + assert_equals(c.textContent, expected, "textContent"); + assert_equals(c.length, expected.length); + assert_equals(c.nodeType, nodeType); + assert_equals(c.nodeName, nodeName); + assert_equals(c.hasChildNodes(), false); + assert_equals(c.childNodes.length, 0); + assert_equals(c.firstChild, null); + assert_equals(c.lastChild, null); + }, method + "(" + format_value(value) + ")"); + }); +} diff --git a/testing/web-platform/tests/dom/nodes/Document-createComment.html b/testing/web-platform/tests/dom/nodes/Document-createComment.html new file mode 100644 index 0000000000..a175c3a2f8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createComment.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createComment</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createcomment"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-ownerdocument"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodevalue"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-textcontent"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-length"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodetype"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-haschildnodes"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-childnodes"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-firstchild"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-lastchild"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-createComment-createTextNode.js"></script> +<div id="log"></div> +<script> +test_create("createComment", Comment, 8, "#comment"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html new file mode 100644 index 0000000000..b80a99a784 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.html @@ -0,0 +1 @@ +<math></math>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg new file mode 100644 index 0000000000..b80a99a784 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.svg @@ -0,0 +1 @@ +<math></math>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml new file mode 100644 index 0000000000..b80a99a784 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xhtml @@ -0,0 +1 @@ +<math></math>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml new file mode 100644 index 0000000000..b80a99a784 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_mathml.xml @@ -0,0 +1 @@ +<math></math>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.html new file mode 100644 index 0000000000..dc1ced5b6b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.html @@ -0,0 +1 @@ +<svg></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg new file mode 100644 index 0000000000..dc1ced5b6b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.svg @@ -0,0 +1 @@ +<svg></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml new file mode 100644 index 0000000000..dc1ced5b6b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xhtml @@ -0,0 +1 @@ +<svg></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml new file mode 100644 index 0000000000..dc1ced5b6b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_svg.xml @@ -0,0 +1 @@ +<svg></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html new file mode 100644 index 0000000000..6c70bcfe4d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.html @@ -0,0 +1 @@ +<html></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg new file mode 100644 index 0000000000..6c70bcfe4d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.svg @@ -0,0 +1 @@ +<html></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml new file mode 100644 index 0000000000..6c70bcfe4d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xhtml @@ -0,0 +1 @@ +<html></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml new file mode 100644 index 0000000000..6c70bcfe4d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/bare_xhtml.xml @@ -0,0 +1 @@ +<html></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.html new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.html diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.svg new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.svg diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xhtml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xhtml diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/empty.xml diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/generate.py b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/generate.py new file mode 100755 index 0000000000..a0bca546c7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/generate.py @@ -0,0 +1,80 @@ +#!/usr/bin/python + +from __future__ import print_function + +import os +import sys + +THIS_NAME = u"generate.py" + +# Note: these lists must be kept in sync with the lists in +# Document-createElement-namespace.html, and this script must be run whenever +# the lists are updated. (We could keep the lists in a shared JSON file, but +# seems like too much effort.) +FILES = ( + (u"empty", u""), + (u"minimal_html", u"<!doctype html><title></title>"), + + (u"xhtml", u'<html xmlns="http://www.w3.org/1999/xhtml"></html>'), + (u"svg", u'<svg xmlns="http://www.w3.org/2000/svg"></svg>'), + (u"mathml", u'<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>'), + + (u"bare_xhtml", u"<html></html>"), + (u"bare_svg", u"<svg></svg>"), + (u"bare_mathml", u"<math></math>"), + + (u"xhtml_ns_removed", u"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS(null, "html"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> +"""), + (u"xhtml_ns_changed", u"""\ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> +"""), +) + +EXTENSIONS = ( + u"html", + u"xhtml", + u"xml", + u"svg", + # Was not able to get server MIME type working properly :( + #"mml", +) + +def __main__(): + if len(sys.argv) > 1: + print(u"No arguments expected, aborting") + return + + if not os.access(THIS_NAME, os.F_OK): + print(u"Must be run from the directory of " + THIS_NAME + u", aborting") + return + + for name in os.listdir(u"."): + if name == THIS_NAME: + continue + os.remove(name) + + manifest = open(u"MANIFEST", u"w") + + for name, contents in FILES: + for extension in EXTENSIONS: + f = open(name + u"." + extension, u"w") + f.write(contents) + f.close() + manifest.write(u"support " + name + u"." + extension + u"\n") + + manifest.close() + +__main__() diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.html new file mode 100644 index 0000000000..0bec8e99e4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.html @@ -0,0 +1 @@ +<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.svg new file mode 100644 index 0000000000..0bec8e99e4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.svg @@ -0,0 +1 @@ +<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml new file mode 100644 index 0000000000..0bec8e99e4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xhtml @@ -0,0 +1 @@ +<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xml new file mode 100644 index 0000000000..0bec8e99e4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/mathml.xml @@ -0,0 +1 @@ +<mathml xmlns="http://www.w3.org/1998/Math/MathML"></mathml>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.html new file mode 100644 index 0000000000..a33d9859af --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.html @@ -0,0 +1 @@ +<!doctype html><title></title>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg new file mode 100644 index 0000000000..a33d9859af --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.svg @@ -0,0 +1 @@ +<!doctype html><title></title>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml new file mode 100644 index 0000000000..a33d9859af --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xhtml @@ -0,0 +1 @@ +<!doctype html><title></title>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml new file mode 100644 index 0000000000..a33d9859af --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/minimal_html.xml @@ -0,0 +1 @@ +<!doctype html><title></title>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.html new file mode 100644 index 0000000000..64def4af7f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.html @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg"></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.svg new file mode 100644 index 0000000000..64def4af7f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg"></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xhtml new file mode 100644 index 0000000000..64def4af7f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xhtml @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg"></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xml new file mode 100644 index 0000000000..64def4af7f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/svg.xml @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg"></svg>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.html new file mode 100644 index 0000000000..1cba998241 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.html @@ -0,0 +1 @@ +<html xmlns="http://www.w3.org/1999/xhtml"></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.svg new file mode 100644 index 0000000000..1cba998241 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.svg @@ -0,0 +1 @@ +<html xmlns="http://www.w3.org/1999/xhtml"></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml new file mode 100644 index 0000000000..1cba998241 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xhtml @@ -0,0 +1 @@ +<html xmlns="http://www.w3.org/1999/xhtml"></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xml new file mode 100644 index 0000000000..1cba998241 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml.xml @@ -0,0 +1 @@ +<html xmlns="http://www.w3.org/1999/xhtml"></html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html new file mode 100644 index 0000000000..b228c7f740 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.html @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg new file mode 100644 index 0000000000..b228c7f740 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.svg @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml new file mode 100644 index 0000000000..b228c7f740 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xhtml @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml new file mode 100644 index 0000000000..b228c7f740 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_changed.xml @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS("http://www.w3.org/2000/svg", "abc"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html new file mode 100644 index 0000000000..dba395fed0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.html @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS(null, "html"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg new file mode 100644 index 0000000000..dba395fed0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.svg @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS(null, "html"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml new file mode 100644 index 0000000000..dba395fed0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xhtml @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS(null, "html"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml new file mode 100644 index 0000000000..dba395fed0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace-tests/xhtml_ns_removed.xml @@ -0,0 +1,7 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head><script> + var newRoot = document.createElementNS(null, "html"); + document.removeChild(document.documentElement); + document.appendChild(newRoot); + </script></head> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement-namespace.html b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace.html new file mode 100644 index 0000000000..cea61f1aec --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement-namespace.html @@ -0,0 +1,117 @@ +<!doctype html> +<title>document.createElement() namespace tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; +/** + * This tests the namespace of elements created by the Document interface's + * createElement() method. See bug: + * https://www.w3.org/Bugs/Public/show_bug.cgi?id=19431 + */ + +/** + * Test that an element created using the Document object doc has the namespace + * that would be expected for the given contentType. + */ +function testDoc(doc, contentType) { + if (doc.contentType !== undefined) { + // Sanity check + assert_equals(doc.contentType, contentType, + "Wrong MIME type returned from doc.contentType"); + } + + var expectedNamespace = contentType == "text/html" || + contentType == "application/xhtml+xml" + ? "http://www.w3.org/1999/xhtml" : null; + + assert_equals(doc.createElement("x").namespaceURI, expectedNamespace); +} + +// First test various objects we create in JS +test(function() { + testDoc(document, "text/html") +}, "Created element's namespace in current document"); +test(function() { + testDoc(document.implementation.createHTMLDocument(""), "text/html"); +}, "Created element's namespace in created HTML document"); +test(function() { + testDoc(document.implementation.createDocument(null, "", null), + "application/xml"); +}, "Created element's namespace in created XML document"); +test(function() { + testDoc(document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", null), + "application/xhtml+xml"); +}, "Created element's namespace in created XHTML document"); +test(function() { + testDoc(document.implementation.createDocument("http://www.w3.org/2000/svg", "svg", null), + "image/svg+xml"); +}, "Created element's namespace in created SVG document"); +test(function() { + testDoc(document.implementation.createDocument("http://www.w3.org/1998/Math/MathML", "math", null), + "application/xml"); +}, "Created element's namespace in created MathML document"); + +// Second also test document created by DOMParser +test(function() { + testDoc(new DOMParser().parseFromString("", "text/html"), "text/html"); +}, "Created element's namespace in created HTML document by DOMParser ('text/html')"); +test(function() { + testDoc(new DOMParser().parseFromString("<root/>", "text/xml"), "text/xml"); +}, "Created element's namespace in created XML document by DOMParser ('text/xml')"); +test(function() { + testDoc(new DOMParser().parseFromString("<root/>", "application/xml"), "application/xml"); +}, "Created element's namespace in created XML document by DOMParser ('application/xml')"); +test(function() { + testDoc(new DOMParser().parseFromString("<html/>", "application/xhtml+xml"), "application/xhtml+xml"); +}, "Created element's namespace in created XHTML document by DOMParser ('application/xhtml+xml')"); +test(function() { + testDoc(new DOMParser().parseFromString("<math/>", "image/svg+xml"), "image/svg+xml"); +}, "Created element's namespace in created SVG document by DOMParser ('image/svg+xml')"); + +// Now for various externally-loaded files. Note: these lists must be kept +// synced with the lists in generate.py in the subdirectory, and that script +// must be run whenever the lists are updated. (We could keep the lists in a +// shared JSON file, but it seems like too much effort.) +var testExtensions = { + html: "text/html", + xhtml: "application/xhtml+xml", + xml: "application/xml", + svg: "image/svg+xml", + // Was not able to get server MIME type working properly :( + //mml: "application/mathml+xml", +}; + +var tests = [ + "empty", + "minimal_html", + + "xhtml", + "svg", + "mathml", + + "bare_xhtml", + "bare_svg", + "bare_mathml", + + "xhtml_ns_removed", + "xhtml_ns_changed", +]; + +tests.forEach(function(testName) { + Object.keys(testExtensions).forEach(function(ext) { + async_test(function(t) { + var iframe = document.createElement("iframe"); + iframe.src = "Document-createElement-namespace-tests/" + + testName + "." + ext; + iframe.onload = t.step_func_done(function() { + testDoc(iframe.contentDocument, testExtensions[ext]); + document.body.removeChild(iframe); + }); + document.body.appendChild(iframe); + }, "Created element's namespace in " + testName + "." + ext); + }); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElement.html b/testing/web-platform/tests/dom/nodes/Document-createElement.html new file mode 100644 index 0000000000..93435ac82d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElement.html @@ -0,0 +1,158 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createElement</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelement"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-localname"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-tagname"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-prefix"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-namespaceuri"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<iframe src="/common/dummy.xml"></iframe> +<iframe src="/common/dummy.xhtml"></iframe> +<script> +function toASCIIUppercase(str) { + var diff = "a".charCodeAt(0) - "A".charCodeAt(0); + var res = ""; + for (var i = 0; i < str.length; ++i) { + if ("a" <= str[i] && str[i] <= "z") { + res += String.fromCharCode(str.charCodeAt(i) - diff); + } else { + res += str[i]; + } + } + return res; +} +function toASCIILowercase(str) { + var diff = "a".charCodeAt(0) - "A".charCodeAt(0); + var res = ""; + for (var i = 0; i < str.length; ++i) { + if ("A" <= str[i] && str[i] <= "Z") { + res += String.fromCharCode(str.charCodeAt(i) + diff); + } else { + res += str[i]; + } + } + return res; +} +var HTMLNS = "http://www.w3.org/1999/xhtml", + valid = [ + undefined, + null, + "foo", + "f1oo", + "foo1", + "f\u0BC6", + "foo\u0BC6", + ":", + ":foo", + "f:oo", + "foo:", + "f:o:o", + "f::oo", + "f::oo:", + "foo:0", + "foo:_", + // combining char after :, invalid QName but valid Name + "foo:\u0BC6", + "foo:foo\u0BC6", + "foo\u0BC6:foo", + "xml", + "xmlns", + "xmlfoo", + "xml:foo", + "xmlns:foo", + "xmlfoo:bar", + "svg", + "math", + "FOO", + // Test that non-ASCII chars don't get uppercased/lowercased + "mar\u212a", + "\u0130nput", + "\u0131nput", + ], + invalid = [ + "", + "1foo", + "1:foo", + "fo o", + "\u0300foo", + "}foo", + "f}oo", + "foo}", + "\ufffffoo", + "f\uffffoo", + "foo\uffff", + "<foo", + "foo>", + "<foo>", + "f<oo", + "-foo", + ".foo", + "\u0300", + ] + +var xmlIframe = document.querySelector('[src="/common/dummy.xml"]'); +var xhtmlIframe = document.querySelector('[src="/common/dummy.xhtml"]'); + +function getWin(desc) { + if (desc == "HTML document") { + return window; + } + if (desc == "XML document") { + assert_equals(xmlIframe.contentDocument.documentElement.textContent, + "Dummy XML document", "XML document didn't load"); + return xmlIframe.contentWindow; + } + if (desc == "XHTML document") { + assert_equals(xhtmlIframe.contentDocument.documentElement.textContent, + "Dummy XHTML document", "XHTML document didn't load"); + return xhtmlIframe.contentWindow; + } +} + + +valid.forEach(function(t) { + ["HTML document", "XML document", "XHTML document"].forEach(function(desc) { + async_test(function(testObj) { + window.addEventListener("load", function() { + testObj.step(function() { + var win = getWin(desc); + var doc = win.document; + var elt = doc.createElement(t) + assert_true(elt instanceof win.Element, "instanceof Element") + assert_true(elt instanceof win.Node, "instanceof Node") + assert_equals(elt.localName, + desc == "HTML document" ? toASCIILowercase(String(t)) + : String(t), + "localName") + assert_equals(elt.tagName, + desc == "HTML document" ? toASCIIUppercase(String(t)) + : String(t), + "tagName") + assert_equals(elt.prefix, null, "prefix") + assert_equals(elt.namespaceURI, + desc == "XML document" ? null : HTMLNS, "namespaceURI") + }); + testObj.done(); + }); + }, "createElement(" + format_value(t) + ") in " + desc); + }); +}); +invalid.forEach(function(arg) { + ["HTML document", "XML document", "XHTML document"].forEach(function(desc) { + async_test(function(testObj) { + window.addEventListener("load", function() { + testObj.step(function() { + let win = getWin(desc); + let doc = win.document; + assert_throws_dom("InvalidCharacterError", win.DOMException, + function() { doc.createElement(arg) }) + }); + testObj.done(); + }); + }, "createElement(" + format_value(arg) + ") in " + desc); + }); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElementNS.html b/testing/web-platform/tests/dom/nodes/Document-createElementNS.html new file mode 100644 index 0000000000..5ad81043de --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElementNS.html @@ -0,0 +1,224 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createElementNS</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelementns"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-createElementNS.js"></script> +<div id="log"></div> +<iframe src="/common/dummy.xml"></iframe> +<iframe src="/common/dummy.xhtml"></iframe> +<script> +var tests = createElementNS_tests.concat([ + /* Arrays with three elements: + * the namespace argument + * the qualifiedName argument + * the expected exception, or null if none + */ + ["", "", "INVALID_CHARACTER_ERR"], + [null, "", "INVALID_CHARACTER_ERR"], + [undefined, "", "INVALID_CHARACTER_ERR"], + ["http://example.com/", null, null], + ["http://example.com/", "", "INVALID_CHARACTER_ERR"], + ["/", null, null], + ["/", "", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/XML/1998/namespace", null, null], + ["http://www.w3.org/XML/1998/namespace", "", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/2000/xmlns/", null, "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "", "INVALID_CHARACTER_ERR"], + ["foo:", null, null], + ["foo:", "", "INVALID_CHARACTER_ERR"], +]) + +var xmlIframe = document.querySelector('[src="/common/dummy.xml"]'); +var xhtmlIframe = document.querySelector('[src="/common/dummy.xhtml"]'); + +function runTest(t, i, desc) { + async_test(function(testObj) { + window.addEventListener("load", function() { + testObj.step(function() { + var doc; + if (desc == "HTML document") { + doc = document; + } else if (desc == "XML document") { + doc = xmlIframe.contentDocument; + // Make sure we're testing the right document + assert_equals(doc.documentElement.textContent, "Dummy XML document"); + } else if (desc == "XHTML document") { + doc = xhtmlIframe.contentDocument; + assert_equals(doc.documentElement.textContent, "Dummy XHTML document"); + } + var namespace = t[0], qualifiedName = t[1], expected = t[2] + if (expected != null) { + assert_throws_dom(expected, doc.defaultView.DOMException, function() {doc.createElementNS(namespace, qualifiedName) }); + } else { + var element = doc.createElementNS(namespace, qualifiedName) + assert_not_equals(element, null) + assert_equals(element.nodeType, Node.ELEMENT_NODE) + assert_equals(element.nodeType, element.ELEMENT_NODE) + assert_equals(element.nodeValue, null) + assert_equals(element.ownerDocument, doc) + var qualified = String(qualifiedName), names = [] + if (qualified.indexOf(":") >= 0) { + names = qualified.split(":", 2) + } else { + names = [null, qualified] + } + assert_equals(element.prefix, names[0]) + assert_equals(element.localName, names[1]) + assert_equals(element.tagName, qualified) + assert_equals(element.nodeName, qualified) + assert_equals(element.namespaceURI, + namespace === undefined || namespace === "" ? null + : namespace) + } + }); + testObj.done(); + }); + }, "createElementNS test in " + desc + ": " + t.map(format_value)) +} + +tests.forEach(function(t, i) { + runTest(t, i, "HTML document") + runTest(t, i, "XML document") + runTest(t, i, "XHTML document") +}) + + +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml"; + var element = document.createElementNS(HTMLNS, "span"); + assert_equals(element.namespaceURI, HTMLNS); + assert_equals(element.prefix, null); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_true(element instanceof HTMLElement, "Should be an HTMLElement"); + assert_true(element instanceof HTMLSpanElement, "Should be an HTMLSpanElement"); +}, "Lower-case HTML element without a prefix"); + +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml"; + var element = document.createElementNS(HTMLNS, "html:span"); + assert_equals(element.namespaceURI, HTMLNS); + assert_equals(element.prefix, "html"); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "HTML:SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_true(element instanceof HTMLElement, "Should be an HTMLElement"); + assert_true(element instanceof HTMLSpanElement, "Should be an HTMLSpanElement"); +}, "Lower-case HTML element with a prefix"); + +test(function() { + var element = document.createElementNS("test", "span"); + assert_equals(element.namespaceURI, "test"); + assert_equals(element.prefix, null); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "span"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Lower-case non-HTML element without a prefix"); + +test(function() { + var element = document.createElementNS("test", "html:span"); + assert_equals(element.namespaceURI, "test"); + assert_equals(element.prefix, "html"); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "html:span"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Lower-case non-HTML element with a prefix"); + +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml"; + var element = document.createElementNS(HTMLNS, "SPAN"); + assert_equals(element.namespaceURI, HTMLNS); + assert_equals(element.prefix, null); + assert_equals(element.localName, "SPAN"); + assert_equals(element.tagName, "SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_true(element instanceof HTMLElement, "Should be an HTMLElement"); + assert_true(element instanceof HTMLUnknownElement, "Should be an HTMLUnknownElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Upper-case HTML element without a prefix"); + +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml"; + var element = document.createElementNS(HTMLNS, "html:SPAN"); + assert_equals(element.namespaceURI, HTMLNS); + assert_equals(element.prefix, "html"); + assert_equals(element.localName, "SPAN"); + assert_equals(element.tagName, "HTML:SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_true(element instanceof HTMLElement, "Should be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Upper-case HTML element with a prefix"); + +test(function() { + var element = document.createElementNS("test", "SPAN"); + assert_equals(element.namespaceURI, "test"); + assert_equals(element.prefix, null); + assert_equals(element.localName, "SPAN"); + assert_equals(element.tagName, "SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Upper-case non-HTML element without a prefix"); + +test(function() { + var element = document.createElementNS("test", "html:SPAN"); + assert_equals(element.namespaceURI, "test"); + assert_equals(element.prefix, "html"); + assert_equals(element.localName, "SPAN"); + assert_equals(element.tagName, "html:SPAN"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "Upper-case non-HTML element with a prefix"); + +test(function() { + var element = document.createElementNS(null, "span"); + assert_equals(element.namespaceURI, null); + assert_equals(element.prefix, null); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "span"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "null namespace"); + +test(function() { + var element = document.createElementNS(undefined, "span"); + assert_equals(element.namespaceURI, null); + assert_equals(element.prefix, null); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "span"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "undefined namespace"); + +test(function() { + var element = document.createElementNS("", "span"); + assert_equals(element.namespaceURI, null); + assert_equals(element.prefix, null); + assert_equals(element.localName, "span"); + assert_equals(element.tagName, "span"); + assert_true(element instanceof Node, "Should be a Node"); + assert_true(element instanceof Element, "Should be an Element"); + assert_false(element instanceof HTMLElement, "Should not be an HTMLElement"); + assert_false(element instanceof HTMLSpanElement, "Should not be an HTMLSpanElement"); +}, "empty string namespace"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createElementNS.js b/testing/web-platform/tests/dom/nodes/Document-createElementNS.js new file mode 100644 index 0000000000..2cf2948563 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createElementNS.js @@ -0,0 +1,189 @@ +var createElementNS_tests = [ + /* Arrays with three elements: + * the namespace argument + * the qualifiedName argument + * the expected exception, or null if none + */ + [null, null, null], + [null, undefined, null], + [null, "foo", null], + [null, "1foo", "INVALID_CHARACTER_ERR"], + [null, "f1oo", null], + [null, "foo1", null], + [null, "\u0BC6foo", null], + [null, "\u037Efoo", "INVALID_CHARACTER_ERR"], + [null, "}foo", "INVALID_CHARACTER_ERR"], + [null, "f}oo", "INVALID_CHARACTER_ERR"], + [null, "foo}", "INVALID_CHARACTER_ERR"], + [null, "\uFFFFfoo", "INVALID_CHARACTER_ERR"], + [null, "f\uFFFFoo", "INVALID_CHARACTER_ERR"], + [null, "foo\uFFFF", "INVALID_CHARACTER_ERR"], + [null, "<foo", "INVALID_CHARACTER_ERR"], + [null, "foo>", "INVALID_CHARACTER_ERR"], + [null, "<foo>", "INVALID_CHARACTER_ERR"], + [null, "f<oo", "INVALID_CHARACTER_ERR"], + [null, "^^", "INVALID_CHARACTER_ERR"], + [null, "fo o", "INVALID_CHARACTER_ERR"], + [null, "-foo", "INVALID_CHARACTER_ERR"], + [null, ".foo", "INVALID_CHARACTER_ERR"], + [null, ":foo", "INVALID_CHARACTER_ERR"], + [null, "f:oo", "NAMESPACE_ERR"], + [null, "foo:", "INVALID_CHARACTER_ERR"], + [null, "f:o:o", "INVALID_CHARACTER_ERR"], + [null, ":", "INVALID_CHARACTER_ERR"], + [null, "xml", null], + [null, "xmlns", "NAMESPACE_ERR"], + [null, "xmlfoo", null], + [null, "xml:foo", "NAMESPACE_ERR"], + [null, "xmlns:foo", "NAMESPACE_ERR"], + [null, "xmlfoo:bar", "NAMESPACE_ERR"], + [null, "null:xml", "NAMESPACE_ERR"], + ["", null, null], + ["", ":foo", "INVALID_CHARACTER_ERR"], + ["", "f:oo", "NAMESPACE_ERR"], + ["", "foo:", "INVALID_CHARACTER_ERR"], + [undefined, null, null], + [undefined, undefined, null], + [undefined, "foo", null], + [undefined, "1foo", "INVALID_CHARACTER_ERR"], + [undefined, "f1oo", null], + [undefined, "foo1", null], + [undefined, ":foo", "INVALID_CHARACTER_ERR"], + [undefined, "f:oo", "NAMESPACE_ERR"], + [undefined, "foo:", "INVALID_CHARACTER_ERR"], + [undefined, "f::oo", "INVALID_CHARACTER_ERR"], + [undefined, "xml", null], + [undefined, "xmlns", "NAMESPACE_ERR"], + [undefined, "xmlfoo", null], + [undefined, "xml:foo", "NAMESPACE_ERR"], + [undefined, "xmlns:foo", "NAMESPACE_ERR"], + [undefined, "xmlfoo:bar", "NAMESPACE_ERR"], + ["http://example.com/", "foo", null], + ["http://example.com/", "1foo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "<foo>", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "fo<o", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "-foo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", ".foo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "f1oo", null], + ["http://example.com/", "foo1", null], + ["http://example.com/", ":foo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "f:oo", null], + ["http://example.com/", "f:o:o", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "foo:", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "f::oo", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "a:0", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "0:a", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "a:_", null], + ["http://example.com/", "a:\u0BC6", null], + ["http://example.com/", "a:\u037E", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "a:\u0300", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "\u0BC6:a", null], + ["http://example.com/", "\u0300:a", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "\u037E:a", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "a:a\u0BC6", null], + ["http://example.com/", "a\u0BC6:a", null], + ["http://example.com/", "xml:test", "NAMESPACE_ERR"], + ["http://example.com/", "xmlns:test", "NAMESPACE_ERR"], + ["http://example.com/", "test:xmlns", null], + ["http://example.com/", "xmlns", "NAMESPACE_ERR"], + ["http://example.com/", "_:_", null], + ["http://example.com/", "_:h0", null], + ["http://example.com/", "_:test", null], + ["http://example.com/", "l_:_", null], + ["http://example.com/", "ns:_0", null], + ["http://example.com/", "ns:a0", null], + ["http://example.com/", "ns0:test", null], + ["http://example.com/", "a.b:c", null], + ["http://example.com/", "a-b:c", null], + ["http://example.com/", "xml", null], + ["http://example.com/", "XMLNS", null], + ["http://example.com/", "xmlfoo", null], + ["http://example.com/", "xml:foo", "NAMESPACE_ERR"], + ["http://example.com/", "XML:foo", null], + ["http://example.com/", "xmlns:foo", "NAMESPACE_ERR"], + ["http://example.com/", "XMLNS:foo", null], + ["http://example.com/", "xmlfoo:bar", null], + ["http://example.com/", "prefix::local", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:{", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:}", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:~", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:'", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:!", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:@", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:#", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:$", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:%", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:^", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:&", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:*", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:(", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:)", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:+", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:=", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:[", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:]", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:\\", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:/", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:;", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:`", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:<", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:>", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:,", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:a ", "INVALID_CHARACTER_ERR"], + ["http://example.com/", "namespaceURI:\"", "INVALID_CHARACTER_ERR"], + ["/", "foo", null], + ["/", "1foo", "INVALID_CHARACTER_ERR"], + ["/", "f1oo", null], + ["/", "foo1", null], + ["/", ":foo", "INVALID_CHARACTER_ERR"], + ["/", "f:oo", null], + ["/", "foo:", "INVALID_CHARACTER_ERR"], + ["/", "xml", null], + ["/", "xmlns", "NAMESPACE_ERR"], + ["/", "xmlfoo", null], + ["/", "xml:foo", "NAMESPACE_ERR"], + ["/", "xmlns:foo", "NAMESPACE_ERR"], + ["/", "xmlfoo:bar", null], + ["http://www.w3.org/XML/1998/namespace", "foo", null], + ["http://www.w3.org/XML/1998/namespace", "1foo", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/XML/1998/namespace", "f1oo", null], + ["http://www.w3.org/XML/1998/namespace", "foo1", null], + ["http://www.w3.org/XML/1998/namespace", ":foo", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/XML/1998/namespace", "f:oo", null], + ["http://www.w3.org/XML/1998/namespace", "foo:", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/XML/1998/namespace", "xml", null], + ["http://www.w3.org/XML/1998/namespace", "xmlns", "NAMESPACE_ERR"], + ["http://www.w3.org/XML/1998/namespace", "xmlfoo", null], + ["http://www.w3.org/XML/1998/namespace", "xml:foo", null], + ["http://www.w3.org/XML/1998/namespace", "xmlns:foo", "NAMESPACE_ERR"], + ["http://www.w3.org/XML/1998/namespace", "xmlfoo:bar", null], + ["http://www.w3.org/XML/1998/namespaces", "xml:foo", "NAMESPACE_ERR"], + ["http://www.w3.org/xml/1998/namespace", "xml:foo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "foo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "1foo", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/2000/xmlns/", "f1oo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "foo1", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", ":foo", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/2000/xmlns/", "f:oo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "foo:", "INVALID_CHARACTER_ERR"], + ["http://www.w3.org/2000/xmlns/", "xml", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "xmlns", null], + ["http://www.w3.org/2000/xmlns/", "xmlfoo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "xml:foo", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "xmlns:foo", null], + ["http://www.w3.org/2000/xmlns/", "xmlfoo:bar", "NAMESPACE_ERR"], + ["http://www.w3.org/2000/xmlns/", "foo:xmlns", "NAMESPACE_ERR"], + ["foo:", "foo", null], + ["foo:", "1foo", "INVALID_CHARACTER_ERR"], + ["foo:", "f1oo", null], + ["foo:", "foo1", null], + ["foo:", ":foo", "INVALID_CHARACTER_ERR"], + ["foo:", "f:oo", null], + ["foo:", "foo:", "INVALID_CHARACTER_ERR"], + ["foo:", "xml", null], + ["foo:", "xmlns", "NAMESPACE_ERR"], + ["foo:", "xmlfoo", null], + ["foo:", "xml:foo", "NAMESPACE_ERR"], + ["foo:", "xmlns:foo", "NAMESPACE_ERR"], + ["foo:", "xmlfoo:bar", null], +] diff --git a/testing/web-platform/tests/dom/nodes/Document-createEvent-touchevent.window.js b/testing/web-platform/tests/dom/nodes/Document-createEvent-touchevent.window.js new file mode 100644 index 0000000000..6523ac5a02 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createEvent-touchevent.window.js @@ -0,0 +1,12 @@ +for (const variant of ['TouchEvent', 'touchevent', 'TOUCHEVENT']) { + test(() => { + if (!('ontouchstart' in document)) { + assert_throws_dom("NOT_SUPPORTED_ERR", () => { + document.createEvent(variant); + }); + } else { + document.createEvent(variant); + // The interface and other details of the event is tested in Document-createEvent.https.html + } + }, `document.createEvent('${variant}') should throw if 'expose legacy touch event APIs' is false`); +} diff --git a/testing/web-platform/tests/dom/nodes/Document-createEvent.https.html b/testing/web-platform/tests/dom/nodes/Document-createEvent.https.html new file mode 100644 index 0000000000..4781d54e8e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createEvent.https.html @@ -0,0 +1,170 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createEvent</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createevent"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-createEvent.js"></script> +<div id="log"></div> +<script> +function supportsTouchEvents(isTouchEvent) { + if (isTouchEvent) { + assert_implements_optional('ontouchstart' in document, "'expose legacy touch event APIs'"); + } +} +function testAlias(arg, iface, isTouchEvent) { + var ev; + test(function() { + supportsTouchEvents(isTouchEvent); + ev = document.createEvent(arg); + assert_equals(Object.getPrototypeOf(ev), window[iface].prototype); + }, arg + " should be an alias for " + iface + "."); + test(function() { + supportsTouchEvents(isTouchEvent); + assert_equals(ev.type, "", + "type should be initialized to the empty string"); + assert_equals(ev.target, null, + "target should be initialized to null"); + assert_equals(ev.currentTarget, null, + "currentTarget should be initialized to null"); + assert_equals(ev.eventPhase, 0, + "eventPhase should be initialized to NONE (0)"); + assert_equals(ev.bubbles, false, + "bubbles should be initialized to false"); + assert_equals(ev.cancelable, false, + "cancelable should be initialized to false"); + assert_equals(ev.defaultPrevented, false, + "defaultPrevented should be initialized to false"); + assert_equals(ev.isTrusted, false, + "isTrusted should be initialized to false"); + }, "createEvent('" + arg + "') should be initialized correctly."); +} +aliases.TouchEvent = 'TouchEvent'; +for (var alias in aliases) { + var isTouchEvent = alias === 'TouchEvent'; + var iface = aliases[alias]; + testAlias(alias, iface, isTouchEvent); + testAlias(alias.toLowerCase(), iface, isTouchEvent); + testAlias(alias.toUpperCase(), iface, isTouchEvent); + + if (alias[alias.length - 1] != "s") { + var plural = alias + "s"; + if (!(plural in aliases)) { + test(function () { + assert_throws_dom("NOT_SUPPORTED_ERR", function () { + var evt = document.createEvent(plural); + }); + }, 'Should throw NOT_SUPPORTED_ERR for pluralized legacy event interface "' + plural + '"'); + } + } +} + +test(function() { + assert_throws_dom("NOT_SUPPORTED_ERR", function() { + var evt = document.createEvent("foo"); + }); + assert_throws_dom("NOT_SUPPORTED_ERR", function() { + // 'LATIN CAPITAL LETTER I WITH DOT ABOVE' (U+0130) + var evt = document.createEvent("U\u0130Event"); + }); + assert_throws_dom("NOT_SUPPORTED_ERR", function() { + // 'LATIN SMALL LETTER DOTLESS I' (U+0131) + var evt = document.createEvent("U\u0131Event"); + }); +}, "Should throw NOT_SUPPORTED_ERR for unrecognized arguments"); + +/* + * The following are event interfaces which do actually exist, but must still + * throw since they're absent from the table in the spec for + * document.createEvent(). This list is not exhaustive, but includes all + * interfaces that it is known some UA does or did not throw for. + */ +var someNonCreateableEvents = [ + "AnimationEvent", + "AnimationPlaybackEvent", + "AnimationPlayerEvent", + "ApplicationCacheErrorEvent", + "AudioProcessingEvent", + "AutocompleteErrorEvent", + "BeforeInstallPromptEvent", + "BlobEvent", + "ClipboardEvent", + "CloseEvent", + "CommandEvent", + "DataContainerEvent", + "ErrorEvent", + "ExtendableEvent", + "ExtendableMessageEvent", + "FetchEvent", + "FontFaceSetLoadEvent", + "GamepadEvent", + "GeofencingEvent", + "IDBVersionChangeEvent", + "InstallEvent", + "KeyEvent", + "MIDIConnectionEvent", + "MIDIMessageEvent", + "MediaEncryptedEvent", + "MediaKeyEvent", + "MediaKeyMessageEvent", + "MediaQueryListEvent", + "MediaStreamEvent", + "MediaStreamTrackEvent", + "MouseScrollEvent", + "MutationEvent", + "NotificationEvent", + "NotifyPaintEvent", + "OfflineAudioCompletionEvent", + "OrientationEvent", + "PageTransition", // Yes, with no "Event" + "PageTransitionEvent", + "PointerEvent", + "PopStateEvent", + "PopUpEvent", + "PresentationConnectionAvailableEvent", + "PresentationConnectionCloseEvent", + "ProgressEvent", + "PromiseRejectionEvent", + "PushEvent", + "RTCDTMFToneChangeEvent", + "RTCDataChannelEvent", + "RTCIceCandidateEvent", + "RelatedEvent", + "ResourceProgressEvent", + "SVGEvent", + "SVGZoomEvent", + "ScrollAreaEvent", + "SecurityPolicyViolationEvent", + "ServicePortConnectEvent", + "ServiceWorkerMessageEvent", + "SimpleGestureEvent", + "SpeechRecognitionError", + "SpeechRecognitionEvent", + "SpeechSynthesisEvent", + "SyncEvent", + "TimeEvent", + "TrackEvent", + "TransitionEvent", + "WebGLContextEvent", + "WebKitAnimationEvent", + "WebKitTransitionEvent", + "WheelEvent", + "XULCommandEvent", +]; +someNonCreateableEvents.forEach(function (eventInterface) { + test(function () { + assert_throws_dom("NOT_SUPPORTED_ERR", function () { + var evt = document.createEvent(eventInterface); + }); + }, 'Should throw NOT_SUPPORTED_ERR for non-legacy event interface "' + eventInterface + '"'); + + // SVGEvents is allowed, other plurals are not + if (eventInterface !== "SVGEvent") { + test(function () { + assert_throws_dom("NOT_SUPPORTED_ERR", function () { + var evt = document.createEvent(eventInterface + "s"); + }); + }, 'Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "' + eventInterface + 's"'); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createEvent.js b/testing/web-platform/tests/dom/nodes/Document-createEvent.js new file mode 100644 index 0000000000..57e8e966f8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createEvent.js @@ -0,0 +1,22 @@ +var aliases = { + "BeforeUnloadEvent": "BeforeUnloadEvent", + "CompositionEvent": "CompositionEvent", + "CustomEvent": "CustomEvent", + "DeviceMotionEvent": "DeviceMotionEvent", + "DeviceOrientationEvent": "DeviceOrientationEvent", + "DragEvent": "DragEvent", + "Event": "Event", + "Events": "Event", + "FocusEvent": "FocusEvent", + "HashChangeEvent": "HashChangeEvent", + "HTMLEvents": "Event", + "KeyboardEvent": "KeyboardEvent", + "MessageEvent": "MessageEvent", + "MouseEvent": "MouseEvent", + "MouseEvents": "MouseEvent", + "StorageEvent": "StorageEvent", + "SVGEvents": "Event", + "TextEvent": "CompositionEvent", + "UIEvent": "UIEvent", + "UIEvents": "UIEvent", +}; diff --git a/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml new file mode 100644 index 0000000000..d06f70fdcb --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml @@ -0,0 +1,15 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Document.createProcessingInstruction in XML documents</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-createprocessinginstruction"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-processinginstruction-target"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-characterdata-data"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-ownerdocument"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script src="Document-createProcessingInstruction.js"/> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.html b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.html new file mode 100644 index 0000000000..c57a792fac --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createProcessingInstruction in HTML documents</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createprocessinginstruction"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-processinginstruction-target"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-ownerdocument"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script src="Document-createProcessingInstruction.js"></script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.js b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.js new file mode 100644 index 0000000000..d6cc3725f0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.js @@ -0,0 +1,39 @@ +test(function() { + var invalid = [ + ["A", "?>"], + ["\u00B7A", "x"], + ["\u00D7A", "x"], + ["A\u00D7", "x"], + ["\\A", "x"], + ["\f", "x"], + [0, "x"], + ["0", "x"] + ], + valid = [ + ["xml:fail", "x"], + ["A\u00B7A", "x"], + ["a0", "x"] + ] + + for (var i = 0, il = invalid.length; i < il; i++) { + test(function() { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + document.createProcessingInstruction(invalid[i][0], invalid[i][1]) + }) + }, "Should throw an INVALID_CHARACTER_ERR for target " + + format_value(invalid[i][0]) + " and data " + + format_value(invalid[i][1]) + ".") + } + for (var i = 0, il = valid.length; i < il; ++i) { + test(function() { + var pi = document.createProcessingInstruction(valid[i][0], valid[i][1]); + assert_equals(pi.target, valid[i][0]); + assert_equals(pi.data, valid[i][1]); + assert_equals(pi.ownerDocument, document); + assert_true(pi instanceof ProcessingInstruction); + assert_true(pi instanceof Node); + }, "Should get a ProcessingInstruction for target " + + format_value(valid[i][0]) + " and data " + + format_value(valid[i][1]) + ".") + } +}) diff --git a/testing/web-platform/tests/dom/nodes/Document-createTextNode.html b/testing/web-platform/tests/dom/nodes/Document-createTextNode.html new file mode 100644 index 0000000000..ccc1b1b77f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createTextNode.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.createTextNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createtextnode"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-ownerdocument"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-data"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodevalue"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-textcontent"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-characterdata-length"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodetype"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-haschildnodes"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-childnodes"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-firstchild"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-lastchild"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-createComment-createTextNode.js"></script> +<div id="log"></div> +<script> +test_create("createTextNode", Text, 3, "#text"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-createTreeWalker.html b/testing/web-platform/tests/dom/nodes/Document-createTreeWalker.html new file mode 100644 index 0000000000..1e8420d841 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-createTreeWalker.html @@ -0,0 +1,42 @@ +<!doctype html> +<meta charset=utf-8> +<title>Document.createTreeWalker</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + assert_throws_js(TypeError, function() { + document.createTreeWalker(); + }); +}, "Required arguments to createTreeWalker should be required."); +test(function() { + var tw = document.createTreeWalker(document.body); + assert_equals(tw.root, document.body); + assert_equals(tw.currentNode, document.body); + assert_equals(tw.whatToShow, 0xFFFFFFFF); + assert_equals(tw.filter, null); +}, "Optional arguments to createTreeWalker should be optional (1 passed)."); +test(function() { + var tw = document.createTreeWalker(document.body, 42); + assert_equals(tw.root, document.body); + assert_equals(tw.currentNode, document.body); + assert_equals(tw.whatToShow, 42); + assert_equals(tw.filter, null); +}, "Optional arguments to createTreeWalker should be optional (2 passed)."); +test(function() { + var tw = document.createTreeWalker(document.body, 42, null); + assert_equals(tw.root, document.body); + assert_equals(tw.currentNode, document.body); + assert_equals(tw.whatToShow, 42); + assert_equals(tw.filter, null); +}, "Optional arguments to createTreeWalker should be optional (3 passed, null)."); +test(function() { + var fn = function() {}; + var tw = document.createTreeWalker(document.body, 42, fn); + assert_equals(tw.root, document.body); + assert_equals(tw.currentNode, document.body); + assert_equals(tw.whatToShow, 42); + assert_equals(tw.filter, fn); +}, "Optional arguments to createTreeWalker should be optional (3 passed, function)."); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-doctype.html b/testing/web-platform/tests/dom/nodes/Document-doctype.html new file mode 100644 index 0000000000..75bfd8506d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-doctype.html @@ -0,0 +1,21 @@ +<!-- comment --> +<!doctype html> +<meta charset=utf-8> +<title>Document.doctype</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-doctype"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + assert_true(document.doctype instanceof DocumentType, + "Doctype should be a DocumentType"); + assert_equals(document.doctype, document.childNodes[1]); +}, "Window document with doctype"); + +test(function() { + var newdoc = new Document(); + newdoc.appendChild(newdoc.createElement("html")); + assert_equals(newdoc.doctype, null); +}, "new Document()"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-getElementById.html b/testing/web-platform/tests/dom/nodes/Document-getElementById.html new file mode 100644 index 0000000000..1dec4c085b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-getElementById.html @@ -0,0 +1,350 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.getElementById</title> +<link rel="author" title="Tetsuharu OHZEKI" href="mailto:saneyuki.snyk@gmail.com"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementbyid"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> + <div id="log"></div> + + <!-- test 0 --> + <div id=""></div> + + <!-- test 1 --> + <div id="test1"></div> + + <!-- test 5 --> + <div id="test5" data-name="1st"> + <p id="test5" data-name="2nd">P</p> + <input id="test5" type="submit" value="Submit" data-name="3rd"> + </div> + + <!-- test 15 --> + <div id="outer"> + <div id="middle"> + <div id="inner"></div> + </div> + </div> + +<script> + var gBody = document.getElementsByTagName("body")[0]; + + test(function() { + assert_equals(document.getElementById(""), null); + }, "Calling document.getElementById with an empty string argument."); + + test(function() { + var element = document.createElement("div"); + element.setAttribute("id", "null"); + document.body.appendChild(element); + this.add_cleanup(function() { document.body.removeChild(element) }); + assert_equals(document.getElementById(null), element); + }, "Calling document.getElementById with a null argument."); + + test(function() { + var element = document.createElement("div"); + element.setAttribute("id", "undefined"); + document.body.appendChild(element); + this.add_cleanup(function() { document.body.removeChild(element) }); + assert_equals(document.getElementById(undefined), element); + }, "Calling document.getElementById with an undefined argument."); + + + test(function() { + var bar = document.getElementById("test1"); + assert_not_equals(bar, null, "should not be null"); + assert_equals(bar.tagName, "DIV", "should have expected tag name."); + assert_true(bar instanceof HTMLDivElement, "should be a valid Element instance"); + }, "on static page"); + + + test(function() { + var TEST_ID = "test2"; + + var test = document.createElement("div"); + test.setAttribute("id", TEST_ID); + gBody.appendChild(test); + + // test: appended element + var result = document.getElementById(TEST_ID); + assert_not_equals(result, null, "should not be null."); + assert_equals(result.tagName, "DIV", "should have appended element's tag name"); + assert_true(result instanceof HTMLDivElement, "should be a valid Element instance"); + + // test: removed element + gBody.removeChild(test); + var removed = document.getElementById(TEST_ID); + // `document.getElementById()` returns `null` if there is none. + // https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid + assert_equals(removed, null, "should not get removed element."); + }, "Document.getElementById with a script-inserted element"); + + + test(function() { + // setup fixtures. + var TEST_ID = "test3"; + var test = document.createElement("div"); + test.setAttribute("id", TEST_ID); + gBody.appendChild(test); + + // update id + var UPDATED_ID = "test3-updated"; + test.setAttribute("id", UPDATED_ID); + var e = document.getElementById(UPDATED_ID); + assert_equals(e, test, "should get the element with id."); + + var old = document.getElementById(TEST_ID); + assert_equals(old, null, "shouldn't get the element by the old id."); + + // remove id. + test.removeAttribute("id"); + var e2 = document.getElementById(UPDATED_ID); + assert_equals(e2, null, "should return null when the passed id is none in document."); + }, "update `id` attribute via setAttribute/removeAttribute"); + + + test(function() { + var TEST_ID = "test4-should-not-exist"; + + var e = document.createElement('div'); + e.setAttribute("id", TEST_ID); + + assert_equals(document.getElementById(TEST_ID), null, "should be null"); + document.body.appendChild(e); + assert_equals(document.getElementById(TEST_ID), e, "should be the appended element"); + }, "Ensure that the id attribute only affects elements present in a document"); + + + test(function() { + // the method should return the 1st element. + var TEST_ID = "test5"; + var target = document.getElementById(TEST_ID); + assert_not_equals(target, null, "should not be null"); + assert_equals(target.getAttribute("data-name"), "1st", "should return the 1st"); + + // even if after the new element was appended. + var element4 = document.createElement("div"); + element4.setAttribute("id", TEST_ID); + element4.setAttribute("data-name", "4th"); + gBody.appendChild(element4); + var target2 = document.getElementById(TEST_ID); + assert_not_equals(target2, null, "should not be null"); + assert_equals(target2.getAttribute("data-name"), "1st", "should be the 1st"); + + // should return the next element after removed the subtree including the 1st element. + target2.parentNode.removeChild(target2); + var target3 = document.getElementById(TEST_ID); + assert_not_equals(target3, null, "should not be null"); + assert_equals(target3.getAttribute("data-name"), "4th", "should be the 4th"); + }, "in tree order, within the context object's tree"); + + + test(function() { + var TEST_ID = "test6"; + var s = document.createElement("div"); + s.setAttribute("id", TEST_ID); + // append to Element, not Document. + document.createElement("div").appendChild(s); + + assert_equals(document.getElementById(TEST_ID), null, "should be null"); + }, "Modern browsers optimize this method with using internal id cache. " + + "This test checks that their optimization should effect only append to `Document`, not append to `Node`."); + + + test(function() { + var TEST_ID = "test7" + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID); + gBody.appendChild(element); + + var target = document.getElementById(TEST_ID); + assert_equals(target, element, "should return the element before changing the value"); + + element.attributes[0].value = TEST_ID + "-updated"; + var target2 = document.getElementById(TEST_ID); + assert_equals(target2, null, "should return null after updated id via Attr.value"); + var target3 = document.getElementById(TEST_ID + "-updated"); + assert_equals(target3, element, "should be equal to the updated element."); + }, "changing attribute's value via `Attr` gotten from `Element.attribute`."); + + + test(function() { + var TEST_ID = "test8"; + + // setup fixture + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID + "-fixture"); + gBody.appendChild(element); + + // add id-ed element with using innerHTML + element.innerHTML = "<div id='"+ TEST_ID +"'></div>"; + var test = document.getElementById(TEST_ID); + assert_equals(test, element.firstChild, "should not be null"); + assert_equals(test.tagName, "DIV", "should have expected tag name."); + assert_true(test instanceof HTMLDivElement, "should be a valid Element instance"); + }, "add id attribute via innerHTML"); + + + test(function() { + var TEST_ID = "test9"; + + // add fixture + var fixture = document.createElement("div"); + fixture.setAttribute("id", TEST_ID + "-fixture"); + gBody.appendChild(fixture); + + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID); + fixture.appendChild(element); + + // check 'getElementById' should get the 'element' + assert_equals(document.getElementById(TEST_ID), element, "should not be null"); + + // remove id-ed element with using innerHTML (clear 'element') + fixture.innerHTML = ""; + var test = document.getElementById(TEST_ID); + assert_equals(test, null, "should be null."); + }, "remove id attribute via innerHTML"); + + + test(function() { + var TEST_ID = "test10"; + + // setup fixture + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID + "-fixture"); + gBody.appendChild(element); + + // add id-ed element with using outerHTML + element.outerHTML = "<div id='"+ TEST_ID +"'></div>"; + var test = document.getElementById(TEST_ID); + assert_not_equals(test, null, "should not be null"); + assert_equals(test.tagName, "DIV", "should have expected tag name."); + assert_true(test instanceof HTMLDivElement,"should be a valid Element instance"); + }, "add id attribute via outerHTML"); + + + test(function() { + var TEST_ID = "test11"; + + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID); + gBody.appendChild(element); + + var test = document.getElementById(TEST_ID); + assert_equals(test, element, "should be equal to the appended element."); + + // remove id-ed element with using outerHTML + element.outerHTML = "<div></div>"; + var test = document.getElementById(TEST_ID); + assert_equals(test, null, "should be null."); + }, "remove id attribute via outerHTML"); + + + test(function() { + // setup fixtures. + var TEST_ID = "test12"; + var test = document.createElement("div"); + test.id = TEST_ID; + gBody.appendChild(test); + + // update id + var UPDATED_ID = TEST_ID + "-updated"; + test.id = UPDATED_ID; + var e = document.getElementById(UPDATED_ID); + assert_equals(e, test, "should get the element with id."); + + var old = document.getElementById(TEST_ID); + assert_equals(old, null, "shouldn't get the element by the old id."); + + // remove id. + test.id = ""; + var e2 = document.getElementById(UPDATED_ID); + assert_equals(e2, null, "should return null when the passed id is none in document."); + }, "update `id` attribute via element.id"); + + + test(function() { + var TEST_ID = "test13"; + + var create_same_id_element = function (order) { + var element = document.createElement("div"); + element.setAttribute("id", TEST_ID); + element.setAttribute("data-order", order);// for debug + return element; + }; + + // create fixture + var container = document.createElement("div"); + container.setAttribute("id", TEST_ID + "-fixture"); + gBody.appendChild(container); + + var element1 = create_same_id_element("1"); + var element2 = create_same_id_element("2"); + var element3 = create_same_id_element("3"); + var element4 = create_same_id_element("4"); + + // append element: 2 -> 4 -> 3 -> 1 + container.appendChild(element2); + container.appendChild(element4); + container.insertBefore(element3, element4); + container.insertBefore(element1, element2); + + + var test = document.getElementById(TEST_ID); + assert_equals(test, element1, "should return 1st element"); + container.removeChild(element1); + + test = document.getElementById(TEST_ID); + assert_equals(test, element2, "should return 2nd element"); + container.removeChild(element2); + + test = document.getElementById(TEST_ID); + assert_equals(test, element3, "should return 3rd element"); + container.removeChild(element3); + + test = document.getElementById(TEST_ID); + assert_equals(test, element4, "should return 4th element"); + container.removeChild(element4); + + + }, "where insertion order and tree order don't match"); + + test(function() { + var TEST_ID = "test14"; + var a = document.createElement("a"); + var b = document.createElement("b"); + a.appendChild(b); + b.id = TEST_ID; + assert_equals(document.getElementById(TEST_ID), null); + + gBody.appendChild(a); + assert_equals(document.getElementById(TEST_ID), b); + }, "Inserting an id by inserting its parent node"); + + test(function () { + var TEST_ID = "test15" + var outer = document.getElementById("outer"); + var middle = document.getElementById("middle"); + var inner = document.getElementById("inner"); + outer.removeChild(middle); + + var new_el = document.createElement("h1"); + new_el.id = "heading"; + inner.appendChild(new_el); + // the new element is not part of the document since + // "middle" element was removed previously + assert_equals(document.getElementById("heading"), null); + }, "Document.getElementById must not return nodes not present in document"); + + // TODO: + // id attribute in a namespace + + + // TODO: + // SVG + MathML elements with id attributes + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-getElementsByClassName.html b/testing/web-platform/tests/dom/nodes/Document-getElementsByClassName.html new file mode 100644 index 0000000000..db8fac212d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-getElementsByClassName.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<title>Document.getElementsByClassName</title> +<link rel="author" title="Intel" href="http://www.intel.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var a = document.createElement("a"), + b = document.createElement("b"); + a.className = "foo"; + this.add_cleanup(function() {document.body.removeChild(a);}); + document.body.appendChild(a); + + var l = document.getElementsByClassName("foo"); + assert_true(l instanceof HTMLCollection); + assert_equals(l.length, 1); + + b.className = "foo"; + document.body.appendChild(b); + assert_equals(l.length, 2); + + document.body.removeChild(b); + assert_equals(l.length, 1); +}, "getElementsByClassName() should be a live collection"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName-xhtml.xhtml new file mode 100644 index 0000000000..309a29ae77 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName-xhtml.xhtml @@ -0,0 +1,104 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Document.getElementsByTagName</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<pre id="x"></pre> +<script> +test(function() { + var t = document.body.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "I")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_equals(t.localName, "I") + assert_equals(t.tagName, "I") + assert_array_equals(document.getElementsByTagName("I"), [t]) + assert_array_equals(document.getElementsByTagName("i"), []) + assert_array_equals(document.body.getElementsByTagName("I"), [t]) + assert_array_equals(document.body.getElementsByTagName("i"), []) +}, "HTML element with uppercase tag name matches in XHTML documents") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "st")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("st"), [t]) + assert_array_equals(document.getElementsByTagName("ST"), []) +}, "Element in non-HTML namespace, no prefix, lowercase name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "ST")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("ST"), [t]) + assert_array_equals(document.getElementsByTagName("st"), []) +}, "Element in non-HTML namespace, no prefix, uppercase name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "te:st")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("st"), []) + assert_array_equals(document.getElementsByTagName("ST"), []) + assert_array_equals(document.getElementsByTagName("te:st"), [t]) + assert_array_equals(document.getElementsByTagName("te:ST"), []) +}, "Element in non-HTML namespace, prefix, lowercase name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "te:ST")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("ST"), []) + assert_array_equals(document.getElementsByTagName("st"), []) + assert_array_equals(document.getElementsByTagName("te:st"), []) + assert_array_equals(document.getElementsByTagName("te:ST"), [t]) +}, "Element in non-HTML namespace, prefix, uppercase name") + +test(function() { + var t = document.body.appendChild(document.createElement("AÇ")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("AÇ"), [t], "All uppercase input") + assert_array_equals(document.getElementsByTagName("aÇ"), [], "Ascii lowercase input") + assert_array_equals(document.getElementsByTagName("aç"), [], "All lowercase input") +}, "Element in HTML namespace, no prefix, non-ascii characters in name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "AÇ")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("AÇ"), [t], "All uppercase input") + assert_array_equals(document.getElementsByTagName("aÇ"), [], "Ascii lowercase input") + assert_array_equals(document.getElementsByTagName("aç"), [], "All lowercase input") +}, "Element in non-HTML namespace, non-ascii characters in name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "test:aÇ")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("TEST:AÇ"), [], "All uppercase input") + assert_array_equals(document.getElementsByTagName("test:aÇ"), [t], "Ascii lowercase input") + assert_array_equals(document.getElementsByTagName("test:aç"), [], "All lowercase input") +}, "Element in HTML namespace, prefix, non-ascii characters in name") + +test(function() { + var t = document.body.appendChild(document.createElementNS("test", "TEST:AÇ")) + this.add_cleanup(function() {document.body.removeChild(t)}) + assert_array_equals(document.getElementsByTagName("TEST:AÇ"), [t], "All uppercase input") + assert_array_equals(document.getElementsByTagName("test:aÇ"), [], "Ascii lowercase input") + assert_array_equals(document.getElementsByTagName("test:aç"), [], "All lowercase input") +}, "Element in non-HTML namespace, prefix, non-ascii characters in name") + +test(function() { + var actual = document.getElementsByTagName("*"); + var expected = []; + var get_elements = function(node) { + for (var i = 0; i < node.childNodes.length; i++) { + var child = node.childNodes[i]; + if (child.nodeType === child.ELEMENT_NODE) { + expected.push(child); + get_elements(child); + } + } + } + get_elements(document); + assert_array_equals(actual, expected); +}, "getElementsByTagName('*')") +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName.html b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName.html new file mode 100644 index 0000000000..00e3435c4c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagName.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.getElementsByTagName</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbytagname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-Element-getElementsByTagName.js"></script> +<div id="log"></div> +<script> +test_getElementsByTagName(document, document.body); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-getElementsByTagNameNS.html b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagNameNS.html new file mode 100644 index 0000000000..063dc98215 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-getElementsByTagNameNS.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.getElementsByTagNameNS</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbytagnamens"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-Element-getElementsByTagNameNS.js"></script> +<div id="log"></div> +<script> +test_getElementsByTagNameNS(document, document.body); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-implementation.html b/testing/web-platform/tests/dom/nodes/Document-implementation.html new file mode 100644 index 0000000000..aed5259659 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-implementation.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.implementation</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-implementation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var implementation = document.implementation; + assert_true(implementation instanceof DOMImplementation, + "implementation should implement DOMImplementation"); + assert_equals(document.implementation, implementation); +}, "Getting implementation off the same document"); + +test(function() { + var doc = document.implementation.createHTMLDocument(); + assert_not_equals(document.implementation, doc.implementation); +}, "Getting implementation off different documents"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Document-importNode.html b/testing/web-platform/tests/dom/nodes/Document-importNode.html new file mode 100644 index 0000000000..d27cce6c56 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Document-importNode.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Document.importNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-importnode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var doc = document.implementation.createHTMLDocument("Title"); + var div = doc.body.appendChild(doc.createElement("div")); + div.appendChild(doc.createElement("span")); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + var newDiv = document.importNode(div); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + assert_equals(newDiv.ownerDocument, document); + assert_equals(newDiv.firstChild, null); +}, "No 'deep' argument.") +test(function() { + var doc = document.implementation.createHTMLDocument("Title"); + var div = doc.body.appendChild(doc.createElement("div")); + div.appendChild(doc.createElement("span")); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + var newDiv = document.importNode(div, undefined); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + assert_equals(newDiv.ownerDocument, document); + assert_equals(newDiv.firstChild, null); +}, "Undefined 'deep' argument.") +test(function() { + var doc = document.implementation.createHTMLDocument("Title"); + var div = doc.body.appendChild(doc.createElement("div")); + div.appendChild(doc.createElement("span")); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + var newDiv = document.importNode(div, true); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + assert_equals(newDiv.ownerDocument, document); + assert_equals(newDiv.firstChild.ownerDocument, document); +}, "True 'deep' argument.") +test(function() { + var doc = document.implementation.createHTMLDocument("Title"); + var div = doc.body.appendChild(doc.createElement("div")); + div.appendChild(doc.createElement("span")); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + var newDiv = document.importNode(div, false); + assert_equals(div.ownerDocument, doc); + assert_equals(div.firstChild.ownerDocument, doc); + assert_equals(newDiv.ownerDocument, document); + assert_equals(newDiv.firstChild, null); +}, "False 'deep' argument.") + +test(function() { + let doc = document.implementation.createHTMLDocument("Title"); + doc.body.setAttributeNS("http://example.com/", "p:name", "value"); + let originalAttr = doc.body.getAttributeNodeNS("http://example.com/", "name"); + let imported = document.importNode(originalAttr, true); + assert_equals(imported.prefix, originalAttr.prefix); + assert_equals(imported.namespaceURI, originalAttr.namespaceURI); + assert_equals(imported.localName, originalAttr.localName); +}, "Import an Attr node with namespace/prefix correctly."); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DocumentFragment-constructor.html b/testing/web-platform/tests/dom/nodes/DocumentFragment-constructor.html new file mode 100644 index 0000000000..e97a7c4836 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentFragment-constructor.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DocumentFragment constructor</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documentfragment-documentfragment"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const fragment = new DocumentFragment(); + assert_equals(fragment.ownerDocument, document); +}, "Sets the owner document to the current global object associated document"); + +test(() => { + const fragment = new DocumentFragment(); + const text = document.createTextNode(""); + fragment.appendChild(text); + assert_equals(fragment.firstChild, text); +}, "Create a valid document DocumentFragment"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DocumentFragment-getElementById.html b/testing/web-platform/tests/dom/nodes/DocumentFragment-getElementById.html new file mode 100644 index 0000000000..ce0d302c12 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentFragment-getElementById.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DocumentFragment.prototype.getElementById</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<template> + <div id="bar"> + <span id="foo" data-yes></span> + </div> + <div id="foo"> + <span id="foo"></span> + <ul id="bar"> + <li id="foo"></li> + </ul> + </div> +</template> + +<script> +"use strict"; + +test(() => { + assert_equals(typeof DocumentFragment.prototype.getElementById, "function", "It must exist on the prototype"); + assert_equals(typeof document.createDocumentFragment().getElementById, "function", "It must exist on an instance"); +}, "The method must exist"); + +test(() => { + assert_equals(document.createDocumentFragment().getElementById("foo"), null); + assert_equals(document.createDocumentFragment().getElementById(""), null); +}, "It must return null when there are no matches"); + +test(() => { + const frag = document.createDocumentFragment(); + frag.appendChild(document.createElement("div")); + frag.appendChild(document.createElement("span")); + frag.childNodes[0].id = "foo"; + frag.childNodes[1].id = "foo"; + + assert_equals(frag.getElementById("foo"), frag.childNodes[0]); +}, "It must return the first element when there are matches"); + +test(() => { + const frag = document.createDocumentFragment(); + frag.appendChild(document.createElement("div")); + frag.childNodes[0].setAttribute("id", ""); + + assert_equals( + frag.getElementById(""), + null, + "Even if there is an element with an empty-string ID attribute, it must not be returned" + ); +}, "Empty string ID values"); + +test(() => { + const frag = document.querySelector("template").content; + + assert_true(frag.getElementById("foo").hasAttribute("data-yes")); +}, "It must return the first element when there are matches, using a template"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html b/testing/web-platform/tests/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html new file mode 100644 index 0000000000..8049363885 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll should still work on DocumentFragments after they are modified</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2290 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const frag = document.createDocumentFragment(); +frag.appendChild(document.createElement("div")); + +assert_array_equals(frag.querySelectorAll("img"), [], "before modification"); + +frag.appendChild(document.createElement("div")); + +// If the bug is present, this will throw. +assert_array_equals(frag.querySelectorAll("img"), [], "after modification"); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/DocumentType-literal-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/DocumentType-literal-xhtml.xhtml new file mode 100644 index 0000000000..2b6965c14b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentType-literal-xhtml.xhtml @@ -0,0 +1,23 @@ +<!DOCTYPE html PUBLIC "STAFF" "staffNS.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>DocumentType literals</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-name"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-publicid"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-systemid"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +test(function() { + var doctype = document.firstChild; + assert_true(doctype instanceof DocumentType) + assert_equals(doctype.name, "html") + assert_equals(doctype.publicId, 'STAFF') + assert_equals(doctype.systemId, 'staffNS.dtd') +}) +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/DocumentType-literal.html b/testing/web-platform/tests/dom/nodes/DocumentType-literal.html new file mode 100644 index 0000000000..a755c397b0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentType-literal.html @@ -0,0 +1,17 @@ +<!DOCTYPE html PUBLIC "STAFF" "staffNS.dtd"> +<title>DocumentType literals</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-name"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-publicid"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documenttype-systemid"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var doctype = document.firstChild; + assert_true(doctype instanceof DocumentType) + assert_equals(doctype.name, "html") + assert_equals(doctype.publicId, 'STAFF') + assert_equals(doctype.systemId, 'staffNS.dtd') +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/DocumentType-remove.html b/testing/web-platform/tests/dom/nodes/DocumentType-remove.html new file mode 100644 index 0000000000..9e18d3511a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/DocumentType-remove.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>DocumentType.remove</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-remove"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="ChildNode-remove.js"></script> +<div id=log></div> +<script> +var node, parentNode; +setup(function() { + node = document.implementation.createDocumentType("html", "", ""); + parentNode = document.implementation.createDocument(null, "", null); +}); +testRemove(node, parentNode, "doctype"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElement-null-svg.svg b/testing/web-platform/tests/dom/nodes/Element-childElement-null-svg.svg new file mode 100644 index 0000000000..388482874b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElement-null-svg.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>Null test</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of firstElementChild and lastChildElement returning null</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle" font-weight="bold">Test</text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.firstElementChild, null) + assert_equals(parentEl.lastElementChild, null) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElement-null-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-childElement-null-xhtml.xhtml new file mode 100644 index 0000000000..daedab6d97 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElement-null-xhtml.xhtml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Null Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of firstElementChild and lastChildElement returning null</h1> +<div id="log"></div> +<p id="parentEl" style="font-weight:bold;">Test.</p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.firstElementChild, null) + assert_equals(parentEl.lastElementChild, null) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElement-null.html b/testing/web-platform/tests/dom/nodes/Element-childElement-null.html new file mode 100644 index 0000000000..1863a41da5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElement-null.html @@ -0,0 +1,15 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Null test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of firstElementChild and lastChildElement returning null</h1> +<div id="log"></div> +<p id="parentEl" style="font-weight:bold;">Test.</p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.firstElementChild, null) + assert_equals(parentEl.lastElementChild, null) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-svg.svg b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-svg.svg new file mode 100644 index 0000000000..d149f1ea3f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-svg.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>Dynamic Adding of Elements</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of Dynamic Adding of Elements</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is +<tspan id="first_element_child" font-weight="bold">unknown.</tspan></text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var newChild = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + parentEl.appendChild(newChild); + assert_equals(parentEl.childElementCount, 2) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-xhtml.xhtml new file mode 100644 index 0000000000..c97ed1965b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add-xhtml.xhtml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Dynamic Adding of Elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of Dynamic Adding of Elements</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span></p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var newChild = document.createElement("span"); + parentEl.appendChild(newChild); + assert_equals(parentEl.childElementCount, 2) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add.html b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add.html new file mode 100644 index 0000000000..3e7490b21d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Dynamic Adding of Elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of Dynamic Adding of Elements</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span></p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var newChild = document.createElement("span"); + parentEl.appendChild(newChild); + assert_equals(parentEl.childElementCount, 2) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-svg.svg b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-svg.svg new file mode 100644 index 0000000000..bf99de65aa --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-svg.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>Dynamic Removal of Elements</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of Dynamic Removal of Elements</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is +<tspan id="first_element_child" font-weight="bold">unknown.</tspan><tspan id="last_element_child"> </tspan></text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + parentEl.removeChild(lec); + assert_equals(parentEl.childElementCount, 1) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-xhtml.xhtml new file mode 100644 index 0000000000..f0009b0a77 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove-xhtml.xhtml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Dynamic Removal of Elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of Removal Adding of Elements</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span><span id="last_element_child"> </span></p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + parentEl.removeChild(lec); + assert_equals(parentEl.childElementCount, 1) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove.html b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove.html new file mode 100644 index 0000000000..3f7e7c7ead --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Dynamic Removal of Elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of Dynamic Removal of Elements</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">unknown.</span><span id="last_element_child"> </span></p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + parentEl.removeChild(lec); + assert_equals(parentEl.childElementCount, 1) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-svg.svg b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-svg.svg new file mode 100644 index 0000000000..8ba5743607 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-svg.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>childElementCount</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of childElementCount with No Child Element Nodes</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle" font-weight="bold">Test</text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.childElementCount, 0) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-xhtml.xhtml new file mode 100644 index 0000000000..f567a20c23 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild-xhtml.xhtml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>childElementCount without Child Element Nodes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of childElementCount with No Child Element Nodes</h1> +<div id="log"></div> +<p id="parentEl" style="font-weight:bold;">Test.</p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.childElementCount, 0) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild.html b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild.html new file mode 100644 index 0000000000..fb52fb205c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>childElementCount without Child Element Nodes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of childElementCount with No Child Element Nodes</h1> +<div id="log"></div> +<p id="parentEl" style="font-weight:bold;">Test.</p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl") + assert_equals(parentEl.childElementCount, 0) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-svg.svg b/testing/web-platform/tests/dom/nodes/Element-childElementCount-svg.svg new file mode 100644 index 0000000000..ff93eff625 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-svg.svg @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>childElementCount</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of childElementCount</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of <tspan id="first_element_child"><tspan>this</tspan> <tspan>test</tspan></tspan> is +<tspan id="middle_element_child" font-weight="bold">unknown.</tspan> + + + +<tspan id="last_element_child" style="display:none;">fnord</tspan> </text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_true("childElementCount" in parentEl) + assert_equals(parentEl.childElementCount, 3) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-childElementCount-xhtml.xhtml new file mode 100644 index 0000000000..6b719ff7a8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount-xhtml.xhtml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>childElementCount</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of childElementCount</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child"><span>this</span> <span>test</span></span> is +<span id="middle_element_child" style="font-weight:bold;">unknown.</span> + + + +<span id="last_element_child" style="display:none;">fnord</span> </p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + assert_true("childElementCount" in parentEl) + assert_equals(parentEl.childElementCount, 3) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-childElementCount.html b/testing/web-platform/tests/dom/nodes/Element-childElementCount.html new file mode 100644 index 0000000000..8cfe567f91 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-childElementCount.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>childElementCount</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of childElementCount</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child"><span>this</span> <span>test</span></span> is +<span id="middle_element_child" style="font-weight:bold;">given above.</span> + + + +<span id="last_element_child" style="display:none;">fnord</span> </p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl") + assert_true("childElementCount" in parentEl) + assert_equals(parentEl.childElementCount, 3) +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-children.html b/testing/web-platform/tests/dom/nodes/Element-children.html new file mode 100644 index 0000000000..c0210f9667 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-children.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<title>HTMLCollection edge cases</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div id="test"><img><img id=foo><img id=foo><img name="bar"></div> +<script> +setup(function() { + // Add some non-HTML elements in there to test what happens with those. + var container = document.getElementById("test"); + var child = document.createElementNS("", "img"); + child.setAttribute("id", "baz"); + container.appendChild(child); + + child = document.createElementNS("", "img"); + child.setAttribute("name", "qux"); + container.appendChild(child); +}); + +test(function() { + var container = document.getElementById("test"); + var result = container.children.item("foo"); + assert_true(result instanceof Element, "Expected an Element."); + assert_false(result.hasAttribute("id"), "Expected the IDless Element.") +}) + +test(function() { + var container = document.getElementById("test"); + var list = container.children; + var result = []; + for (var p in list) { + if (list.hasOwnProperty(p)) { + result.push(p); + } + } + assert_array_equals(result, ['0', '1', '2', '3', '4', '5']); + result = Object.getOwnPropertyNames(list); + assert_array_equals(result, ['0', '1', '2', '3', '4', '5', 'foo', 'bar', 'baz']); + + // Mapping of exposed names to their indices in the list. + var exposedNames = { 'foo': 1, 'bar': 3, 'baz': 4 }; + for (var exposedName in exposedNames) { + assert_true(exposedName in list); + assert_true(list.hasOwnProperty(exposedName)); + assert_equals(list[exposedName], list.namedItem(exposedName)); + assert_equals(list[exposedName], list.item(exposedNames[exposedName])); + assert_true(list[exposedName] instanceof Element); + } + + var unexposedNames = ['qux']; + for (var unexposedName of unexposedNames) { + assert_false(unexposedName in list); + assert_false(list.hasOwnProperty(unexposedName)); + assert_equals(list[unexposedName], undefined); + assert_equals(list.namedItem(unexposedName), null); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-classlist.html b/testing/web-platform/tests/dom/nodes/Element-classlist.html new file mode 100644 index 0000000000..2b5a271ba4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-classlist.html @@ -0,0 +1,478 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test for the classList element attribute</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="content"></div> +<script> +const SVG_NS = "http://www.w3.org/2000/svg"; +const XHTML_NS = "http://www.w3.org/1999/xhtml" +const MATHML_NS = "http://www.w3.org/1998/Math/MathML"; + +function setClass(e, newVal) { + if (newVal === null) { + e.removeAttribute("class"); + } else { + e.setAttribute("class", newVal); + } +} + +function checkModification(e, funcName, args, expectedRes, before, after, + expectedException, desc) { + if (!Array.isArray(args)) { + args = [args]; + } + + test(function() { + var shouldThrow = typeof(expectedException) === "string"; + if (shouldThrow) { + // If an exception is thrown, the class attribute shouldn't change. + after = before; + } + setClass(e, before); + + var obs; + // If we have MutationObservers available, do some checks to make + // sure attribute sets are happening at sane times. + if (self.MutationObserver) { + obs = new MutationObserver(() => {}); + obs.observe(e, { attributes: true }); + } + if (shouldThrow) { + assert_throws_dom(expectedException, function() { + var list = e.classList; + var res = list[funcName].apply(list, args); + }); + } else { + var list = e.classList; + var res = list[funcName].apply(list, args); + } + if (obs) { + var mutationRecords = obs.takeRecords(); + obs.disconnect(); + if (shouldThrow) { + assert_equals(mutationRecords.length, 0, + "There should have been no mutation"); + } else if (funcName == "replace") { + assert_equals(mutationRecords.length == 1, + expectedRes, + "Should have a mutation exactly when replace() returns true"); + } else { + // For other functions, would need to check when exactly + // mutations are supposed to happen. + } + } + if (!shouldThrow) { + assert_equals(res, expectedRes, "wrong return value"); + } + + var expectedAfter = after; + + assert_equals(e.getAttribute("class"), expectedAfter, + "wrong class after modification"); + }, "classList." + funcName + "(" + args.map(format_value).join(", ") + + ") with attribute value " + format_value(before) + desc); +} + +function assignToClassListStrict(e) { + "use strict"; + e.classList = "foo"; + e.removeAttribute("class"); +} + +function assignToClassList(e) { + var expect = e.classList; + e.classList = "foo"; + assert_equals(e.classList, expect, + "classList should be unchanged after assignment"); + e.removeAttribute("class"); +} + +function testClassList(e, desc) { + + // assignment + + test(function() { + assignToClassListStrict(e); + assignToClassList(e); + }, "Assigning to classList" + desc); + + // supports + test(function() { + assert_throws_js(TypeError, function() { + e.classList.supports("a"); + }) + }, ".supports() must throw TypeError" + desc); + + // length attribute + + function checkLength(value, length) { + test(function() { + setClass(e, value); + assert_equals(e.classList.length, length); + }, "classList.length when " + + (value === null ? "removed" : "set to " + format_value(value)) + desc); + } + + checkLength(null, 0); + checkLength("", 0); + checkLength(" \t \f", 0); + checkLength("a", 1); + checkLength("a A", 2); + checkLength("\r\na\t\f", 1); + checkLength("a a", 1); + checkLength("a a a a a a", 1); + checkLength("a a b b", 2); + checkLength("a A B b", 4); + checkLength("a b c c b a a b c c", 3); + checkLength(" a a b", 2); + checkLength("a\tb\nc\fd\re f", 6); + + // [Stringifies] + + function checkStringifier(value, expected) { + test(function() { + setClass(e, value); + assert_equals(e.classList.toString(), expected); + }, "classList.toString() when " + + (value === null ? "removed" : "set to " + format_value(value)) + desc); + } + + checkStringifier(null, ""); + checkStringifier("foo", "foo"); + checkStringifier(" a a b", " a a b"); + + // item() method + + function checkItems(attributeValue, expectedValues) { + function checkItemFunction(index, expected) { + assert_equals(e.classList.item(index), expected, + "classList.item(" + index + ")"); + } + + function checkItemArray(index, expected) { + assert_equals(e.classList[index], expected, "classList[" + index + "]"); + } + + test(function() { + setClass(e, attributeValue); + + checkItemFunction(-1, null); + checkItemArray(-1, undefined); + + var i = 0; + while (i < expectedValues.length) { + checkItemFunction(i, expectedValues[i]); + checkItemArray(i, expectedValues[i]); + i++; + } + + checkItemFunction(i, null); + checkItemArray(i, undefined); + + checkItemFunction(0xffffffff, null); + checkItemArray(0xffffffff, undefined); + + checkItemFunction(0xfffffffe, null); + checkItemArray(0xfffffffe, undefined); + }, "classList.item() when set to " + format_value(attributeValue) + desc); + } + + checkItems(null, []); + checkItems("a", ["a"]); + checkItems("aa AA aa", ["aa", "AA"]); + checkItems("a b", ["a", "b"]); + checkItems(" a a b", ["a", "b"]); + checkItems("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"]); + + // contains() method + + function checkContains(attributeValue, args, expectedRes) { + if (!Array.isArray(expectedRes)) { + expectedRes = Array(args.length).fill(expectedRes); + } + setClass(e, attributeValue); + for (var i = 0; i < args.length; i++) { + test(function() { + assert_equals(e.classList.contains(args[i]), expectedRes[i], + "classList.contains(\"" + args[i] + "\")"); + }, "classList.contains(" + format_value(args[i]) + ") when set to " + + format_value(attributeValue) + desc); + } + } + + checkContains(null, ["a", "", " "], false); + checkContains("", ["a"], false); + + checkContains("a", ["a"], true); + checkContains("a", ["aa", "b", "A", "a.", "a)",, "a'", 'a"', "a$", "a~", + "a?", "a\\"], false); + + // All "ASCII whitespace" per spec, before and after + checkContains("a", ["a\t", "\ta", "a\n", "\na", "a\f", "\fa", "a\r", "\ra", + "a ", " a"], false); + + checkContains("aa AA", ["aa", "AA", "aA"], [true, true, false]); + checkContains("a a a", ["a", "aa", "b"], [true, false, false]); + checkContains("a b c", ["a", "b"], true); + + checkContains("null undefined", [null, undefined], true); + checkContains("\t\n\f\r a\t\n\f\r b\t\n\f\r ", ["a", "b"], true); + + // add() method + + function checkAdd(before, argument, after, param) { + var expectedException = undefined; + var noop = false; + if (param == "noop") { + noop = true; + } else { + expectedException = param; + } + checkModification(e, "add", argument, undefined, before, after, + expectedException, desc); + // Also check force toggle. The only difference is that it doesn't run the + // update steps for a no-op. + if (!Array.isArray(argument)) { + checkModification(e, "toggle", [argument, true], true, before, + noop ? before : after, expectedException, desc); + } + } + + checkAdd(null, "", null, "SyntaxError"); + checkAdd(null, ["a", ""], null, "SyntaxError"); + checkAdd(null, " ", null, "InvalidCharacterError"); + checkAdd(null, "\ta", null, "InvalidCharacterError"); + checkAdd(null, "a\t", null, "InvalidCharacterError"); + checkAdd(null, "\na", null, "InvalidCharacterError"); + checkAdd(null, "a\n", null, "InvalidCharacterError"); + checkAdd(null, "\fa", null, "InvalidCharacterError"); + checkAdd(null, "a\f", null, "InvalidCharacterError"); + checkAdd(null, "\ra", null, "InvalidCharacterError"); + checkAdd(null, "a\r", null, "InvalidCharacterError"); + checkAdd(null, " a", null, "InvalidCharacterError"); + checkAdd(null, "a ", null, "InvalidCharacterError"); + checkAdd(null, ["a", " "], null, "InvalidCharacterError"); + checkAdd(null, ["a", "aa "], null, "InvalidCharacterError"); + + checkAdd("a", "a", "a"); + checkAdd("aa", "AA", "aa AA"); + checkAdd("a b c", "a", "a b c"); + checkAdd("a a a b", "a", "a b", "noop"); + checkAdd(null, "a", "a"); + checkAdd("", "a", "a"); + checkAdd(" ", "a", "a"); + checkAdd(" \f", "a", "a"); + checkAdd("a", "b", "a b"); + checkAdd("a b c", "d", "a b c d"); + checkAdd("a b c ", "d", "a b c d"); + checkAdd(" a a b", "c", "a b c"); + checkAdd(" a a b", "a", "a b", "noop"); + checkAdd("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", "a b c"); + + // multiple add + checkAdd("a b c ", ["d", "e"], "a b c d e"); + checkAdd("a b c ", ["a", "a"], "a b c"); + checkAdd("a b c ", ["d", "d"], "a b c d"); + checkAdd("a b c a ", [], "a b c"); + checkAdd(null, ["a", "b"], "a b"); + checkAdd("", ["a", "b"], "a b"); + + checkAdd(null, null, "null"); + checkAdd(null, undefined, "undefined"); + + // remove() method + + function checkRemove(before, argument, after, param) { + var expectedException = undefined; + var noop = false; + if (param == "noop") { + noop = true; + } else { + expectedException = param; + } + checkModification(e, "remove", argument, undefined, before, after, + expectedException, desc); + // Also check force toggle. The only difference is that it doesn't run the + // update steps for a no-op. + if (!Array.isArray(argument)) { + checkModification(e, "toggle", [argument, false], false, before, + noop ? before : after, expectedException, desc); + } + } + + checkRemove(null, "", null, "SyntaxError"); + checkRemove(null, " ", null, "InvalidCharacterError"); + checkRemove("\ta", "\ta", "\ta", "InvalidCharacterError"); + checkRemove("a\t", "a\t", "a\t", "InvalidCharacterError"); + checkRemove("\na", "\na", "\na", "InvalidCharacterError"); + checkRemove("a\n", "a\n", "a\n", "InvalidCharacterError"); + checkRemove("\fa", "\fa", "\fa", "InvalidCharacterError"); + checkRemove("a\f", "a\f", "a\f", "InvalidCharacterError"); + checkRemove("\ra", "\ra", "\ra", "InvalidCharacterError"); + checkRemove("a\r", "a\r", "a\r", "InvalidCharacterError"); + checkRemove(" a", " a", " a", "InvalidCharacterError"); + checkRemove("a ", "a ", "a ", "InvalidCharacterError"); + checkRemove("aa ", "aa ", null, "InvalidCharacterError"); + + checkRemove(null, "a", null); + checkRemove("", "a", ""); + checkRemove("a b c", "d", "a b c", "noop"); + checkRemove("a b c", "A", "a b c", "noop"); + checkRemove(" a a a ", "a", ""); + checkRemove("a b", "a", "b"); + checkRemove("a b ", "a", "b"); + checkRemove("a a b", "a", "b"); + checkRemove("aa aa bb", "aa", "bb"); + checkRemove("a a b a a c a a", "a", "b c"); + + checkRemove("a b c", "b", "a c"); + checkRemove("aaa bbb ccc", "bbb", "aaa ccc"); + checkRemove(" a b c ", "b", "a c"); + checkRemove("a b b b c", "b", "a c"); + + checkRemove("a b c", "c", "a b"); + checkRemove(" a b c ", "c", "a b"); + checkRemove("a b c c c", "c", "a b"); + + checkRemove("a b a c a d a", "a", "b c d"); + checkRemove("AA BB aa CC AA dd aa", "AA", "BB aa CC dd"); + + checkRemove("\ra\na\ta\f", "a", ""); + checkRemove("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "b"); + + // multiple remove + checkRemove("a b c ", ["d", "e"], "a b c"); + checkRemove("a b c ", ["a", "b"], "c"); + checkRemove("a b c ", ["a", "c"], "b"); + checkRemove("a b c ", ["a", "a"], "b c"); + checkRemove("a b c ", ["d", "d"], "a b c"); + checkRemove("a b c ", [], "a b c"); + checkRemove(null, ["a", "b"], null); + checkRemove("", ["a", "b"], ""); + checkRemove("a a", [], "a"); + + checkRemove("null", null, ""); + checkRemove("undefined", undefined, ""); + + // toggle() method + + function checkToggle(before, argument, expectedRes, after, expectedException) { + checkModification(e, "toggle", argument, expectedRes, before, after, + expectedException, desc); + } + + checkToggle(null, "", null, null, "SyntaxError"); + checkToggle(null, "aa ", null, null, "InvalidCharacterError"); + + checkToggle(null, "a", true, "a"); + checkToggle("", "a", true, "a"); + checkToggle(" ", "a", true, "a"); + checkToggle(" \f", "a", true, "a"); + checkToggle("a", "b", true, "a b"); + checkToggle("a", "A", true, "a A"); + checkToggle("a b c", "d", true, "a b c d"); + checkToggle(" a a b", "d", true, "a b d"); + + checkToggle("a", "a", false, ""); + checkToggle(" a a a ", "a", false, ""); + checkToggle(" A A A ", "a", true, "A a"); + checkToggle(" a b c ", "b", false, "a c"); + checkToggle(" a b c b b", "b", false, "a c"); + checkToggle(" a b c ", "c", false, "a b"); + checkToggle(" a b c ", "a", false, "b c"); + checkToggle(" a a b", "b", false, "a"); + checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", false, "b"); + checkToggle("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "c", true, "a b c"); + + checkToggle("null", null, false, ""); + checkToggle("", null, true, "null"); + checkToggle("undefined", undefined, false, ""); + checkToggle("", undefined, true, "undefined"); + + + // replace() method + function checkReplace(before, token, newToken, expectedRes, after, expectedException) { + checkModification(e, "replace", [token, newToken], expectedRes, before, + after, expectedException, desc); + } + + checkReplace(null, "", "a", null, null, "SyntaxError"); + checkReplace(null, "", " ", null, null, "SyntaxError"); + checkReplace(null, " ", "a", null, null, "InvalidCharacterError"); + checkReplace(null, "\ta", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "a\t", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "\na", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "a\n", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "\fa", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "a\f", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "\ra", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "a\r", "b", null, null, "InvalidCharacterError"); + checkReplace(null, " a", "b", null, null, "InvalidCharacterError"); + checkReplace(null, "a ", "b", null, null, "InvalidCharacterError"); + + checkReplace(null, "a", "", null, null, "SyntaxError"); + checkReplace(null, " ", "", null, null, "SyntaxError"); + checkReplace(null, "a", " ", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "\ta", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "a\t", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "\na", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "a\n", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "\fa", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "a\f", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "\ra", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "a\r", null, null, "InvalidCharacterError"); + checkReplace(null, "b", " a", null, null, "InvalidCharacterError"); + checkReplace(null, "b", "a ", null, null, "InvalidCharacterError"); + + checkReplace("a", "a", "a", true, "a"); + checkReplace("a", "a", "b", true, "b"); + checkReplace("a", "A", "b", false, "a"); + checkReplace("a b", "b", "A", true, "a A"); + checkReplace("a b", "c", "a", false, "a b"); + checkReplace("a b c", "d", "e", false, "a b c"); + // https://github.com/whatwg/dom/issues/443 + checkReplace("a a a b", "a", "a", true, "a b"); + checkReplace("a a a b", "c", "d", false, "a a a b"); + checkReplace(null, "a", "b", false, null); + checkReplace("", "a", "b", false, ""); + checkReplace(" ", "a", "b", false, " "); + checkReplace(" a \f", "a", "b", true, "b"); + checkReplace("a b c", "b", "d", true, "a d c"); + checkReplace("a b c", "c", "a", true, "a b"); + checkReplace("c b a", "c", "a", true, "a b"); + checkReplace("a b a", "a", "c", true, "c b"); + checkReplace("a b a", "b", "c", true, "a c"); + checkReplace(" a a b", "a", "c", true, "c b"); + checkReplace(" a a b", "b", "c", true, "a c"); + checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "a", "c", true, "c b"); + checkReplace("\t\n\f\r a\t\n\f\r b\t\n\f\r ", "b", "c", true, "a c"); + + checkReplace("a null", null, "b", true, "a b"); + checkReplace("a b", "a", null, true, "null b"); + checkReplace("a undefined", undefined, "b", true, "a b"); + checkReplace("a b", "a", undefined, true, "undefined b"); +} + +var content = document.getElementById("content"); + +var htmlNode = document.createElement("div"); +content.appendChild(htmlNode); +testClassList(htmlNode, " (HTML node)"); + +var xhtmlNode = document.createElementNS(XHTML_NS, "div"); +content.appendChild(xhtmlNode); +testClassList(xhtmlNode, " (XHTML node)"); + +var mathMLNode = document.createElementNS(MATHML_NS, "math"); +content.appendChild(mathMLNode); +testClassList(mathMLNode, " (MathML node)"); + +var xmlNode = document.createElementNS(null, "foo"); +content.appendChild(xmlNode); +testClassList(xmlNode, " (XML node with null namespace)"); + +var fooNode = document.createElementNS("http://example.org/foo", "foo"); +content.appendChild(fooNode); +testClassList(fooNode, " (foo node)"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-closest.html b/testing/web-platform/tests/dom/nodes/Element-closest.html new file mode 100644 index 0000000000..386e3bd251 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-closest.html @@ -0,0 +1,73 @@ +<!DOCTYPE HTML> +<meta charset=utf8> +<title>Test for Element.closest</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body id="body"> + <div id="test8" class="div3" style="display:none"> + <div id="test7" class="div2"> + <div id="test6" class="div1"> + <form id="test10" class="form2"></form> + <form id="test5" class="form1" name="form-a"> + <input id="test1" class="input1" required> + <fieldset class="fieldset2" id="test2"> + <select id="test3" class="select1" required> + <option default id="test4" value="">Test4</option> + <option selected id="test11">Test11</option> + <option id="test12">Test12</option> + <option id="test13">Test13</option> + </select> + <input id="test9" type="text" required> + </fieldset> + </form> + </div> + </div> + </div> + <div id=log></div> +<script> + do_test("select" , "test12", "test3"); + do_test("fieldset" , "test13", "test2"); + do_test("div" , "test13", "test6"); + do_test("body" , "test3" , "body"); + + do_test("[default]" , "test4" , "test4"); + do_test("[selected]" , "test4" , ""); + do_test("[selected]" , "test11", "test11"); + do_test('[name="form-a"]' , "test12", "test5"); + do_test('form[name="form-a"]' , "test13", "test5"); + do_test("input[required]" , "test9" , "test9"); + do_test("select[required]" , "test9" , ""); + + do_test("div:not(.div1)" , "test13", "test7"); + do_test("div.div3" , "test6" , "test8"); + do_test("div#test7" , "test1" , "test7"); + + do_test(".div3 > .div2" , "test12", "test7"); + do_test(".div3 > .div1" , "test12", ""); + do_test("form > input[required]" , "test9" , ""); + do_test("fieldset > select[required]", "test12", "test3"); + + do_test("input + fieldset" , "test6" , ""); + do_test("form + form" , "test3" , "test5"); + do_test("form + form" , "test5" , "test5"); + + do_test(":empty" , "test10", "test10"); + do_test(":last-child" , "test11", "test2"); + do_test(":first-child" , "test12", "test3"); + do_test(":invalid" , "test11", "test2"); + + do_test(":scope" , "test4", "test4"); + do_test("select > :scope" , "test4", "test4"); + do_test("div > :scope" , "test4", ""); + do_test(":has(> :scope)" , "test4", "test3"); +function do_test(aSelector, aElementId, aTargetId) { + test(function() { + var el = document.getElementById(aElementId).closest(aSelector); + if (el === null) { + assert_equals("", aTargetId, aSelector); + } else { + assert_equals(el.id, aTargetId, aSelector); + } + }, "Element.closest with context node '" + aElementId + "' and selector '" + aSelector + "'"); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity-xhtml.xhtml new file mode 100644 index 0000000000..f28005e9c8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity-xhtml.xhtml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" +[ +<!ENTITY tree "<span id='first_element_child' style='font-weight:bold;'>unknown.</span>"> +]> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<title>Entity References</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of Entity References</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is &tree;</p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity.svg b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity.svg new file mode 100644 index 0000000000..3a20ea79ab --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" +[ +<!ENTITY tree "<tspan id='first_element_child' font-weight='bold'>unknown.</tspan>"> +]> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>Entity References</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of Entity References</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is &tree;</text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl") + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-svg.svg b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-svg.svg new file mode 100644 index 0000000000..d42c08777c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-svg.svg @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + xmlns:pickle="http://ns.example.org/pickle" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>firstElementChild with namespaces</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of firstElementChild with namespaces</text> +<g id="parentEl"> + <pickle:dill id="first_element_child"/> +</g> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") + assert_equals(fec.localName, "dill") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-xhtml.xhtml new file mode 100644 index 0000000000..29441d2786 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace-xhtml.xhtml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:pickle="http://ns.example.org/pickle"> +<head> +<title>firstElementChild with namespaces</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of firstElementChild with namespaces</h1> +<div id="parentEl"> + <pickle:dill id="first_element_child"/> +</div> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span></p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") + assert_equals(fec.localName, "dill") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace.html b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace.html new file mode 100644 index 0000000000..629deab3ae --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>firstElementChild with namespaces</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of firstElementChild with namespaces</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is a unknown.</p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl") + var el = document.createElementNS("http://ns.example.org/pickle", "pickle:dill") + el.setAttribute("id", "first_element_child") + parentEl.appendChild(el) + var fec = parentEl.firstElementChild + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") + assert_equals(fec.localName, "dill") +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-svg.svg b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-svg.svg new file mode 100644 index 0000000000..359c5b82ca --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-svg.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>firstElementChild</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of firstElementChild</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is +<tspan id="first_element_child" font-weight="bold">unknown.</tspan></text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-xhtml.xhtml new file mode 100644 index 0000000000..302052b0fc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild-xhtml.xhtml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>firstElementChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of firstElementChild</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span></p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-firstElementChild.html b/testing/web-platform/tests/dom/nodes/Element-firstElementChild.html new file mode 100644 index 0000000000..12a0c5946e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-firstElementChild.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>firstElementChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of firstElementChild</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is +<span id="first_element_child" style="font-weight:bold;">logged above.</span></p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = parentEl.firstElementChild; + assert_true(!!fec) + assert_equals(fec.nodeType, 1) + assert_equals(fec.getAttribute("id"), "first_element_child") +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-getElementsByClassName.html b/testing/web-platform/tests/dom/nodes/Element-getElementsByClassName.html new file mode 100644 index 0000000000..bc87b05d25 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-getElementsByClassName.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<title>Element.getElementsByClassName</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var a = document.createElement("a"), b = document.createElement("b") + b.className = "foo" + a.appendChild(b) + var list = a.getElementsByClassName("foo") + assert_array_equals(list, [b]) + var secondList = a.getElementsByClassName("foo") + assert_true(list === secondList || list !== secondList, "Caching is allowed.") +}, "getElementsByClassName should work on disconnected subtrees.") + +test(function() { + var list = document.getElementsByClassName("foo") + assert_false(list instanceof NodeList, "NodeList") + assert_true(list instanceof HTMLCollection, "HTMLCollection") +}, "Interface should be correct.") + +test(function() { + var a = document.createElement("a"); + var b = document.createElement("b"); + var c = document.createElement("c"); + b.className = "foo"; + document.body.appendChild(a); + this.add_cleanup(function() {document.body.removeChild(a)}); + a.appendChild(b); + + var l = a.getElementsByClassName("foo"); + assert_true(l instanceof HTMLCollection); + assert_equals(l.length, 1); + + c.className = "foo"; + a.appendChild(c); + assert_equals(l.length, 2); + + a.removeChild(c); + assert_equals(l.length, 1); +}, "getElementsByClassName() should be a live collection"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess-iframe.xml b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess-iframe.xml new file mode 100644 index 0000000000..f3f286eafc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess-iframe.xml @@ -0,0 +1 @@ +<root/> diff --git a/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess.html b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess.html new file mode 100644 index 0000000000..c41ee2e877 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName-change-document-HTMLNess.html @@ -0,0 +1,51 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe src="Element-getElementsByTagName-change-document-HTMLNess-iframe.xml"></iframe> +<script> + setup({ single_test: true }); + onload = function() { + var parent = document.createElement("div"); + var child1 = document.createElementNS("http://www.w3.org/1999/xhtml", "a"); + child1.textContent = "xhtml:a"; + var child2 = document.createElementNS("http://www.w3.org/1999/xhtml", "A"); + child2.textContent = "xhtml:A"; + var child3 = document.createElementNS("", "a"); + child3.textContent = "a"; + var child4 = document.createElementNS("", "A"); + child4.textContent = "A"; + + parent.appendChild(child1); + parent.appendChild(child2); + parent.appendChild(child3); + parent.appendChild(child4); + + var list = parent.getElementsByTagName("A"); + assert_array_equals(list, [child1, child4], + "In an HTML document, should lowercase the tagname passed in for HTML " + + "elements only"); + + frames[0].document.documentElement.appendChild(parent); + assert_array_equals(list, [child1, child4], + "After changing document, should still be lowercasing for HTML"); + + assert_array_equals(parent.getElementsByTagName("A"), + [child2, child4], + "New list with same root and argument should not be lowercasing now"); + + // Now reinsert all those nodes into the parent, to blow away caches. + parent.appendChild(child1); + parent.appendChild(child2); + parent.appendChild(child3); + parent.appendChild(child4); + assert_array_equals(list, [child1, child4], + "After blowing away caches, should still have the same list"); + + assert_array_equals(parent.getElementsByTagName("A"), + [child2, child4], + "New list with same root and argument should still not be lowercasing"); + done(); + } +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName.html b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName.html new file mode 100644 index 0000000000..87c4fe934a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagName.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Element.getElementsByTagName</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-getelementsbytagname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-Element-getElementsByTagName.js"></script> +<div id="log"></div> +<script> +var element; +setup(function() { + element = document.createElement("div"); + element.appendChild(document.createTextNode("text")); + var p = element.appendChild(document.createElement("p")); + p.appendChild(document.createElement("a")) + .appendChild(document.createTextNode("link")); + p.appendChild(document.createElement("b")) + .appendChild(document.createTextNode("bold")); + p.appendChild(document.createElement("em")) + .appendChild(document.createElement("u")) + .appendChild(document.createTextNode("emphasized")); + element.appendChild(document.createComment("comment")); +}); + +test_getElementsByTagName(element, element); + +test(function() { + assert_array_equals(element.getElementsByTagName(element.localName), []); +}, "Matching the context object"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-getElementsByTagNameNS.html b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagNameNS.html new file mode 100644 index 0000000000..f826afc391 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-getElementsByTagNameNS.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Element.getElementsByTagNameNS</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-getelementsbytagnamens"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Document-Element-getElementsByTagNameNS.js"></script> +<div id="log"></div> +<script> +var element; +setup(function() { + element = document.createElement("div"); + element.appendChild(document.createTextNode("text")); + var p = element.appendChild(document.createElement("p")); + p.appendChild(document.createElement("a")) + .appendChild(document.createTextNode("link")); + p.appendChild(document.createElement("b")) + .appendChild(document.createTextNode("bold")); + p.appendChild(document.createElement("em")) + .appendChild(document.createElement("u")) + .appendChild(document.createTextNode("emphasized")); + element.appendChild(document.createComment("comment")); +}); + +test_getElementsByTagNameNS(element, element); + +test(function() { + assert_array_equals(element.getElementsByTagNameNS("*", element.localName), []); +}, "Matching the context object (wildcard namespace)"); + +test(function() { + assert_array_equals( + element.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", + element.localName), + []); +}, "Matching the context object (specific namespace)"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-hasAttribute.html b/testing/web-platform/tests/dom/nodes/Element-hasAttribute.html new file mode 100644 index 0000000000..26528d7569 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-hasAttribute.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.hasAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-hasattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span data-e2="2" data-F2="3" id="t"></span> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + + assert_true(el.hasAttribute("x")); + +}, "hasAttribute should check for attribute presence, irrespective of namespace"); + +test(() => { + + const el = document.getElementById("t"); + + assert_true(el.hasAttribute("data-e2")); + assert_true(el.hasAttribute("data-E2")); + assert_true(el.hasAttribute("data-f2")); + assert_true(el.hasAttribute("data-F2")); + +}, "hasAttribute should work with all attribute casings"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-hasAttributes.html b/testing/web-platform/tests/dom/nodes/Element-hasAttributes.html new file mode 100644 index 0000000000..fbb9c233b7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-hasAttributes.html @@ -0,0 +1,40 @@ +<!doctype html> +<meta charset="utf-8"> +<title></title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> + +<button></button> +<div id="foo"></div> +<p data-foo=""></p> + +<script> +test(function() { + var buttonElement = document.getElementsByTagName('button')[0]; + assert_equals(buttonElement.hasAttributes(), false, 'hasAttributes() on empty element must return false.'); + + var emptyDiv = document.createElement('div'); + assert_equals(emptyDiv.hasAttributes(), false, 'hasAttributes() on dynamically created empty element must return false.'); + +}, 'element.hasAttributes() must return false when the element does not have attribute.'); + +test(function() { + var divWithId = document.getElementById('foo'); + assert_equals(divWithId.hasAttributes(), true, 'hasAttributes() on element with id attribute must return true.'); + + var divWithClass = document.createElement('div'); + divWithClass.setAttribute('class', 'foo'); + assert_equals(divWithClass.hasAttributes(), true, 'hasAttributes() on dynamically created element with class attribute must return true.'); + + var pWithCustomAttr = document.getElementsByTagName('p')[0]; + assert_equals(pWithCustomAttr.hasAttributes(), true, 'hasAttributes() on element with custom attribute must return true.'); + + var divWithCustomAttr = document.createElement('div'); + divWithCustomAttr.setAttribute('data-custom', 'foo'); + assert_equals(divWithCustomAttr.hasAttributes(), true, 'hasAttributes() on dynamically created element with custom attribute must return true.'); + +}, 'element.hasAttributes() must return true when the element has attribute.'); + +</script> +</body> diff --git a/testing/web-platform/tests/dom/nodes/Element-insertAdjacentElement.html b/testing/web-platform/tests/dom/nodes/Element-insertAdjacentElement.html new file mode 100644 index 0000000000..9eafee6a76 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-insertAdjacentElement.html @@ -0,0 +1,91 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> + +<div id="target"></div> +<div id="parent"><span id=target2></span></div> +<div id="log" style="visibility:visible"></div> +<span id="test1"></span> +<span id="test2"></span> +<span id="test3"></span> +<span id="test4"></span> +<script> +var target = document.getElementById("target"); +var target2 = document.getElementById("target2"); + +test(function() { + assert_throws_dom("SyntaxError", function() { + target.insertAdjacentElement("test", document.getElementById("test1")) + }); + + assert_throws_dom("SyntaxError", function() { + target2.insertAdjacentElement("test", document.getElementById("test1")) + }); +}, "Inserting to an invalid location should cause a Syntax Error exception") + +test(function() { + var el = target.insertAdjacentElement("beforebegin", document.getElementById("test1")); + assert_equals(target.previousSibling.id, "test1"); + assert_equals(el.id, "test1"); + + el = target2.insertAdjacentElement("beforebegin", document.getElementById("test1")); + assert_equals(target2.previousSibling.id, "test1"); + assert_equals(el.id, "test1"); +}, "Inserted element should be target element's previous sibling for 'beforebegin' case") + +test(function() { + var el = target.insertAdjacentElement("afterbegin", document.getElementById("test2")); + assert_equals(target.firstChild.id, "test2"); + assert_equals(el.id, "test2"); + + el = target2.insertAdjacentElement("afterbegin", document.getElementById("test2")); + assert_equals(target2.firstChild.id, "test2"); + assert_equals(el.id, "test2"); +}, "Inserted element should be target element's first child for 'afterbegin' case") + +test(function() { + var el = target.insertAdjacentElement("beforeend", document.getElementById("test3")); + assert_equals(target.lastChild.id, "test3"); + assert_equals(el.id, "test3"); + + el = target2.insertAdjacentElement("beforeend", document.getElementById("test3")); + assert_equals(target2.lastChild.id, "test3"); + assert_equals(el.id, "test3"); +}, "Inserted element should be target element's last child for 'beforeend' case") + +test(function() { + var el = target.insertAdjacentElement("afterend", document.getElementById("test4")); + assert_equals(target.nextSibling.id, "test4"); + assert_equals(el.id, "test4"); + + el = target2.insertAdjacentElement("afterend", document.getElementById("test4")); + assert_equals(target2.nextSibling.id, "test4"); + assert_equals(el.id, "test4"); +}, "Inserted element should be target element's next sibling for 'afterend' case") + +test(function() { + var docElement = document.documentElement; + docElement.style.visibility="hidden"; + + assert_throws_dom("HierarchyRequestError", function() { + var el = docElement.insertAdjacentElement("beforebegin", document.getElementById("test1")); + assert_equals(el, null); + }); + + var el = docElement.insertAdjacentElement("afterbegin", document.getElementById("test2")); + assert_equals(docElement.firstChild.id, "test2"); + assert_equals(el.id, "test2"); + + el = docElement.insertAdjacentElement("beforeend", document.getElementById("test3")); + assert_equals(docElement.lastChild.id, "test3"); + assert_equals(el.id, "test3"); + + assert_throws_dom("HierarchyRequestError", function() { + var el = docElement.insertAdjacentElement("afterend", document.getElementById("test4")); + assert_equals(el, null); + }); +}, "Adding more than one child to document should cause a HierarchyRequestError exception") + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-insertAdjacentText.html b/testing/web-platform/tests/dom/nodes/Element-insertAdjacentText.html new file mode 100644 index 0000000000..be744fd49e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-insertAdjacentText.html @@ -0,0 +1,76 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<body style="visibility:hidden"> +<div id="target"></div> +<div id="parent"><span id=target2></span></div> +<div id="log" style="visibility:visible"></div> +</body> +<script> +var target = document.getElementById("target"); +var target2 = document.getElementById("target2"); + +test(function() { + assert_throws_dom("SyntaxError", function() { + target.insertAdjacentText("test", "text") + }); + + assert_throws_dom("SyntaxError", function() { + target2.insertAdjacentText("test", "test") + }); +}, "Inserting to an invalid location should cause a Syntax Error exception") + +test(function() { + target.insertAdjacentText("beforebegin", "test1"); + assert_equals(target.previousSibling.nodeValue, "test1"); + + target2.insertAdjacentText("beforebegin", "test1"); + assert_equals(target2.previousSibling.nodeValue, "test1"); +}, "Inserted text node should be target element's previous sibling for 'beforebegin' case") + +test(function() { + target.insertAdjacentText("afterbegin", "test2"); + assert_equals(target.firstChild.nodeValue, "test2"); + + target2.insertAdjacentText("afterbegin", "test2"); + assert_equals(target2.firstChild.nodeValue, "test2"); +}, "Inserted text node should be target element's first child for 'afterbegin' case") + +test(function() { + target.insertAdjacentText("beforeend", "test3"); + assert_equals(target.lastChild.nodeValue, "test3"); + + target2.insertAdjacentText("beforeend", "test3"); + assert_equals(target2.lastChild.nodeValue, "test3"); +}, "Inserted text node should be target element's last child for 'beforeend' case") + +test(function() { + target.insertAdjacentText("afterend", "test4"); + assert_equals(target.nextSibling.nodeValue, "test4"); + + target2.insertAdjacentText("afterend", "test4"); + assert_equals(target.nextSibling.nodeValue, "test4"); +}, "Inserted text node should be target element's next sibling for 'afterend' case") + +test(function() { + var docElement = document.documentElement; + docElement.style.visibility="hidden"; + + assert_throws_dom("HierarchyRequestError", function() { + docElement.insertAdjacentText("beforebegin", "text1") + }); + + docElement.insertAdjacentText("afterbegin", "test2"); + assert_equals(docElement.firstChild.nodeValue, "test2"); + + docElement.insertAdjacentText("beforeend", "test3"); + assert_equals(docElement.lastChild.nodeValue, "test3"); + + assert_throws_dom("HierarchyRequestError", function() { + docElement.insertAdjacentText("afterend", "test4") + }); +}, "Adding more than one child to document should cause a HierarchyRequestError exception") + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-lastElementChild-svg.svg b/testing/web-platform/tests/dom/nodes/Element-lastElementChild-svg.svg new file mode 100644 index 0000000000..1cec4a1308 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-lastElementChild-svg.svg @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>lastElementChild</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of lastElementChild</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of <tspan id="first_element_child">this test</tspan> is <tspan id="last_element_child" font-weight="bold">not</tspan> known.</text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + assert_true(!!lec) + assert_equals(lec.nodeType, 1) + assert_equals(lec.getAttribute("id"), "last_element_child") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-lastElementChild-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-lastElementChild-xhtml.xhtml new file mode 100644 index 0000000000..3150b92a42 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-lastElementChild-xhtml.xhtml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>firstElementChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of firstElementChild</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is <span id="last_element_child" style="font-weight:bold;">logged</span> above.</p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + assert_true(!!lec) + assert_equals(lec.nodeType, 1) + assert_equals(lec.getAttribute("id"), "last_element_child") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-lastElementChild.html b/testing/web-platform/tests/dom/nodes/Element-lastElementChild.html new file mode 100644 index 0000000000..de7aebdf24 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-lastElementChild.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>lastElementChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of lastElementChild</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is <span id="last_element_child" style="font-weight:bold;">logged</span> above.</p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = parentEl.lastElementChild; + assert_true(!!lec) + assert_equals(lec.nodeType, 1) + assert_equals(lec.getAttribute("id"), "last_element_child") +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-matches-init.js b/testing/web-platform/tests/dom/nodes/Element-matches-init.js new file mode 100644 index 0000000000..254af61565 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-matches-init.js @@ -0,0 +1,65 @@ +function init(e, method) { + /* + * This test suite tests Selectors API methods in 4 different contexts: + * 1. Document node + * 2. In-document Element node + * 3. Detached Element node (an element with no parent, not in the document) + * 4. Document Fragment node + * + * For each context, the following tests are run: + * + * The interface check tests ensure that each type of node exposes the Selectors API methods. + * + * The matches() tests are run + * All the selectors tested for both the valid and invalid selector tests are found in selectors.js. + * See comments in that file for documentation of the format used. + * + * The level2-lib.js file contains all the common test functions for running each of the aforementioned tests + */ + + var docType = "html"; // Only run tests suitable for HTML + + // Prepare the nodes for testing + var doc = e.target.contentDocument; // Document Node tests + + var element = doc.getElementById("root"); // In-document Element Node tests + + //Setup the namespace tests + setupSpecialElements(doc, element); + + var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document + // Element tests, but after running the Document tests. This + // tests that no elements that are not descendants of element + // are selected. + + traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying + elem.setAttribute("data-clone", ""); // that none of these elements ever match. + }); + + + var detached = element.cloneNode(true); // Detached Element Node tests + + var fragment = doc.createDocumentFragment(); // Fragment Node tests + fragment.appendChild(element.cloneNode(true)); + + // Setup Tests + interfaceCheckMatches(method, "Document", doc); + interfaceCheckMatches(method, "Detached Element", detached); + interfaceCheckMatches(method, "Fragment", fragment); + interfaceCheckMatches(method, "In-document Element", element); + + runSpecialMatchesTests(method, "DIV Element", element); + runSpecialMatchesTests(method, "NULL Element", document.createElement("null")); + runSpecialMatchesTests(method, "UNDEFINED Element", document.createElement("undefined")); + + runInvalidSelectorTestMatches(method, "Document", doc, invalidSelectors); + runInvalidSelectorTestMatches(method, "Detached Element", detached, invalidSelectors); + runInvalidSelectorTestMatches(method, "Fragment", fragment, invalidSelectors); + runInvalidSelectorTestMatches(method, "In-document Element", element, invalidSelectors); + + runMatchesTest(method, "In-document", doc, validSelectors, "html"); + runMatchesTest(method, "Detached", detached, validSelectors, "html"); + runMatchesTest(method, "Fragment", fragment, validSelectors, "html"); + + runMatchesTest(method, "In-document", doc, scopedSelectors, "html"); +} diff --git a/testing/web-platform/tests/dom/nodes/Element-matches-namespaced-elements.html b/testing/web-platform/tests/dom/nodes/Element-matches-namespaced-elements.html new file mode 100644 index 0000000000..e61b11ca61 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-matches-namespaced-elements.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>matches/webkitMatchesSelector must work when an element has a namespace</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression tests for https://github.com/jsdom/jsdom/issues/1846, https://github.com/jsdom/jsdom/issues/2247 --> + +<script> +"use strict"; + +for (const method of ["matches", "webkitMatchesSelector"]) { + test(() => { + assert_true(document.createElementNS("", "element")[method]("element")); + }, `empty string namespace, ${method}`); + + test(() => { + assert_true(document.createElementNS("urn:ns", "h")[method]("h")); + }, `has a namespace, ${method}`); + + test(() => { + assert_true(document.createElementNS("urn:ns", "h")[method]("*|h")); + }, `has a namespace, *|, ${method}`); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-matches.html b/testing/web-platform/tests/dom/nodes/Element-matches.html new file mode 100644 index 0000000000..de234b6639 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-matches.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title> +<!-- Selectors API Test Suite Version 3 --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/dom/nodes/selectors.js"></script> +<script src="/dom/nodes/ParentNode-querySelector-All.js"></script> +<script src="Element-matches.js"></script> +<script src="Element-matches-init.js"></script> +<style>iframe { visibility: hidden; position: absolute; }</style> + +<div id="log">This test requires JavaScript.</div> + +<script> + async_test(function() { + var frame = document.createElement("iframe"); + frame.onload = this.step_func_done(e => init(e, "matches" )); + frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target"; + document.body.appendChild(frame); + }); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-matches.js b/testing/web-platform/tests/dom/nodes/Element-matches.js new file mode 100644 index 0000000000..a1455c671f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-matches.js @@ -0,0 +1,135 @@ +/* + * Check that the matches() method exists on the given Node + */ +function interfaceCheckMatches(method, type, obj) { + if (obj.nodeType === obj.ELEMENT_NODE) { + test(function() { + assert_idl_attribute(obj, method, type + " supports " + method); + }, type + " supports " + method) + } else { + test(function() { + assert_false(method in obj, type + " supports " + method); + }, type + " should not support " + method) + } +} + +function runSpecialMatchesTests(method, type, element) { + test(function() { // 1 + if (element.tagName.toLowerCase() === "null") { + assert_true(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match."); + } else { + assert_false(element[method](null), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match."); + } + }, type + "." + method + "(null)") + + test(function() { // 2 + if (element.tagName.toLowerCase() === "undefined") { + assert_true(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should match."); + } else { + assert_false(element[method](undefined), "An element with the tag name '" + element.tagName.toLowerCase() + "' should not match."); + } + }, type + "." + method + "(undefined)") + + test(function() { // 3 + assert_throws_js(element.ownerDocument.defaultView.TypeError, function() { + element[method](); + }, "This should throw a TypeError.") + }, type + "." + method + " no parameter") +} + +/* + * Execute queries with the specified invalid selectors for matches() + * Only run these tests when errors are expected. Don't run for valid selector tests. + */ +function runInvalidSelectorTestMatches(method, type, root, selectors) { + if (root.nodeType === root.ELEMENT_NODE) { + for (var i = 0; i < selectors.length; i++) { + var s = selectors[i]; + var n = s["name"]; + var q = s["selector"]; + + test(function() { + assert_throws_dom( + "SyntaxError", + root.ownerDocument.defaultView.DOMException, + function() { + root[method](q) + } + ); + }, type + "." + method + ": " + n + ": " + q); + } + } +} + +function runMatchesTest(method, type, root, selectors, docType) { + var nodeType = getNodeType(root); + + for (var i = 0; i < selectors.length; i++) { + var s = selectors[i]; + var n = s["name"]; + var q = s["selector"]; + var e = s["expect"]; + var u = s["unexpected"]; + + var ctx = s["ctx"]; + var ref = s["ref"]; + + if ((!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1)) + && (s["testType"] & TEST_MATCH) ) { + + if (ctx && !ref) { + test(function() { + var j, element, refNode; + for (j = 0; j < e.length; j++) { + element = root.querySelector("#" + e[j]); + refNode = root.querySelector(ctx); + assert_true(element[method](q, refNode), "The element #" + e[j] + " should match the selector.") + } + + if (u) { + for (j = 0; j < u.length; j++) { + element = root.querySelector("#" + u[j]); + refNode = root.querySelector(ctx); + assert_false(element[method](q, refNode), "The element #" + u[j] + " should not match the selector.") + } + } + }, type + " Element." + method + ": " + n + " (with refNode Element): " + q); + } + + if (ref) { + test(function() { + var j, element, refNodes; + for (j = 0; j < e.length; j++) { + element = root.querySelector("#" + e[j]); + refNodes = root.querySelectorAll(ref); + assert_true(element[method](q, refNodes), "The element #" + e[j] + " should match the selector.") + } + + if (u) { + for (j = 0; j < u.length; j++) { + element = root.querySelector("#" + u[j]); + refNodes = root.querySelectorAll(ref); + assert_false(element[method](q, refNodes), "The element #" + u[j] + " should not match the selector.") + } + } + }, type + " Element." + method + ": " + n + " (with refNodes NodeList): " + q); + } + + if (!ctx && !ref) { + test(function() { + for (var j = 0; j < e.length; j++) { + var element = root.querySelector("#" + e[j]); + assert_true(element[method](q), "The element #" + e[j] + " should match the selector.") + } + + if (u) { + for (j = 0; j < u.length; j++) { + element = root.querySelector("#" + u[j]); + assert_false(element[method](q), "The element #" + u[j] + " should not match the selector.") + } + } + }, type + " Element." + method + ": " + n + " (with no refNodes): " + q); + } + } + } +} diff --git a/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-svg.svg b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-svg.svg new file mode 100644 index 0000000000..3e17cad20c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-svg.svg @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>nextElementSibling</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of nextElementSibling</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of <tspan id="first_element_child">this test</tspan> is <tspan id="last_element_child" font-weight="bold">unknown.</tspan></text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = document.getElementById("first_element_child"); + var nes = fec.nextElementSibling; + assert_true(!!nes) + assert_equals(nes.nodeType, 1) + assert_equals(nes.getAttribute("id"), "last_element_child") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-xhtml.xhtml new file mode 100644 index 0000000000..915209bda2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling-xhtml.xhtml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>nextElementSibling</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of nextElementSibling</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is <span id="last_element_child" style="font-weight:bold;">unknown.</span></p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = document.getElementById("first_element_child"); + var nes = fec.nextElementSibling; + assert_true(!!nes) + assert_equals(nes.nodeType, 1) + assert_equals(nes.getAttribute("id"), "last_element_child") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-nextElementSibling.html b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling.html new file mode 100644 index 0000000000..985c602f41 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-nextElementSibling.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>nextElementSibling</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of nextElementSibling</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is <span id="last_element_child" style="font-weight:bold;">unknown.</span></p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var fec = document.getElementById("first_element_child"); + var nes = fec.nextElementSibling; + assert_true(!!nes) + assert_equals(nes.nodeType, 1) + assert_equals(nes.getAttribute("id"), "last_element_child") +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-svg.svg b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-svg.svg new file mode 100644 index 0000000000..671d2c87f2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-svg.svg @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>previousElementSibling</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of previousElementSibling</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of <tspan id="first_element_child">this test</tspan> is +<tspan id="middle_element_child" font-weight="bold">unknown.</tspan> + + + +<tspan id="last_element_child" display="none">fnord</tspan> </text> + +<h:script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = document.getElementById("last_element_child"); + var pes = lec.previousElementSibling; + assert_true(!!pes) + assert_equals(pes.nodeType, 1) + assert_equals(pes.getAttribute("id"), "middle_element_child") +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-xhtml.xhtml new file mode 100644 index 0000000000..7fbbc6d384 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling-xhtml.xhtml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>previousElementSibling</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of previousElementSibling</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is +<span id="middle_element_child" style="font-weight:bold;">unknown.</span> + + + +<span id="last_element_child" style="display:none;">fnord</span> </p> +<script><![CDATA[ +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = document.getElementById("last_element_child"); + var pes = lec.previousElementSibling; + assert_true(!!pes) + assert_equals(pes.nodeType, 1) + assert_equals(pes.getAttribute("id"), "middle_element_child") +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-previousElementSibling.html b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling.html new file mode 100644 index 0000000000..02c7b16df5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-previousElementSibling.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>previousElementSibling</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of previousElementSibling</h1> +<div id="log"></div> +<p id="parentEl">The result of <span id="first_element_child">this test</span> is +<span id="middle_element_child" style="font-weight:bold;">unknown.</span> + + + +<span id="last_element_child" style="display:none;">fnord</span> </p> +<script> +test(function() { + var parentEl = document.getElementById("parentEl"); + var lec = document.getElementById("last_element_child"); + var pes = lec.previousElementSibling; + assert_true(!!pes) + assert_equals(pes.nodeType, 1) + assert_equals(pes.getAttribute("id"), "middle_element_child") +}) +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-remove.html b/testing/web-platform/tests/dom/nodes/Element-remove.html new file mode 100644 index 0000000000..ab642d660b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-remove.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Element.remove</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-childnode-remove"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="ChildNode-remove.js"></script> +<div id=log></div> +<script> +var node, parentNode; +setup(function() { + node = document.createElement("div"); + parentNode = document.createElement("div"); +}); +testRemove(node, parentNode, "element"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-removeAttribute.html b/testing/web-platform/tests/dom/nodes/Element-removeAttribute.html new file mode 100644 index 0000000000..df79e62cf4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-removeAttribute.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.removeAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-removeattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttribute("x", "first"); + el.setAttributeNS("foo", "x", "second"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "first"); + assert_equals(el.getAttributeNS(null, "x"), "first"); + assert_equals(el.getAttributeNS("foo", "x"), "second"); + + // removeAttribute removes the first attribute with name "x" that + // we set on the element, irrespective of namespace. + el.removeAttribute("x"); + + // The only attribute remaining should be the second one. + assert_equals(el.getAttribute("x"), "second"); + assert_equals(el.getAttributeNS(null, "x"), null); + assert_equals(el.getAttributeNS("foo", "x"), "second"); + assert_equals(el.attributes.length, 1, "one attribute"); + +}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " + + "not in a namespace"); + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + el.setAttributeNS("foo2", "x", "second"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "first"); + assert_equals(el.getAttributeNS("foo", "x"), "first"); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + + // removeAttribute removes the first attribute with name "x" that + // we set on the element, irrespective of namespace. + el.removeAttribute("x"); + + // The only attribute remaining should be the second one. + assert_equals(el.getAttribute("x"), "second"); + assert_equals(el.getAttributeNS("foo", "x"), null); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + assert_equals(el.attributes.length, 1, "one attribute"); + +}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " + + "in a namespace"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-removeAttributeNS.html b/testing/web-platform/tests/dom/nodes/Element-removeAttributeNS.html new file mode 100644 index 0000000000..a2773e6f1e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-removeAttributeNS.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>Element.removeAttributeNS</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="attributes.js"></script> +<div id="log"></div> +<script> +var XML = "http://www.w3.org/XML/1998/namespace" + +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XML, "a:bb", "pass") + attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb") + el.removeAttributeNS(XML, "a:bb") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb") +}, "removeAttributeNS should take a local name.") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-setAttribute-crbug-1138487.html b/testing/web-platform/tests/dom/nodes/Element-setAttribute-crbug-1138487.html new file mode 100644 index 0000000000..9aa9ed8139 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-setAttribute-crbug-1138487.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// Regression test for crbug.com/1138487. +// +// It was possible for a non-ASCII-lowercase string to be used when inserting +// into the attribute collection if a hashtable encountered it during probing +// while looking for the ASCII-lowercase equivalent. +// +// This caused such a string to be illegally used as an attribute name, thus +// causing inconsistent behavior in future attribute lookup. +test(() => { + const el = document.createElement('div'); + el.setAttribute('labelXQL', 'abc'); + el.setAttribute('_valueXQL', 'def'); + assert_equals(el.getAttribute('labelXQL'), 'abc'); + assert_equals(el.getAttribute('labelxql'), 'abc'); + assert_equals(el.getAttribute('_valueXQL'), 'def'); + assert_equals(el.getAttribute('_valuexql'), 'def'); +}, "Attributes first seen in mixed ASCII case should not be corrupted."); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-setAttribute.html b/testing/web-platform/tests/dom/nodes/Element-setAttribute.html new file mode 100644 index 0000000000..7609406815 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-setAttribute.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.setAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + el.setAttributeNS("foo2", "x", "second"); + + el.setAttribute("x", "changed"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "changed"); + assert_equals(el.getAttributeNS("foo", "x"), "changed"); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + +}, "setAttribute should change the first attribute, irrespective of namespace"); + +test(() => { + // https://github.com/whatwg/dom/issues/31 + + const el = document.createElement("p"); + el.setAttribute("FOO", "bar"); + + assert_equals(el.getAttribute("foo"), "bar"); + assert_equals(el.getAttribute("FOO"), "bar"); + assert_equals(el.getAttributeNS("", "foo"), "bar"); + assert_equals(el.getAttributeNS("", "FOO"), null); + +}, "setAttribute should lowercase before setting"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-svg.svg b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-svg.svg new file mode 100644 index 0000000000..48c981b8c8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-svg.svg @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:h="http://www.w3.org/1999/xhtml" + version="1.1" + width="100%" height="100%" viewBox="0 0 400 400"> +<title>Null test</title> +<h:script src="/resources/testharness.js"/> +<h:script src="/resources/testharnessreport.js"/> + +<text x="200" y="40" font-size="25" fill="black" text-anchor="middle">Test of previousElementSibling and nextElementSibling returning null</text> +<text id="parentEl" x="200" y="70" font-size="20" fill="black" text-anchor="middle">The result of this test is <tspan id="first_element_child" font-weight="bold">unknown.</tspan></text> + +<h:script><![CDATA[ +test(function() { + var fec = document.getElementById("first_element_child"); + assert_equals(fec.previousElementSibling, null) + assert_equals(fec.nextElementSibling, null) +}) +]]></h:script> +</svg> diff --git a/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-xhtml.xhtml new file mode 100644 index 0000000000..fcf4d54ff9 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null-xhtml.xhtml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Null Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>Test of previousElementSibling and nextElementSibling returning null</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p> +<script><![CDATA[ +test(function() { + var fec = document.getElementById("first_element_child"); + assert_equals(fec.previousElementSibling, null) + assert_equals(fec.nextElementSibling, null) +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Element-siblingElement-null.html b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null.html new file mode 100644 index 0000000000..a7920b4fb8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-siblingElement-null.html @@ -0,0 +1,16 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Null test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>Test of previousElementSibling and nextElementSibling returning null</h1> +<div id="log"></div> +<p id="parentEl">The result of this test is <span id="first_element_child" style="font-weight:bold;">unknown.</span></p> +<script> +test(function() { + var fec = document.getElementById("first_element_child"); + assert_equals(fec.previousElementSibling, null) + assert_equals(fec.nextElementSibling, null) +}) +</script> + diff --git a/testing/web-platform/tests/dom/nodes/Element-tagName.html b/testing/web-platform/tests/dom/nodes/Element-tagName.html new file mode 100644 index 0000000000..43e7a2d2bf --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-tagName.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<title>Element.tagName</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml" + assert_equals(document.createElementNS(HTMLNS, "I").tagName, "I") + assert_equals(document.createElementNS(HTMLNS, "i").tagName, "I") + assert_equals(document.createElementNS(HTMLNS, "x:b").tagName, "X:B") +}, "tagName should upper-case for HTML elements in HTML documents.") + +test(function() { + var SVGNS = "http://www.w3.org/2000/svg" + assert_equals(document.createElementNS(SVGNS, "svg").tagName, "svg") + assert_equals(document.createElementNS(SVGNS, "SVG").tagName, "SVG") + assert_equals(document.createElementNS(SVGNS, "s:svg").tagName, "s:svg") + assert_equals(document.createElementNS(SVGNS, "s:SVG").tagName, "s:SVG") + + assert_equals(document.createElementNS(SVGNS, "textPath").tagName, "textPath"); +}, "tagName should not upper-case for SVG elements in HTML documents.") + +test(() => { + const el2 = document.createElementNS("http://example.com/", "mixedCase"); + assert_equals(el2.tagName, "mixedCase"); +}, "tagName should not upper-case for other non-HTML namespaces"); + +test(function() { + if ("DOMParser" in window) { + var xmlel = new DOMParser() + .parseFromString('<div xmlns="http://www.w3.org/1999/xhtml">Test</div>', 'text/xml') + .documentElement; + assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML") + var htmlel = document.importNode(xmlel, true) + assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML") + } +}, "tagName should be updated when changing ownerDocument") + +test(function() { + var xmlel = document.implementation + .createDocument("http://www.w3.org/1999/xhtml", "div", null) + .documentElement; + assert_equals(xmlel.tagName, "div", "tagName should be lowercase in XML") + var htmlel = document.importNode(xmlel, true) + assert_equals(htmlel.tagName, "DIV", "tagName should be uppercase in HTML") +}, "tagName should be updated when changing ownerDocument (createDocument without prefix)") + +test(function() { + var xmlel = document.implementation + .createDocument("http://www.w3.org/1999/xhtml", "foo:div", null) + .documentElement; + assert_equals(xmlel.tagName, "foo:div", "tagName should be lowercase in XML") + var htmlel = document.importNode(xmlel, true) + assert_equals(htmlel.tagName, "FOO:DIV", "tagName should be uppercase in HTML") +}, "tagName should be updated when changing ownerDocument (createDocument with prefix)") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Element-webkitMatchesSelector.html b/testing/web-platform/tests/dom/nodes/Element-webkitMatchesSelector.html new file mode 100644 index 0000000000..107f810203 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Element-webkitMatchesSelector.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<title>Selectors-API Level 2 Test Suite: HTML with Selectors Level 3</title> +<!-- Selectors API Test Suite Version 3 --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/dom/nodes/selectors.js"></script> +<script src="/dom/nodes/ParentNode-querySelector-All.js"></script> +<script src="Element-matches.js"></script> +<script src="Element-matches-init.js"></script> +<style>iframe { visibility: hidden; position: absolute; }</style> + +<div id="log">This test requires JavaScript.</div> + +<script> + async_test(function() { + var frame = document.createElement("iframe"); + frame.onload = this.step_func_done(e => init(e, "webkitMatchesSelector" )); + frame.src = "/dom/nodes/ParentNode-querySelector-All-content.html#target"; + document.body.appendChild(frame); + }); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-attributes.html b/testing/web-platform/tests/dom/nodes/MutationObserver-attributes.html new file mode 100644 index 0000000000..6721b7eecd --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-attributes.html @@ -0,0 +1,406 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: attributes mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: attributes mutations</h1> +<div id="log"></div> + +<section style="display: none"> +<p id='n'></p> + +<p id='n00'></p> +<p id='n01'></p> +<p id='n02'></p> +<p id='n03'></p> +<input id="n04" type="text"> + +<p id='n10'></p> +<p id='n11'></p> +<p id='n12' class='c01'></p> +<p id='n13' class='c01 c02'></p> + +<p id='n20'></p> +<p id='n21'></p> +<p id='n22'></p> +<p id='n23'></p> +<p id='n24' class="c01 c02"></p> + +<p id='n30' class="c01 c02"></p> +<p id='n31' class="c01 c02"></p> +<p id='n32' class="c01 c02"></p> + +<p id='n40' class="c01 c02"></p> +<p id='n41' class="c01 c02"></p> +<p id='n42' class="c01 c02"></p> +<p id='n43' class="c01 c02"></p> +<p id='n44' class="c01 c02"></p> +<p id='n45' class="c01 c02"></p> + +<p id='n50' class="c01 c02"></p> +<p id='n51'></p> + +<p id='n60'></p> +<p id='n61' class="c01"></p> +<p id='n62'></p> + +<p id='n70' class="c01"></p> +<p id='n71'></p> +<input id="n72" type="text"> + +<p id='n80'></p> +<p id='n81'></p> + +<p id='n90'></p> +<p id='n91'></p> +<p id='n92'></p> + +<p id='n1000'></p> +<p id='n1001' class='c01'></p> + +<p id='n2000'></p> +<p id='n2001' class='c01'></p> + +<p id='n3000'></p> + +</section> + +<script> + +var n = document.getElementById('n'); + +runMutationTest(n, + {"attributes":true}, + [{type: "attributes", attributeName: "id"}], + function() { n.id = "n000";}, + "attributes Element.id: update, no oldValue, mutation"); + +var n00 = document.getElementById('n00'); +runMutationTest(n00, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n00", attributeName: "id"}], + function() { n00.id = "n000";}, + "attributes Element.id: update mutation"); + +var n01 = document.getElementById('n01'); +runMutationTest(n01, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n01", attributeName: "id"}], + function() { n01.id = "";}, + "attributes Element.id: empty string update mutation"); + +var n02 = document.getElementById('n02'); +runMutationTest(n02, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n02", attributeName: "id"}, {type: "attributes", attributeName: "class"}], + function() { n02.id = "n02"; n02.setAttribute("class", "c01");}, + "attributes Element.id: same value mutation"); + +var n03 = document.getElementById('n03'); +runMutationTest(n03, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n03", attributeName: "id"}], + function() { n03.unknown = "c02"; n03.id = "n030";}, + "attributes Element.unknown: IDL attribute no mutation"); + +var n04 = document.getElementById('n04'); +runMutationTest(n04, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "text", attributeName: "type"}, {type: "attributes", oldValue: "n04", attributeName: "id"}], + function() { n04.type = "unknown"; n04.id = "n040";}, + "attributes HTMLInputElement.type: type update mutation"); + + var n10 = document.getElementById('n10'); +runMutationTest(n10, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "class"}], + function() { n10.className = "c01";}, + "attributes Element.className: new value mutation"); + + var n11 = document.getElementById('n11'); +runMutationTest(n11, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "class"}], + function() { n11.className = "";}, + "attributes Element.className: empty string update mutation"); + + var n12 = document.getElementById('n12'); +runMutationTest(n12, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01", attributeName: "class"}], + function() { n12.className = "c01";}, + "attributes Element.className: same value mutation"); + + var n13 = document.getElementById('n13'); +runMutationTest(n13, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n13.className = "c01 c02";}, + "attributes Element.className: same multiple values mutation"); + + var n20 = document.getElementById('n20'); +runMutationTest(n20, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "class"}], + function() { n20.classList.add("c01");}, + "attributes Element.classList.add: single token addition mutation"); + + var n21 = document.getElementById('n21'); +runMutationTest(n21, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "class"}], + function() { n21.classList.add("c01", "c02", "c03");}, + "attributes Element.classList.add: multiple tokens addition mutation"); + + var n22 = document.getElementById('n22'); +runMutationTest(n22, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n22", attributeName: "id"}], + function() { try { n22.classList.add("c01", "", "c03"); } catch (e) { }; + n22.id = "n220"; }, + "attributes Element.classList.add: syntax err/no mutation"); + + var n23 = document.getElementById('n23'); +runMutationTest(n23, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n23", attributeName: "id"}], + function() { try { n23.classList.add("c01", "c 02", "c03"); } catch (e) { }; + n23.id = "n230"; }, + "attributes Element.classList.add: invalid character/no mutation"); + + var n24 = document.getElementById('n24'); +runMutationTest(n24, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}, {type: "attributes", oldValue: "n24", attributeName: "id"}], + function() { n24.classList.add("c02"); n24.id = "n240";}, + "attributes Element.classList.add: same value mutation"); + + var n30 = document.getElementById('n30'); +runMutationTest(n30, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n30.classList.remove("c01");}, + "attributes Element.classList.remove: single token removal mutation"); + + var n31 = document.getElementById('n31'); +runMutationTest(n31, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n31.classList.remove("c01", "c02");}, + "attributes Element.classList.remove: multiple tokens removal mutation"); + + var n32 = document.getElementById('n32'); +runMutationTest(n32, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}, {type: "attributes", oldValue: "n32", attributeName: "id"}], + function() { n32.classList.remove("c03"); n32.id = "n320";}, + "attributes Element.classList.remove: missing token removal mutation"); + + var n40 = document.getElementById('n40'); +runMutationTest(n40, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n40.classList.toggle("c01");}, + "attributes Element.classList.toggle: token removal mutation"); + + var n41 = document.getElementById('n41'); +runMutationTest(n41, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n41.classList.toggle("c03");}, + "attributes Element.classList.toggle: token addition mutation"); + + var n42 = document.getElementById('n42'); +runMutationTest(n42, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n42.classList.toggle("c01", false);}, + "attributes Element.classList.toggle: forced token removal mutation"); + + var n43 = document.getElementById('n43'); +runMutationTest(n43, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n43", attributeName: "id"}], + function() { n43.classList.toggle("c03", false); n43.id = "n430"; }, + "attributes Element.classList.toggle: forced missing token removal no mutation"); + + var n44 = document.getElementById('n44'); +runMutationTest(n44, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n44", attributeName: "id"}], + function() { n44.classList.toggle("c01", true); n44.id = "n440"; }, + "attributes Element.classList.toggle: forced existing token addition no mutation"); + + var n45 = document.getElementById('n45'); +runMutationTest(n45, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { n45.classList.toggle("c03", true);}, + "attributes Element.classList.toggle: forced token addition mutation"); + + var n50 = document.getElementById('n50'); +runMutationTest(n50, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01 c02", attributeName: "class"}], + function() { + for (var i = 0; i < n50.attributes.length; i++) { + var attr = n50.attributes[i]; + if (attr.localName === "class") { + attr.value = "c03"; + } + }; + }, + "attributes Element.attributes.value: update mutation"); + + var n51 = document.getElementById('n51'); +runMutationTest(n51, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n51", attributeName: "id"}], + function() { + n51.attributes[0].value = "n51"; + }, + "attributes Element.attributes.value: same id mutation"); + + var n60 = document.getElementById('n60'); +runMutationTest(n60, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n60", attributeName: "id"}], + function() { + n60.setAttribute("id", "n601"); + }, + "attributes Element.setAttribute: id mutation"); + + var n61 = document.getElementById('n61'); +runMutationTest(n61, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01", attributeName: "class"}], + function() { + n61.setAttribute("class", "c01"); + }, + "attributes Element.setAttribute: same class mutation"); + + var n62 = document.getElementById('n62'); +runMutationTest(n62, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "classname"}], + function() { + n62.setAttribute("classname", "c01"); + }, + "attributes Element.setAttribute: classname mutation"); + + var n70 = document.getElementById('n70'); +runMutationTest(n70, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "c01", attributeName: "class"}], + function() { + n70.removeAttribute("class"); + }, + "attributes Element.removeAttribute: removal mutation"); + + var n71 = document.getElementById('n71'); +runMutationTest(n71, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n71", attributeName: "id"}], + function() { + n71.removeAttribute("class"); + n71.id = "n710"; + }, + "attributes Element.removeAttribute: removal no mutation"); + + var n72 = document.getElementById('n72'); +runMutationTest(n72, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "text", attributeName: "type"}, {type: "attributes", oldValue: "n72", attributeName: "id"}], + function() { + n72.removeAttribute("type"); + n72.id = "n720"; + }, + "childList HTMLInputElement.removeAttribute: type removal mutation"); + + var n80 = document.getElementById('n80'); +runMutationTest(n80, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "private", attributeNamespace: "http://example.org/"}], + function() { + n80.setAttributeNS("http://example.org/", "private", "42"); + }, + "attributes Element.setAttributeNS: creation mutation"); + + var n81 = document.getElementById('n81'); +runMutationTest(n81, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", attributeName: "lang", attributeNamespace: "http://www.w3.org/XML/1998/namespace"}], + function() { + n81.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "42"); + }, + "attributes Element.setAttributeNS: prefixed attribute creation mutation"); + + var n90 = document.getElementById('n90'); + n90.setAttributeNS("http://example.org/", "private", "42"); +runMutationTest(n90, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "42", attributeName: "private", attributeNamespace: "http://example.org/"}], + function() { + n90.removeAttributeNS("http://example.org/", "private"); + }, + "attributes Element.removeAttributeNS: removal mutation"); + + var n91 = document.getElementById('n91'); +runMutationTest(n91, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n91", attributeName: "id"}], + function() { + n91.removeAttributeNS("http://example.org/", "private"); + n91.id = "n910"; + }, + "attributes Element.removeAttributeNS: removal no mutation"); + + var n92 = document.getElementById('n92'); +runMutationTest(n92, + {"attributes":true, "attributeOldValue": true}, + [{type: "attributes", oldValue: "n92", attributeName: "id"}], + function() { + n92.removeAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang"); + n92.id = "n920"; + }, + "attributes Element.removeAttributeNS: prefixed attribute removal no mutation"); + + var n1000 = document.getElementById('n1000'); +runMutationTest(n1000, + {"attributes":true, "attributeOldValue": true,"attributeFilter": ["id"]}, + [{type: "attributes", oldValue: "n1000", attributeName: "id"}], + function() { n1000.id = "abc"; n1000.className = "c01"}, + "attributes/attributeFilter Element.id/Element.className: update mutation"); + + var n1001 = document.getElementById('n1001'); +runMutationTest(n1001, + {"attributes":true, "attributeOldValue": true,"attributeFilter": ["id", "class"]}, + [{type: "attributes", oldValue: "n1001", attributeName: "id"}, + {type: "attributes", oldValue: "c01", attributeName: "class"}], + function() { n1001.id = "abc"; n1001.className = "c02"; n1001.setAttribute("lang", "fr");}, + "attributes/attributeFilter Element.id/Element.className: multiple filter update mutation"); + + var n2000 = document.getElementById('n2000'); +runMutationTest(n2000, + {"attributeOldValue": true}, + [{type: "attributes", oldValue: "n2000", attributeName: "id"}], + function() { n2000.id = "abc";}, + "attributeOldValue alone Element.id: update mutation"); + + var n2001 = document.getElementById('n2001'); +runMutationTest(n2001, + {"attributeFilter": ["id", "class"]}, + [{type: "attributes", attributeName: "id"}, + {type: "attributes", attributeName: "class"}], + function() { n2001.id = "abcd"; n2001.className = "c02"; n2001.setAttribute("lang", "fr");}, + "attributeFilter alone Element.id/Element.className: multiple filter update mutation"); + + var n3000 = document.getElementById('n3000'); +runMutationTest(n3000, + {"subtree": true, "childList":false, "attributes" : true}, + [{type: "attributes", attributeName: "id" }], + function() { n3000.textContent = "CHANGED"; n3000.id = "abc";}, + "childList false: no childList mutation"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-callback-arguments.html b/testing/web-platform/tests/dom/nodes/MutationObserver-callback-arguments.html new file mode 100644 index 0000000000..d64758cb4f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-callback-arguments.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObserver: callback arguments</title> +<link rel="help" href="https://dom.spec.whatwg.org/#notify-mutation-observers"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="mo-target"></div> +<div id="log"></div> +<script> +"use strict"; + +async_test(t => { + const moTarget = document.querySelector("#mo-target"); + const mo = new MutationObserver(function(records, observer) { + t.step(() => { + assert_equals(this, mo); + assert_equals(arguments.length, 2); + assert_true(Array.isArray(records)); + assert_equals(records.length, 1); + assert_true(records[0] instanceof MutationRecord); + assert_equals(observer, mo); + + mo.disconnect(); + t.done(); + }); + }); + + mo.observe(moTarget, {attributes: true}); + moTarget.className = "trigger-mutation"; +}, "Callback is invoked with |this| value of MutationObserver and two arguments"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-characterData.html b/testing/web-platform/tests/dom/nodes/MutationObserver-characterData.html new file mode 100644 index 0000000000..addaef03da --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-characterData.html @@ -0,0 +1,215 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: characterData mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: characterData mutations</h1> +<div id="log"></div> + +<section style="display: none"> + +<p id='n'>text content</p> + +<p id='n00'>text content</p> + +<p id='n10'>CHAN</p> +<p id='n11'>CHANGED</p> +<p id='n12'>CHANGED</p> + +<p id='n20'>CHGED</p> +<p id='n21'>CHANGED</p> +<p id='n22'>CHANGED</p> + +<p id='n30'>CCCHANGED</p> +<p id='n31'>CHANGED</p> + +<p id='n40'>CCCHANGED</p> +<p id='n41'>CHANGED</p> + +<p id="n50"><?processing data?></p> + +<p id="n60"><!-- data --></p> + +<p id='n70'>CHANN</p> +<p id='n71'>CHANN</p> + +<p id='n80'>CHANN</p> +<p id='n81'>CHANN</p> + +<p id='n90'>CHANN</p> + +</section> + +<script> + var n = document.getElementById('n').firstChild; +runMutationTest(n, + {"characterData":true}, + [{type: "characterData"}], + function() { n.data = "NEW VALUE"; }, + "characterData Text.data: simple mutation without oldValue"); + + var n00 = document.getElementById('n00').firstChild; +runMutationTest(n00, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "text content" }], + function() { n00.data = "CHANGED"; }, + "characterData Text.data: simple mutation"); + + var n10 = document.getElementById('n10').firstChild; +runMutationTest(n10, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHAN" }], + function() { n10.appendData("GED"); }, + "characterData Text.appendData: simple mutation"); + + var n11 = document.getElementById('n11').firstChild; +runMutationTest(n11, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }], + function() { n11.appendData(""); }, + "characterData Text.appendData: empty string mutation"); + + var n12 = document.getElementById('n12').firstChild; +runMutationTest(n12, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }], + function() { n12.appendData(null); }, + "characterData Text.appendData: null string mutation"); + + var n20 = document.getElementById('n20').firstChild; +runMutationTest(n20, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHGED" }], + function() { n20.insertData(2, "AN"); }, + "characterData Text.insertData: simple mutation"); + + var n21 = document.getElementById('n21').firstChild; +runMutationTest(n21, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }], + function() { n21.insertData(2, ""); }, + "characterData Text.insertData: empty string mutation"); + + var n22 = document.getElementById('n22').firstChild; +runMutationTest(n22, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }], + function() { n22.insertData(2, null); }, + "characterData Text.insertData: null string mutation"); + + var n30 = document.getElementById('n30').firstChild; +runMutationTest(n30, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CCCHANGED" }], + function() { n30.deleteData(0, 2); }, + "characterData Text.deleteData: simple mutation"); + + var n31 = document.getElementById('n31').firstChild; +runMutationTest(n31, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }, {type: "characterData", oldValue: "CHANGED" }], + function() { n31.deleteData(0, 0); n31.data = "n31"; }, + "characterData Text.deleteData: empty mutation"); + + var n40 = document.getElementById('n40').firstChild; +runMutationTest(n40, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CCCHANGED" }], + function() { n40.replaceData(0, 2, "CH"); }, + "characterData Text.replaceData: simple mutation"); + + var n41 = document.getElementById('n41').firstChild; +runMutationTest(n41, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANGED" }], + function() { n41.replaceData(0, 0, "CH"); }, + "characterData Text.replaceData: empty mutation"); + + var n50 = document.getElementById('n50').firstChild; +runMutationTest(n50, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "?processing data?" },{type: "characterData", oldValue: "CHANGED" },{type: "characterData", oldValue: "CHANGED" }], + function() { + n50.data = "CHANGED"; + n50.deleteData(0, 0); + n50.replaceData(0, 2, "CH"); }, + "characterData ProcessingInstruction: data mutations"); + + var n60 = document.getElementById('n60').firstChild; +runMutationTest(n60, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: " data " },{type: "characterData", oldValue: "CHANGED" },{type: "characterData", oldValue: "CHANGED" }], + function() { + n60.data = "CHANGED"; + n60.deleteData(0, 0); + n60.replaceData(0, 2, "CH"); }, + "characterData Comment: data mutations"); + + var n70 = document.getElementById('n70'); + var r70 = null; + test(function () { + n70.appendChild(document.createTextNode("NNN")); + n70.appendChild(document.createTextNode("NGED")); + r70 = document.createRange(); + r70.setStart(n70.firstChild, 4); + r70.setEnd(n70.lastChild, 1); + }, "Range (r70) is created"); +runMutationTest(n70.firstChild, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANN" }], + function() { r70.deleteContents(); }, + "characterData Range.deleteContents: child and data removal mutation"); + + var n71 = document.getElementById('n71'); + var r71 = null; + test(function () { + n71.appendChild(document.createTextNode("NNN")); + n71.appendChild(document.createTextNode("NGED")); + r71 = document.createRange(); + r71.setStart(n71.firstChild, 4); + r71.setEnd(n71.lastChild, 1); + }, "Range (r71) is created"); +runMutationTest(n71.lastChild, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "NGED"}], + function() { r71.deleteContents(); }, + "characterData Range.deleteContents: child and data removal mutation (2)"); + + var n80 = document.getElementById('n80'); + var r80 = null; + test(function () { + n80.appendChild(document.createTextNode("NNN")); + n80.appendChild(document.createTextNode("NGED")); + r80 = document.createRange(); + r80.setStart(n80.firstChild, 4); + r80.setEnd(n80.lastChild, 1); + }, "Range (r80) is created"); +runMutationTest(n80.firstChild, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANN" }], + function() { r80.extractContents(); }, + "characterData Range.extractContents: child and data removal mutation"); + + var n81 = document.getElementById('n81'); + var r81 = null; + test(function () { + n81.appendChild(document.createTextNode("NNN")); + n81.appendChild(document.createTextNode("NGED")); + r81 = document.createRange(); + r81.setStart(n81.firstChild, 4); + r81.setEnd(n81.lastChild, 1); + }, "Range (r81) is created"); +runMutationTest(n81.lastChild, + {"characterData":true,"characterDataOldValue":true}, + [{type: "characterData", oldValue: "NGED" }], + function() { r81.extractContents(); }, + "characterData Range.extractContents: child and data removal mutation (2)"); + + var n90 = document.getElementById('n90').firstChild; +runMutationTest(n90, + {"characterDataOldValue":true}, + [{type: "characterData", oldValue: "CHANN" }], + function() { n90.data = "CHANGED"; }, + "characterData/characterDataOldValue alone Text.data: simple mutation"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-childList.html b/testing/web-platform/tests/dom/nodes/MutationObserver-childList.html new file mode 100644 index 0000000000..e4c674e027 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-childList.html @@ -0,0 +1,434 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: childList mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: childList mutations</h1> +<div id="log"></div> + +<section style="display: none"> +<p id='dummies'> +<span id='d30'>text content</span> +<span id='d35'>text content</span> +<span id='d40'>text content</span> +<span id='d45'>text content</span> +<span id='d50'>text content</span> +<span id='d51'>text content</span> +</p> + +</section> +<section style="display: none"> +<p id='n00'><span>text content</span></p> + +<p id='n10'><span>text content</span></p> +<p id='n11'></p> +<p id='n12'></p> +<p id='n13'><span>text content</span></p> + +<p id='n20'>PAS</p> +<p id='n21'>CH</p> + +<p id='n30'><span>text content</span></p> +<p id='n31'><span>text content</span></p> +<p id='n32'><span>AN</span><span>CH</span><span>GED</span></p> +<p id='n33'><span>text content</span></p> +<p id='n34'><span>text content</span></p> +<p id='n35'><span>text content</span></p> + +<p id='n40'><span>text content</span></p> +<p id='n41'><span>text content</span></p> +<p id='n42'><span>CH</span><span>GED</span><span>AN</span></p> +<p id='n43'><span>text content</span></p> +<p id='n44'><span>text content</span></p> +<p id='n45'><span>text content</span></p> + + +<p id='n50'><span>text content</span></p> +<p id='n51'><span>text content</span></p> +<p id='n52'><span>NO </span><span>CHANGED</span></p> +<p id='n53'><span>text content</span></p> + +<p id='n60'><span>text content</span></p> + +<p id='n70'><span>NO </span><span>CHANGED</span></p> +<p id='n71'>CHANN</p> + +<p id='n80'><span>NO </span><span>CHANGED</span></p> +<p id='n81'>CHANN</p> + +<p id='n90'><span>CHA</span><span>ED</span></p> +<p id='n91'>CHAE</p> + +<p id='n100'><span id="s1">CHAN</span><span id="s2">GED</span></p> + +</section> + +<script> + var dummies = document.getElementById('dummies'); + + function createFragment() { + var fragment = document.createDocumentFragment(); + fragment.appendChild(document.createTextNode("11")); + fragment.appendChild(document.createTextNode("22")); + return fragment; + } + + var n00 = document.getElementById('n00'); + + runMutationTest(n00, + {"childList":true, "attributes":true}, + [{type: "attributes", attributeName: "class"}], + function() { n00.nodeValue = ""; n00.setAttribute("class", "dummy");}, + "childList Node.nodeValue: no mutation"); + + var n10 = document.getElementById('n10'); + runMutationTest(n10, + {"childList":true}, + [{type: "childList", + removedNodes: [n10.firstChild], + addedNodes: function() {return [n10.firstChild]}}], + function() { n10.textContent = "new data"; }, + "childList Node.textContent: replace content mutation"); + + var n11 = document.getElementById('n11'); + runMutationTest(n11, + {"childList":true}, + [{type: "childList", + addedNodes: function() {return [n11.firstChild]}}], + function() { n11.textContent = "new data"; }, + "childList Node.textContent: no previous content mutation"); + + var n12 = document.getElementById('n12'); + runMutationTest(n12, + {"childList":true, "attributes":true}, + [{type: "attributes", attributeName: "class"}], + function() { n12.textContent = ""; n12.setAttribute("class", "dummy");}, + "childList Node.textContent: textContent no mutation"); + + var n13 = document.getElementById('n13'); + runMutationTest(n13, + {"childList":true}, + [{type: "childList", removedNodes: [n13.firstChild]}], + function() { n13.textContent = ""; }, + "childList Node.textContent: empty string mutation"); + + var n20 = document.getElementById('n20'); + n20.appendChild(document.createTextNode("S")); + runMutationTest(n20, + {"childList":true}, + [{type: "childList", + removedNodes: [n20.lastChild], + previousSibling: n20.firstChild}], + function() { n20.normalize(); }, + "childList Node.normalize mutation"); + + var n21 = document.getElementById('n21'); + n21.appendChild(document.createTextNode("AN")); + n21.appendChild(document.createTextNode("GED")); + runMutationTest(n21, + {"childList":true}, + [{type: "childList", + removedNodes: [n21.lastChild.previousSibling], + previousSibling: n21.firstChild, + nextSibling: n21.lastChild}, + {type: "childList", + removedNodes: [n21.lastChild], + previousSibling: n21.firstChild}], + function() { n21.normalize(); }, + "childList Node.normalize mutations"); + + var n30 = document.getElementById('n30'); + var d30 = document.getElementById('d30'); + runMutationTest(n30, + {"childList":true}, + [{type: "childList", + addedNodes: [d30], + nextSibling: n30.firstChild}], + function() { n30.insertBefore(d30, n30.firstChild); }, + "childList Node.insertBefore: addition mutation"); + + var n31 = document.getElementById('n31'); + runMutationTest(n31, + {"childList":true}, + [{type: "childList", + removedNodes: [n31.firstChild]}], + function() { dummies.insertBefore(n31.firstChild, dummies.firstChild); }, + "childList Node.insertBefore: removal mutation"); + + var n32 = document.getElementById('n32'); + runMutationTest(n32, + {"childList":true}, + [{type: "childList", + removedNodes: [n32.firstChild.nextSibling], + previousSibling: n32.firstChild, nextSibling: n32.lastChild}, + {type: "childList", + addedNodes: [n32.firstChild.nextSibling], + nextSibling: n32.firstChild}], + function() { n32.insertBefore(n32.firstChild.nextSibling, n32.firstChild); }, + "childList Node.insertBefore: removal and addition mutations"); + + var n33 = document.getElementById('n33'); + var f33 = createFragment(); + runMutationTest(n33, + {"childList":true}, + [{type: "childList", + addedNodes: [f33.firstChild, f33.lastChild], + nextSibling: n33.firstChild}], + function() { n33.insertBefore(f33, n33.firstChild); }, + "childList Node.insertBefore: fragment addition mutations"); + + var n34 = document.getElementById('n34'); + var f34 = createFragment(); + runMutationTest(f34, + {"childList":true}, + [{type: "childList", + removedNodes: [f34.firstChild, f34.lastChild]}], + function() { n34.insertBefore(f34, n34.firstChild); }, + "childList Node.insertBefore: fragment removal mutations"); + + var n35 = document.getElementById('n35'); + var d35 = document.getElementById('d35'); + runMutationTest(n35, + {"childList":true}, + [{type: "childList", + addedNodes: [d35], + previousSibling: n35.firstChild}], + function() { n35.insertBefore(d35, null); }, + "childList Node.insertBefore: last child addition mutation"); + + var n40 = document.getElementById('n40'); + var d40 = document.getElementById('d40'); + runMutationTest(n40, + {"childList":true}, + [{type: "childList", + addedNodes: [d40], + previousSibling: n40.firstChild}], + function() { n40.appendChild(d40); }, + "childList Node.appendChild: addition mutation"); + + var n41 = document.getElementById('n41'); + runMutationTest(n41, + {"childList":true}, + [{type: "childList", + removedNodes: [n41.firstChild]}], + function() { dummies.appendChild(n41.firstChild); }, + "childList Node.appendChild: removal mutation"); + + var n42 = document.getElementById('n42'); + runMutationTest(n42, + {"childList":true}, + [{type: "childList", + removedNodes: [n42.firstChild.nextSibling], + previousSibling: n42.firstChild, nextSibling: n42.lastChild}, + {type: "childList", + addedNodes: [n42.firstChild.nextSibling], + previousSibling: n42.lastChild}], + function() { n42.appendChild(n42.firstChild.nextSibling); }, + "childList Node.appendChild: removal and addition mutations"); + + var n43 = document.getElementById('n43'); + var f43 = createFragment(); + runMutationTest(n43, + {"childList":true}, + [{type: "childList", + addedNodes: [f43.firstChild, f43.lastChild], + previousSibling: n43.firstChild}], + function() { n43.appendChild(f43); }, + "childList Node.appendChild: fragment addition mutations"); + + var n44 = document.getElementById('n44'); + var f44 = createFragment(); + runMutationTest(f44, + {"childList":true}, + [{type: "childList", + removedNodes: [f44.firstChild, f44.lastChild]}], + function() { n44.appendChild(f44); }, + "childList Node.appendChild: fragment removal mutations"); + + var n45 = document.createElement('p'); + var d45 = document.createElement('span'); + runMutationTest(n45, + {"childList":true}, + [{type: "childList", + addedNodes: [d45]}], + function() { n45.appendChild(d45); }, + "childList Node.appendChild: addition outside document tree mutation"); + + var n50 = document.getElementById('n50'); + var d50 = document.getElementById('d50'); + runMutationTest(n50, + {"childList":true}, + [{type: "childList", + removedNodes: [n50.firstChild], + addedNodes: [d50]}], + function() { n50.replaceChild(d50, n50.firstChild); }, + "childList Node.replaceChild: replacement mutation"); + + var n51 = document.getElementById('n51'); + var d51 = document.getElementById('d51'); + runMutationTest(n51, + {"childList":true}, + [{type: "childList", + removedNodes: [n51.firstChild]}], + function() { d51.parentNode.replaceChild(n51.firstChild, d51); }, + "childList Node.replaceChild: removal mutation"); + + var n52 = document.getElementById('n52'); + runMutationTest(n52, + {"childList":true}, + [{type: "childList", + removedNodes: [n52.lastChild], + previousSibling: n52.firstChild}, + {type: "childList", + removedNodes: [n52.firstChild], + addedNodes: [n52.lastChild]}], + function() { n52.replaceChild(n52.lastChild, n52.firstChild); }, + "childList Node.replaceChild: internal replacement mutation"); + + var n53 = document.getElementById('n53'); + runMutationTest(n53, + {"childList":true}, + [{type: "childList", + removedNodes: [n53.firstChild]}, + {type: "childList", + addedNodes: [n53.firstChild]}], + function() { n53.replaceChild(n53.firstChild, n53.firstChild); }, + "childList Node.replaceChild: self internal replacement mutation"); + + var n60 = document.getElementById('n60'); + runMutationTest(n60, + {"childList":true}, + [{type: "childList", + removedNodes: [n60.firstChild]}], + function() { n60.removeChild(n60.firstChild); }, + "childList Node.removeChild: removal mutation"); + + var n70 = document.getElementById('n70'); + var r70 = null; + test(function () { + r70 = document.createRange(); + r70.setStartBefore(n70.firstChild); + r70.setEndAfter(n70.firstChild); + }, "Range (r70) is created"); + runMutationTest(n70, + {"childList":true}, + [{type: "childList", + removedNodes: [n70.firstChild], + nextSibling: n70.lastChild}], + function() { r70.deleteContents(); }, + "childList Range.deleteContents: child removal mutation"); + + var n71 = document.getElementById('n71'); + var r71 = null; + test(function () { + n71.appendChild(document.createTextNode("NNN")); + n71.appendChild(document.createTextNode("NGED")); + r71 = document.createRange(); + r71.setStart(n71.firstChild, 4); + r71.setEnd(n71.lastChild, 1); + }, "Range (r71) is created"); + runMutationTest(n71, + {"childList":true}, + [{type: "childList", + removedNodes: [n71.firstChild.nextSibling], + previousSibling: n71.firstChild, + nextSibling: n71.lastChild}], + function() { r71.deleteContents(); }, + "childList Range.deleteContents: child and data removal mutation"); + + var n80 = document.getElementById('n80'); + var r80 = null; + test(function () { + r80 = document.createRange(); + r80.setStartBefore(n80.firstChild); + r80.setEndAfter(n80.firstChild); + }, "Range (r80) is created"); + runMutationTest(n80, + {"childList":true}, + [{type: "childList", + removedNodes: [n80.firstChild], + nextSibling: n80.lastChild}], + function() { r80.extractContents(); }, + "childList Range.extractContents: child removal mutation"); + + var n81 = document.getElementById('n81'); + var r81 = null; + test(function () { + n81.appendChild(document.createTextNode("NNN")); + n81.appendChild(document.createTextNode("NGED")); + r81 = document.createRange(); + r81.setStart(n81.firstChild, 4); + r81.setEnd(n81.lastChild, 1); + }, "Range (r81) is created"); + runMutationTest(n81, + {"childList":true}, + [{type: "childList", + removedNodes: [n81.firstChild.nextSibling], + previousSibling: n81.firstChild, + nextSibling: n81.lastChild}], + function() { r81.extractContents(); }, + "childList Range.extractContents: child and data removal mutation"); + + var n90 = document.getElementById('n90'); + var f90 = document.createTextNode("NG"); + var r90 = null; + test(function () { + r90 = document.createRange(); + r90.setStartAfter(n90.firstChild); + r90.setEndBefore(n90.lastChild); + }, "Range (r90) is created"); + runMutationTest(n90, + {"childList":true}, + [{type: "childList", + addedNodes: [f90], + previousSibling: n90.firstChild, + nextSibling: n90.lastChild}], + function() { r90.insertNode(f90); }, + "childList Range.insertNode: child insertion mutation"); + + var n91 = document.getElementById('n91'); + var f91 = document.createTextNode("NG"); + var r91 = null; + test(function () { + n91.appendChild(document.createTextNode("D")); + r91 = document.createRange(); + r91.setStart(n91.firstChild, 3); + r91.setEnd(n91.lastChild, 0); + }, "Range (r91) is created"); + runMutationTest(n91, + {"childList":true}, + [{type: "childList", + addedNodes: function() { return [n91.lastChild.previousSibling]; }, + previousSibling: n91.firstChild, + nextSibling: n91.lastChild}, + {type: "childList", + addedNodes: [f91], + previousSibling: n91.firstChild, + nextSibling: function () { return n91.lastChild.previousSibling; } }], + function() { r91.insertNode(f91); }, + "childList Range.insertNode: children insertion mutation"); + + var n100 = document.getElementById('n100'); + var f100 = document.createElement("span"); + var r100 = null; + test(function () { + r100 = document.createRange(); + r100.setStartBefore(n100.firstChild); + r100.setEndAfter(n100.lastChild); + }, "Range (r100) is created"); + runMutationTest(n100, + {"childList":true}, + [{type: "childList", + removedNodes: [n100.firstChild], + nextSibling: n100.lastChild}, + {type: "childList", + removedNodes: [n100.lastChild]}, + {type: "childList", + addedNodes: [f100] }], + function() { r100.surroundContents(f100); }, + "childList Range.surroundContents: children removal and addition mutation"); + +</script> + + diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html b/testing/web-platform/tests/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html new file mode 100644 index 0000000000..7d05c045b3 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-cross-realm-callback-report-exception.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title>MutationObserver reports the exception from its callback in the callback's global object</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<iframe></iframe> +<iframe></iframe> +<iframe></iframe> +<script> +setup({ allow_uncaught_exception: true }); + +const onerrorCalls = []; +window.onerror = () => { onerrorCalls.push("top"); }; +frames[0].onerror = () => { onerrorCalls.push("frame0"); }; +frames[1].onerror = () => { onerrorCalls.push("frame1"); }; +frames[2].onerror = () => { onerrorCalls.push("frame2"); }; + +async_test(t => { + window.onload = t.step_func(() => { + const target = frames[0].document.body; + const mo = new frames[0].MutationObserver(new frames[1].Function(`throw new parent.frames[2].Error("PASS");`)); + + mo.observe(target, { childList: true, subtree: true }); + target.append("foo"); + + t.step_timeout(() => { + assert_array_equals(onerrorCalls, ["frame1"]); + t.done(); + }, 4); + }); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-disconnect.html b/testing/web-platform/tests/dom/nodes/MutationObserver-disconnect.html new file mode 100644 index 0000000000..883edecf74 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-disconnect.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: disconnect</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<h1>MutationObservers: disconnect</h1> +<div id="log"></div> +<section style="display: none"> +<p id='n00'></p> +</section> +<script> +var n00 = document.getElementById('n00'); +var parentTest = async_test("subtree mutations"); +function masterMO(sequence, obs) { + parentTest.step(function() { + assert_equals(sequence.length, 4, "mutation records must match"); + }); + parentTest.done(); +} +parentTest.step(function() { + (new MutationObserver(masterMO)).observe(n00.parentNode, {"subtree": true, "attributes": true}); +}); + +var disconnectTest = async_test("disconnect discarded some mutations"); +function observerCallback(sequence, obs) { + disconnectTest.step(function() { + assert_equals(sequence.length, 1); + assert_equals(sequence[0].type, "attributes"); + assert_equals(sequence[0].attributeName, "id"); + assert_equals(sequence[0].oldValue, "latest"); + disconnectTest.done(); + }); +} + +var observer; +disconnectTest.step(function() { + observer = new MutationObserver(observerCallback); + observer.observe(n00, {"attributes": true}); + n00.id = "foo"; + n00.id = "bar"; + observer.disconnect(); + observer.observe(n00, {"attributes": true, "attributeOldValue": true}); + n00.id = "latest"; + observer.disconnect(); + observer.observe(n00, {"attributes": true, "attributeOldValue": true}); + n00.id = "n0000"; +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-document.html b/testing/web-platform/tests/dom/nodes/MutationObserver-document.html new file mode 100644 index 0000000000..4662b23459 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-document.html @@ -0,0 +1,167 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: takeRecords</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: document mutations</h1> +<div id="log"></div> + +<script id='s001'> + var setupTest = async_test("setup test"); + var insertionTest = async_test("parser insertion mutations"); + var insertionTest2 = async_test("parser script insertion mutation"); + var testCounter = 0; + + function masterMO(sequence, obs) { + testCounter++; + if (testCounter == 1) { + insertionTest.step( + function () { + checkRecords(document, sequence, + [{type: "childList", + addedNodes: function () { + return [ document.getElementById("n00") ]; + }, + previousSibling: function () { + return document.getElementById("s001"); + }, + target: document.body}, + {type: "childList", + addedNodes: function () { + return [ document.getElementById("s002") ]; + }, + previousSibling: function () { + return document.getElementById("n00"); + }, + target: document.body}, + {type: "childList", + addedNodes: function () { + return [ document.getElementById("s002").firstChild ]; + }, + target: function () { + return document.getElementById("s002"); + }}]); + }); + } else if (testCounter == 2) { + insertionTest2.step( + function () { + checkRecords(document, sequence, + [{type: "childList", + addedNodes: function () { + return [ document.getElementById("inserted_script") ]; + }, + target: function () { + return document.getElementById("n00"); + }}, + {type: "childList", + addedNodes: function () { + return [ document.getElementById("inserted_element") ]; + }, + previousSibling: function () { + return document.getElementById("s002"); + }, + target: document.body} + ]); + }); + } + } + var document_observer; + var newElement; + setupTest.step(function() { + document_observer = new MutationObserver(masterMO); + newElement = document.createElement("span"); + document_observer.observe(document, {subtree:true,childList:true}); + newElement.id = "inserted_element"; + newElement.setAttribute("style", "display: none"); + newElement.textContent = "my new span for n00"; + }); +</script><p id='n00'></p><script id='s002'> + var newScript = document.createElement("script"); + setupTest.step(function() { + newScript.textContent = "document.body.appendChild(newElement);"; + newScript.id = "inserted_script"; + document.getElementById("n00").appendChild(newScript); + }); + if (testCounter < 1) { + insertionTest.step( + function () { + assert_unreached("document observer did not trigger"); + }); + } +</script><script id='s003'> + setupTest.step(function() { + document_observer.disconnect(); + }); + if (testCounter < 2) { + insertionTest2.step( + function () { + assert_unreached("document observer did not trigger"); + }); + } + insertionTest.done(); + insertionTest2.done(); +</script> + +<p id='n012'></p><div id='d01'> +<script id='s011'> + var removalTest = async_test("removal of parent during parsing"); + var d01 = document.getElementById("d01"); + testCounter = 0; + + function removalMO(sequence, obs) { + testCounter++; + if (testCounter == 1) { + removalTest.step( + function () { + checkRecords(document, sequence, + [{type: "childList", + removedNodes: function () { + return [ d01 ]; + }, + previousSibling: function () { + return document.getElementById("n012"); + }, + target: document.body}]); + }); + } else if (testCounter == 2) { + removalTest.step( + function () { + checkRecords(document, sequence, + [{type: "childList", + addedNodes: function () { + return [ document.getElementById("s012") ]; + }, + previousSibling: function () { + return document.getElementById("n012"); + }, + target: document.body}, + {type: "childList", + addedNodes: function () { + return [ document.getElementById("s012").firstChild ]; + }, + target: function () { + return document.getElementById("s012"); + }}]); + }); + } + } + var document2_observer; + setupTest.step(function() { + document2_observer = new MutationObserver(removalMO); + document2_observer.observe(document, {subtree:true,childList:true}); + d01.parentNode.removeChild(d01); + }); +</script><p id='n01'></p></div><script id='s012'> + setupTest.step(function() { + document2_observer.disconnect(); + }); + if (testCounter < 2) { + removalTest.step( + function () { + assert_unreached("document observer did not trigger"); + }); + } + removalTest.done(); + setupTest.done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-inner-outer.html b/testing/web-platform/tests/dom/nodes/MutationObserver-inner-outer.html new file mode 100644 index 0000000000..9f6d871417 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-inner-outer.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: innerHTML, outerHTML mutations</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: innerHTML, outerHTML mutations</h1> +<div id="log"></div> + +<section style="display: none"> + +<p id='n00'>old text</p> + +<p id='n01'>old text</p> + +<div id='n02'><p>old text</p></div> +</section> + +<script> + var n00; + var n00oldText; + var n01; + var n01oldText; + var n02; + + setup(function() { + n00 = document.getElementById('n00'); + n00oldText = n00.firstChild; + n01 = document.getElementById('n01'); + n01oldText = n01.firstChild; + n02 = document.getElementById('n02'); + }) + + runMutationTest(n00, + {childList:true,attributes:true}, + [{type: "childList", + removedNodes: [n00oldText], + addedNodes: function() { + return [document.getElementById("n00").firstChild]; + }}, + {type: "attributes", attributeName: "class"}], + function() { n00.innerHTML = "new text"; n00.className = "c01"}, + "innerHTML mutation"); + + runMutationTest(n01, + {childList:true}, + [{type: "childList", + removedNodes: [n01oldText], + addedNodes: function() { + return [document.getElementById("n01").firstChild, + document.getElementById("n01").lastChild]; + }}], + function() { n01.innerHTML = "<span>new</span><span>text</span>"; }, + "innerHTML with 2 children mutation"); + + runMutationTest(n02, + {childList:true}, + [{type: "childList", + removedNodes: [n02.firstChild], + addedNodes: function() { + return [n02.firstChild]; + }}], + function() { n02.firstChild.outerHTML = "<p>next text</p>"; }, + "outerHTML mutation"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-sanity.html b/testing/web-platform/tests/dom/nodes/MutationObserver-sanity.html new file mode 100644 index 0000000000..a4f6382b94 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-sanity.html @@ -0,0 +1,95 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + test(() => { + var m = new MutationObserver(() => {}); + assert_throws_js(TypeError, () => { + m.observe(document, {}); + }); + }, "Should throw if none of childList, attributes, characterData are true"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { childList: true }); + m.disconnect(); + }, "Should not throw if childList is true"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { attributes: true }); + m.disconnect(); + }, "Should not throw if attributes is true"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { characterData: true }); + m.disconnect(); + }, "Should not throw if characterData is true"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { attributeOldValue: true }); + m.disconnect(); + }, "Should not throw if attributeOldValue is true and attributes is omitted"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { characterDataOldValue: true }); + m.disconnect(); + }, "Should not throw if characterDataOldValue is true and characterData is omitted"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { attributes: ["abc"] }); + m.disconnect(); + }, "Should not throw if attributeFilter is present and attributes is omitted"); + + test(() => { + var m = new MutationObserver(() => {}); + assert_throws_js(TypeError, () => { + m.observe(document, { childList: true, attributeOldValue: true, + attributes: false }); + }); + }, "Should throw if attributeOldValue is true and attributes is false"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { childList: true, attributeOldValue: true, + attributes: true }); + m.disconnect(); + }, "Should not throw if attributeOldValue and attributes are both true"); + + test(() => { + var m = new MutationObserver(() => {}); + assert_throws_js(TypeError, () => { + m.observe(document, { childList: true, attributeFilter: ["abc"], + attributes: false }); + }); + }, "Should throw if attributeFilter is present and attributes is false"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { childList: true, attributeFilter: ["abc"], + attributes: true }); + m.disconnect(); + }, "Should not throw if attributeFilter is present and attributes is true"); + + test(() => { + var m = new MutationObserver(() => {}); + assert_throws_js(TypeError, () => { + m.observe(document, { childList: true, characterDataOldValue: true, + characterData: false }); + }); + }, "Should throw if characterDataOldValue is true and characterData is false"); + + test(() => { + var m = new MutationObserver(() => {}); + m.observe(document, { childList: true, characterDataOldValue: true, + characterData: true }); + m.disconnect(); + }, "Should not throw if characterDataOldValue is true and characterData is true"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/MutationObserver-takeRecords.html b/testing/web-platform/tests/dom/nodes/MutationObserver-takeRecords.html new file mode 100644 index 0000000000..6a27ef77ec --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/MutationObserver-takeRecords.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>MutationObservers: takeRecords</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="mutationobservers.js"></script> +<h1>MutationObservers: takeRecords</h1> +<div id="log"></div> + +<section style="display: none"> + +<p id='n00'></p> + +</section> + +<script> + + var n00 = document.getElementById('n00'); + + var unused = async_test("unreachabled test"); + + var observer; + unused.step(function () { + observer = new MutationObserver(unused.unreached_func("the observer callback should not fire")); + observer.observe(n00, { "subtree": true, + "childList": true, + "attributes": true, + "characterData": true, + "attributeOldValue": true, + "characterDataOldValue": true}); + n00.id = "foo"; + n00.id = "bar"; + n00.className = "bar"; + n00.textContent = "old data"; + n00.firstChild.data = "new data"; + }); + + test(function() { + checkRecords(n00, observer.takeRecords(), [{type: "attributes", attributeName: "id", oldValue: "n00"}, + {type: "attributes", attributeName: "id", oldValue: "foo"}, + {type: "attributes", attributeName: "class"}, + {type: "childList", addedNodes: [n00.firstChild]}, + {type: "characterData", oldValue: "old data", target: n00.firstChild}]); + }, "All records present"); + + test(function() { + checkRecords(n00, observer.takeRecords(), []); + }, "No more records present"); +</script> +<script> + unused.done(); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-appendChild-cereactions-vs-script.window.js b/testing/web-platform/tests/dom/nodes/Node-appendChild-cereactions-vs-script.window.js new file mode 100644 index 0000000000..bc0b8ad6dc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-appendChild-cereactions-vs-script.window.js @@ -0,0 +1,27 @@ +const results = []; +test(() => { + class Script1 extends HTMLScriptElement { + constructor() { + super(); + } + connectedCallback() { + results.push("ce connected s1"); + } + } + class Script2 extends HTMLScriptElement { + constructor() { + super(); + } + connectedCallback() { + results.push("ce connected s2"); + } + } + customElements.define("script-1", Script1, { extends: "script" }); + customElements.define("script-2", Script2, { extends: "script" }); + const s1 = new Script1(); + s1.textContent = "results.push('s1')"; + const s2 = new Script2(); + s2.textContent = "results.push('s2')"; + document.body.append(s1, s2); + assert_array_equals(results, ["s1", "s2", "ce connected s1", "ce connected s2"]); +}, "Custom element reactions follow script execution"); diff --git a/testing/web-platform/tests/dom/nodes/Node-appendChild.html b/testing/web-platform/tests/dom/nodes/Node-appendChild.html new file mode 100644 index 0000000000..8264cb11a5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-appendChild.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.appendChild</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-appendchild"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<iframe src=about:blank></iframe> +<script> +// TODO: Exhaustive tests +function testLeaf(node, desc) { + // WebIDL. + test(function() { + assert_throws_js(TypeError, function() { node.appendChild(null) }) + }, "Appending null to a " + desc) + + // Pre-insert step 1. + test(function() { + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.appendChild(document.createTextNode("fail")) }) + }, "Appending to a " + desc) +} + +// WebIDL. +test(function() { + assert_throws_js(TypeError, function() { document.body.appendChild(null) }) + assert_throws_js(TypeError, function() { document.body.appendChild({'a':'b'}) }) +}, "WebIDL tests") + +// WebIDL and pre-insert step 1. +test(function() { + testLeaf(document.createTextNode("Foo"), "text node") + testLeaf(document.createComment("Foo"), "comment") + testLeaf(document.doctype, "doctype") +}, "Appending to a leaf node.") + +// Pre-insert step 5. +test(function() { + var frameDoc = frames[0].document + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { document.body.appendChild(frameDoc) }) +}, "Appending a document") + +// Pre-insert step 8. +test(function() { + var frameDoc = frames[0].document + var s = frameDoc.createElement("a") + assert_equals(s.ownerDocument, frameDoc) + document.body.appendChild(s) + assert_equals(s.ownerDocument, document) +}, "Adopting an orphan") +test(function() { + var frameDoc = frames[0].document + var s = frameDoc.createElement("b") + assert_equals(s.ownerDocument, frameDoc) + frameDoc.body.appendChild(s) + assert_equals(s.ownerDocument, frameDoc) + document.body.appendChild(s) + assert_equals(s.ownerDocument, document) +}, "Adopting a non-orphan") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-baseURI.html b/testing/web-platform/tests/dom/nodes/Node-baseURI.html new file mode 100644 index 0000000000..e9e9d76a10 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-baseURI.html @@ -0,0 +1,62 @@ +<!DOCTYPE html> +<title>Node.baseURI</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +const elementTests = [ + { + name: "elements belonging to document", + creator: () => { + const element = document.createElement("div"); + document.body.appendChild(element); + return element; + } + }, + { + name: "elements unassigned to document", + creator: () => document.createElement("div") + }, + { + name: "elements belonging to document fragments", + creator: () => { + const fragment = document.createDocumentFragment(); + const element = document.createElement("div"); + fragment.appendChild(element); + return element; + } + }, + { + name: "elements belonging to document fragments in document", + creator: () => { + const fragment = document.createDocumentFragment(); + const element = document.createElement("div"); + fragment.appendChild(element); + document.body.appendChild(fragment); + return element; + } + }, +]; + +const attributeTests = [ + { + name: "attributes unassigned to element", + creator: () => document.createAttribute("class") + }, + ...elementTests.map(({ name, creator }) => ({ + name: "attributes in " + name, + creator: () => { + const element = creator(); + element.setAttribute("class", "abc"); + return element.getAttributeNode("class"); + } + })) +]; + +for (const { name, creator } of [...elementTests, ...attributeTests]) { + test(function() { + const node = creator(); + assert_equals(node.baseURI, document.URL); + }, `For ${name}, baseURI should be document URL`) +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-childNodes.html b/testing/web-platform/tests/dom/nodes/Node-childNodes.html new file mode 100644 index 0000000000..0d38df37b2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-childNodes.html @@ -0,0 +1,117 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.childNodes</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-childnodes"> +<link rel=author title="Tim Taubert" href="mailto:ttaubert@mozilla.com"> +<link rel=author title="Ms2ger" href="mailto:Ms2ger@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div style="display: none"> + <ul id='test'><li>1</li><li>2</li><li>3</li><li>4</li></ul> +</div> +<script> +test(function() { + var element = document.createElement("p"); + assert_equals(element.childNodes, element.childNodes); +}, "Caching of Node.childNodes"); + +var check_parent_node = function(node) { + assert_array_equals(node.childNodes, []); + + var children = node.childNodes; + var child = document.createElement("p"); + node.appendChild(child); + assert_equals(node.childNodes, children); + assert_array_equals(children, [child]); + assert_equals(children.item(0), child); + + var child2 = document.createComment("comment"); + node.appendChild(child2); + assert_array_equals(children, [child, child2]); + assert_equals(children.item(0), child); + assert_equals(children.item(1), child2); + + assert_false(2 in children); + assert_equals(children[2], undefined); + assert_equals(children.item(2), null); +}; + +test(function() { + check_parent_node(document.createElement("p")); +}, "Node.childNodes on an Element."); + +test(function() { + check_parent_node(document.createDocumentFragment()); +}, "Node.childNodes on a DocumentFragment."); + +test(function() { + check_parent_node(new Document()); +}, "Node.childNodes on a Document."); + +test(function() { + var node = document.createElement("div"); + var kid1 = document.createElement("p"); + var kid2 = document.createTextNode("hey"); + var kid3 = document.createElement("span"); + node.appendChild(kid1); + node.appendChild(kid2); + node.appendChild(kid3); + + var list = node.childNodes; + assert_array_equals([...list], [kid1, kid2, kid3]); + + var keys = list.keys(); + assert_false(keys instanceof Array); + keys = [...keys]; + assert_array_equals(keys, [0, 1, 2]); + + var values = list.values(); + assert_false(values instanceof Array); + values = [...values]; + assert_array_equals(values, [kid1, kid2, kid3]); + + var entries = list.entries(); + assert_false(entries instanceof Array); + entries = [...entries]; + assert_equals(entries.length, keys.length); + assert_equals(entries.length, values.length); + for (var i = 0; i < entries.length; ++i) { + assert_array_equals(entries[i], [keys[i], values[i]]); + } + + var cur = 0; + var thisObj = {}; + list.forEach(function(value, key, listObj) { + assert_equals(listObj, list); + assert_equals(this, thisObj); + assert_equals(value, values[cur]); + assert_equals(key, keys[cur]); + cur++; + }, thisObj); + assert_equals(cur, entries.length); + + assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator]); + assert_equals(list.keys, Array.prototype.keys); + if (Array.prototype.values) { + assert_equals(list.values, Array.prototype.values); + } + assert_equals(list.entries, Array.prototype.entries); + assert_equals(list.forEach, Array.prototype.forEach); +}, "Iterator behavior of Node.childNodes"); + + +test(() => { + var node = document.getElementById("test"); + var children = node.childNodes; + assert_true(children instanceof NodeList); + var li = document.createElement("li"); + assert_equals(children.length, 4); + + node.appendChild(li); + assert_equals(children.length, 5); + + node.removeChild(li); + assert_equals(children.length, 4); +}, "Node.childNodes should be a live collection"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode-XMLDocument.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode-XMLDocument.html new file mode 100644 index 0000000000..2c63c77530 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode-XMLDocument.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of an XMLDocument</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> + +<!-- This is testing in particular "that implements the same interfaces as node" --> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const doc = document.implementation.createDocument("namespace", ""); + + assert_equals( + doc.constructor, XMLDocument, + "Precondition check: document.implementation.createDocument() creates an XMLDocument" + ); + + const clone = doc.cloneNode(true); + + assert_equals(clone.constructor, XMLDocument); +}, "Created with createDocument"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode-document-with-doctype.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode-document-with-doctype.html new file mode 100644 index 0000000000..21963084d2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode-document-with-doctype.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of a document with a doctype</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const doctype = document.implementation.createDocumentType("name", "publicId", "systemId"); + const doc = document.implementation.createDocument("namespace", "", doctype); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 1, "Only one child node"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "name"); + assert_equals(clone.childNodes[0].publicId, "publicId"); + assert_equals(clone.childNodes[0].systemId, "systemId"); +}, "Created with the createDocument/createDocumentType"); + +test(() => { + const doc = document.implementation.createHTMLDocument(); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 2, "Two child nodes"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "html"); + assert_equals(clone.childNodes[0].publicId, ""); + assert_equals(clone.childNodes[0].systemId, ""); +}, "Created with the createHTMLDocument"); + +test(() => { + const parser = new window.DOMParser(); + const doc = parser.parseFromString("<!DOCTYPE html><html></html>", "text/html"); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 2, "Two child nodes"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "html"); + assert_equals(clone.childNodes[0].publicId, ""); + assert_equals(clone.childNodes[0].systemId, ""); +}, "Created with DOMParser"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html new file mode 100644 index 0000000000..bce6074aad --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>cloneNode on a stylesheet link in a browsing-context-less document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2497 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const doc = document.implementation.createHTMLDocument(); + +// Bug was only triggered by absolute URLs, for some reason... +const absoluteURL = new URL("/common/canvas-frame.css", location.href); +doc.head.innerHTML = `<link rel="stylesheet" href="${absoluteURL}">`; + +// Test passes if this does not throw/crash +doc.cloneNode(true); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode-on-inactive-document-crash.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode-on-inactive-document-crash.html new file mode 100644 index 0000000000..cbd7a1e6a5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode-on-inactive-document-crash.html @@ -0,0 +1,6 @@ +<iframe id="i"></iframe> +<script> +var doc = i.contentDocument; +i.remove(); +doc.cloneNode(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode-svg.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode-svg.html new file mode 100644 index 0000000000..9d4704b074 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode-svg.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of SVG elements and attributes</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> +<!-- regression test for https://github.com/jsdom/jsdom/issues/1601 --> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<svg xmlns:xlink='http://www.w3.org/1999/xlink'><use xlink:href='#test'></use></svg> + +<script> +"use strict"; + +const svg = document.querySelector("svg"); +const clone = svg.cloneNode(true); + +test(() => { + + assert_equals(clone.namespaceURI, "http://www.w3.org/2000/svg"); + assert_equals(clone.prefix, null); + assert_equals(clone.localName, "svg"); + assert_equals(clone.tagName, "svg"); + +}, "cloned <svg> should have the right properties"); + +test(() => { + + const attr = clone.attributes[0]; + + assert_equals(attr.namespaceURI, "http://www.w3.org/2000/xmlns/"); + assert_equals(attr.prefix, "xmlns"); + assert_equals(attr.localName, "xlink"); + assert_equals(attr.name, "xmlns:xlink"); + assert_equals(attr.value, "http://www.w3.org/1999/xlink"); + +}, "cloned <svg>'s xmlns:xlink attribute should have the right properties"); + +test(() => { + + const use = clone.firstElementChild; + assert_equals(use.namespaceURI, "http://www.w3.org/2000/svg"); + assert_equals(use.prefix, null); + assert_equals(use.localName, "use"); + assert_equals(use.tagName, "use"); + +}, "cloned <use> should have the right properties"); + +test(() => { + + const use = clone.firstElementChild; + const attr = use.attributes[0]; + + assert_equals(attr.namespaceURI, "http://www.w3.org/1999/xlink"); + assert_equals(attr.prefix, "xlink"); + assert_equals(attr.localName, "href"); + assert_equals(attr.name, "xlink:href"); + assert_equals(attr.value, "#test"); + +}, "cloned <use>'s xlink:href attribute should have the right properties"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-cloneNode.html b/testing/web-platform/tests/dom/nodes/Node-cloneNode.html new file mode 100644 index 0000000000..e97259dace --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-cloneNode.html @@ -0,0 +1,346 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.cloneNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +function assert_equal_node(nodeA, nodeB) { + assert_equals(nodeB.nodeType, nodeA.nodeType, "nodeType"); + assert_equals(nodeB.nodeName, nodeA.nodeName, "nodeName"); + + if (nodeA.nodeType === Node.ELEMENT_NODE) { + assert_equals(nodeB.prefix, nodeA.prefix, "prefix"); + assert_equals(nodeB.namespaceURI, nodeA.namespaceURI, "namespaceURI"); + assert_equals(nodeB.localName, nodeA.localName, "localName"); + assert_equals(nodeB.tagName, nodeA.tagName, "tagName"); + assert_not_equals(nodeB.attributes != nodeA.attributes, "attributes"); + assert_equals(nodeB.attributes.length, nodeA.attributes.length, + "attributes.length"); + for (var i = 0, il = nodeA.attributes.length; i < il; ++i) { + assert_not_equals(nodeB.attributes[i], nodeA.attributes[i], + "attributes[" + i + "]"); + assert_equals(nodeB.attributes[i].name, nodeA.attributes[i].name, + "attributes[" + i + "].name"); + assert_equals(nodeB.attributes[i].prefix, nodeA.attributes[i].prefix, + "attributes[" + i + "].prefix"); + assert_equals(nodeB.attributes[i].namespaceURI, nodeA.attributes[i].namespaceURI, + "attributes[" + i + "].namespaceURI"); + assert_equals(nodeB.attributes[i].value, nodeA.attributes[i].value, + "attributes[" + i + "].value"); + } + } +} + +function check_copy(orig, copy, type) { + assert_not_equals(orig, copy, "Object equality"); + assert_equal_node(orig, copy, "Node equality"); + assert_true(orig instanceof type, "original instanceof " + type); + assert_true(copy instanceof type, "copy instanceof " + type); +} + +function create_element_and_check(localName, typeName) { + test(function() { + assert_true(typeName in window, typeName + " is not supported"); + var element = document.createElement(localName); + var copy = element.cloneNode(); + check_copy(element, copy, window[typeName]); + }, "createElement(" + localName + ")"); +} + +// test1: createElement +create_element_and_check("a", "HTMLAnchorElement"); +create_element_and_check("abbr", "HTMLElement"); +create_element_and_check("acronym", "HTMLElement"); +create_element_and_check("address", "HTMLElement"); +create_element_and_check("area", "HTMLAreaElement"); +create_element_and_check("article", "HTMLElement"); +create_element_and_check("aside", "HTMLElement"); +create_element_and_check("audio", "HTMLAudioElement"); +create_element_and_check("b", "HTMLElement"); +create_element_and_check("base", "HTMLBaseElement"); +create_element_and_check("bdi", "HTMLElement"); +create_element_and_check("bdo", "HTMLElement"); +create_element_and_check("bgsound", "HTMLElement"); +create_element_and_check("big", "HTMLElement"); +create_element_and_check("blockquote","HTMLElement"); +create_element_and_check("body", "HTMLBodyElement"); +create_element_and_check("br", "HTMLBRElement"); +create_element_and_check("button", "HTMLButtonElement"); +create_element_and_check("canvas", "HTMLCanvasElement"); +create_element_and_check("caption", "HTMLTableCaptionElement"); +create_element_and_check("center", "HTMLElement"); +create_element_and_check("cite", "HTMLElement"); +create_element_and_check("code", "HTMLElement"); +create_element_and_check("col", "HTMLTableColElement"); +create_element_and_check("colgroup", "HTMLTableColElement"); +create_element_and_check("data", "HTMLDataElement"); +create_element_and_check("datalist", "HTMLDataListElement"); +create_element_and_check("dialog", "HTMLDialogElement"); +create_element_and_check("dd", "HTMLElement"); +create_element_and_check("del", "HTMLModElement"); +create_element_and_check("details", "HTMLElement"); +create_element_and_check("dfn", "HTMLElement"); +create_element_and_check("dir", "HTMLDirectoryElement"); +create_element_and_check("div", "HTMLDivElement"); +create_element_and_check("dl", "HTMLDListElement"); +create_element_and_check("dt", "HTMLElement"); +create_element_and_check("embed", "HTMLEmbedElement"); +create_element_and_check("fieldset", "HTMLFieldSetElement"); +create_element_and_check("figcaption","HTMLElement"); +create_element_and_check("figure", "HTMLElement"); +create_element_and_check("font", "HTMLFontElement"); +create_element_and_check("footer", "HTMLElement"); +create_element_and_check("form", "HTMLFormElement"); +create_element_and_check("frame", "HTMLFrameElement"); +create_element_and_check("frameset", "HTMLFrameSetElement"); +create_element_and_check("h1", "HTMLHeadingElement"); +create_element_and_check("h2", "HTMLHeadingElement"); +create_element_and_check("h3", "HTMLHeadingElement"); +create_element_and_check("h4", "HTMLHeadingElement"); +create_element_and_check("h5", "HTMLHeadingElement"); +create_element_and_check("h6", "HTMLHeadingElement"); +create_element_and_check("head", "HTMLHeadElement"); +create_element_and_check("header", "HTMLElement"); +create_element_and_check("hgroup", "HTMLElement"); +create_element_and_check("hr", "HTMLHRElement"); +create_element_and_check("html", "HTMLHtmlElement"); +create_element_and_check("i", "HTMLElement"); +create_element_and_check("iframe", "HTMLIFrameElement"); +create_element_and_check("img", "HTMLImageElement"); +create_element_and_check("input", "HTMLInputElement"); +create_element_and_check("ins", "HTMLModElement"); +create_element_and_check("isindex", "HTMLElement"); +create_element_and_check("kbd", "HTMLElement"); +create_element_and_check("label", "HTMLLabelElement"); +create_element_and_check("legend", "HTMLLegendElement"); +create_element_and_check("li", "HTMLLIElement"); +create_element_and_check("link", "HTMLLinkElement"); +create_element_and_check("main", "HTMLElement"); +create_element_and_check("map", "HTMLMapElement"); +create_element_and_check("mark", "HTMLElement"); +create_element_and_check("marquee", "HTMLElement"); +create_element_and_check("meta", "HTMLMetaElement"); +create_element_and_check("meter", "HTMLMeterElement"); +create_element_and_check("nav", "HTMLElement"); +create_element_and_check("nobr", "HTMLElement"); +create_element_and_check("noframes", "HTMLElement"); +create_element_and_check("noscript", "HTMLElement"); +create_element_and_check("object", "HTMLObjectElement"); +create_element_and_check("ol", "HTMLOListElement"); +create_element_and_check("optgroup", "HTMLOptGroupElement"); +create_element_and_check("option", "HTMLOptionElement"); +create_element_and_check("output", "HTMLOutputElement"); +create_element_and_check("p", "HTMLParagraphElement"); +create_element_and_check("param", "HTMLParamElement"); +create_element_and_check("pre", "HTMLPreElement"); +create_element_and_check("progress", "HTMLProgressElement"); +create_element_and_check("q", "HTMLQuoteElement"); +create_element_and_check("rp", "HTMLElement"); +create_element_and_check("rt", "HTMLElement"); +create_element_and_check("ruby", "HTMLElement"); +create_element_and_check("s", "HTMLElement"); +create_element_and_check("samp", "HTMLElement"); +create_element_and_check("script", "HTMLScriptElement"); +create_element_and_check("section", "HTMLElement"); +create_element_and_check("select", "HTMLSelectElement"); +create_element_and_check("small", "HTMLElement"); +create_element_and_check("source", "HTMLSourceElement"); +create_element_and_check("spacer", "HTMLElement"); +create_element_and_check("span", "HTMLSpanElement"); +create_element_and_check("strike", "HTMLElement"); +create_element_and_check("style", "HTMLStyleElement"); +create_element_and_check("sub", "HTMLElement"); +create_element_and_check("summary", "HTMLElement"); +create_element_and_check("sup", "HTMLElement"); +create_element_and_check("table", "HTMLTableElement"); +create_element_and_check("tbody", "HTMLTableSectionElement"); +create_element_and_check("td", "HTMLTableCellElement"); +create_element_and_check("template", "HTMLTemplateElement"); +create_element_and_check("textarea", "HTMLTextAreaElement"); +create_element_and_check("th", "HTMLTableCellElement"); +create_element_and_check("time", "HTMLTimeElement"); +create_element_and_check("title", "HTMLTitleElement"); +create_element_and_check("tr", "HTMLTableRowElement"); +create_element_and_check("tt", "HTMLElement"); +create_element_and_check("track", "HTMLTrackElement"); +create_element_and_check("u", "HTMLElement"); +create_element_and_check("ul", "HTMLUListElement"); +create_element_and_check("var", "HTMLElement"); +create_element_and_check("video", "HTMLVideoElement"); +create_element_and_check("unknown", "HTMLUnknownElement"); +create_element_and_check("wbr", "HTMLElement"); + +test(function() { + var fragment = document.createDocumentFragment(); + var copy = fragment.cloneNode(); + check_copy(fragment, copy, DocumentFragment); +}, "createDocumentFragment"); + +test(function() { + var text = document.createTextNode("hello world"); + var copy = text.cloneNode(); + check_copy(text, copy, Text); + assert_equals(text.data, copy.data); + assert_equals(text.wholeText, copy.wholeText); +}, "createTextNode"); + +test(function() { + var comment = document.createComment("a comment"); + var copy = comment.cloneNode(); + check_copy(comment, copy, Comment); + assert_equals(comment.data, copy.data); +}, "createComment"); + +test(function() { + var el = document.createElement("foo"); + el.setAttribute("a", "b"); + el.setAttribute("c", "d"); + var c = el.cloneNode(); + check_copy(el, c, Element); +}, "createElement with attributes") + +test(function() { + var el = document.createElementNS("http://www.w3.org/1999/xhtml", "foo:div"); + var c = el.cloneNode(); + check_copy(el, c, HTMLDivElement); +}, "createElementNS HTML") + +test(function() { + var el = document.createElementNS("http://www.example.com/", "foo:div"); + var c = el.cloneNode(); + check_copy(el, c, Element); +}, "createElementNS non-HTML") + +test(function() { + var pi = document.createProcessingInstruction("target", "data"); + var copy = pi.cloneNode(); + check_copy(pi, copy, ProcessingInstruction); + assert_equals(pi.data, copy.data, "data"); + assert_equals(pi.target, pi.target, "target"); +}, "createProcessingInstruction"); + +test(function() { + var attr = document.createAttribute("class"); + var copy = attr.cloneNode(); + check_copy(attr, copy, Attr); + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy.localName); + assert_equals(attr.value, copy.value); + + attr.value = "abc"; + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy.localName); + assert_not_equals(attr.value, copy.value); + + var copy2 = attr.cloneNode(); + check_copy(attr, copy2, Attr); + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy2.localName); + assert_equals(attr.value, copy2.value); +}, "createAttribute"); + +test(function() { + var attr = document.createAttributeNS("http://www.w3.org/1999/xhtml", "foo:class"); + var copy = attr.cloneNode(); + check_copy(attr, copy, Attr); + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy.localName); + assert_equals(attr.value, copy.value); + + attr.value = "abc"; + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy.localName); + assert_not_equals(attr.value, copy.value); + + var copy2 = attr.cloneNode(); + check_copy(attr, copy2, Attr); + assert_equals(attr.namespaceURI, copy.namespaceURI); + assert_equals(attr.prefix, copy.prefix); + assert_equals(attr.localName, copy2.localName); + assert_equals(attr.value, copy2.value); +}, "createAttributeNS"); + +test(function() { + var doctype = document.implementation.createDocumentType("html", "public", "system"); + var copy = doctype.cloneNode(); + check_copy(doctype, copy, DocumentType); + assert_equals(doctype.name, copy.name, "name"); + assert_equals(doctype.publicId, copy.publicId, "publicId"); + assert_equals(doctype.systemId, copy.systemId, "systemId"); +}, "implementation.createDocumentType"); + +test(function() { + var doc = document.implementation.createDocument(null, null); + var copy = doc.cloneNode(); + check_copy(doc, copy, Document); + assert_equals(doc.charset, "UTF-8", "charset value"); + assert_equals(doc.charset, copy.charset, "charset equality"); + assert_equals(doc.contentType, "application/xml", "contentType value"); + assert_equals(doc.contentType, copy.contentType, "contentType equality"); + assert_equals(doc.URL, "about:blank", "URL value") + assert_equals(doc.URL, copy.URL, "URL equality"); + assert_equals(doc.compatMode, "CSS1Compat", "compatMode value"); + assert_equals(doc.compatMode, copy.compatMode, "compatMode equality"); +}, "implementation.createDocument"); + +test(function() { + var html = document.implementation.createHTMLDocument("title"); + var copy = html.cloneNode(); + check_copy(html, copy, Document); + assert_equals(copy.title, "", "title value"); +}, "implementation.createHTMLDocument"); + +test(function() { + var parent = document.createElement("div"); + var child1 = document.createElement("div"); + var child2 = document.createElement("div"); + var grandChild = document.createElement("div"); + + child2.appendChild(grandChild); + parent.appendChild(child1); + parent.appendChild(child2); + + var deep = true; + var copy = parent.cloneNode(deep); + + check_copy(parent, copy, HTMLDivElement); + assert_equals(copy.childNodes.length, 2, + "copy.childNodes.length with deep copy"); + + check_copy(child1, copy.childNodes[0], HTMLDivElement); + assert_equals(copy.childNodes[0].childNodes.length, 0, + "copy.childNodes[0].childNodes.length"); + + check_copy(child2, copy.childNodes[1], HTMLDivElement); + assert_equals(copy.childNodes[1].childNodes.length, 1, + "copy.childNodes[1].childNodes.length"); + check_copy(grandChild, copy.childNodes[1].childNodes[0], HTMLDivElement); + + deep = false; + copy = parent.cloneNode(deep); + + check_copy(parent, copy, HTMLDivElement); + assert_equals(copy.childNodes.length, 0, + "copy.childNodes.length with non-deep copy"); +}, "node with children"); + +test(() => { + const proto = Object.create(HTMLElement.prototype), + node = document.createElement("hi"); + Object.setPrototypeOf(node, proto); + assert_true(proto.isPrototypeOf(node)); + const clone = node.cloneNode(); + assert_false(proto.isPrototypeOf(clone)); + assert_true(HTMLUnknownElement.prototype.isPrototypeOf(clone)); + const deepClone = node.cloneNode(true); + assert_false(proto.isPrototypeOf(deepClone)); + assert_true(HTMLUnknownElement.prototype.isPrototypeOf(deepClone)); +}, "Node with custom prototype") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-compareDocumentPosition.html b/testing/web-platform/tests/dom/nodes/Node-compareDocumentPosition.html new file mode 100644 index 0000000000..afae60aad1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-compareDocumentPosition.html @@ -0,0 +1,87 @@ +<!doctype html> +<title>Node.compareDocumentPosition() tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testNodes.forEach(function(referenceName) { + var reference = eval(referenceName); + testNodes.forEach(function(otherName) { + var other = eval(otherName); + test(function() { + var result = reference.compareDocumentPosition(other); + + // "If other and reference are the same object, return zero and + // terminate these steps." + if (other === reference) { + assert_equals(result, 0); + return; + } + + // "If other and reference are not in the same tree, return the result of + // adding DOCUMENT_POSITION_DISCONNECTED, + // DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, and either + // DOCUMENT_POSITION_PRECEDING or DOCUMENT_POSITION_FOLLOWING, with the + // constraint that this is to be consistent, together and terminate these + // steps." + if (furthestAncestor(reference) !== furthestAncestor(other)) { + // TODO: Test that it's consistent. + assert_in_array(result, [Node.DOCUMENT_POSITION_DISCONNECTED + + Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + + Node.DOCUMENT_POSITION_PRECEDING, + Node.DOCUMENT_POSITION_DISCONNECTED + + Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC + + Node.DOCUMENT_POSITION_FOLLOWING]); + return; + } + + // "If other is an ancestor of reference, return the result of + // adding DOCUMENT_POSITION_CONTAINS to DOCUMENT_POSITION_PRECEDING + // and terminate these steps." + var ancestor = reference.parentNode; + while (ancestor && ancestor !== other) { + ancestor = ancestor.parentNode; + } + if (ancestor === other) { + assert_equals(result, Node.DOCUMENT_POSITION_CONTAINS + + Node.DOCUMENT_POSITION_PRECEDING); + return; + } + + // "If other is a descendant of reference, return the result of adding + // DOCUMENT_POSITION_CONTAINED_BY to DOCUMENT_POSITION_FOLLOWING and + // terminate these steps." + ancestor = other.parentNode; + while (ancestor && ancestor !== reference) { + ancestor = ancestor.parentNode; + } + if (ancestor === reference) { + assert_equals(result, Node.DOCUMENT_POSITION_CONTAINED_BY + + Node.DOCUMENT_POSITION_FOLLOWING); + return; + } + + // "If other is preceding reference return DOCUMENT_POSITION_PRECEDING + // and terminate these steps." + var prev = previousNode(reference); + while (prev && prev !== other) { + prev = previousNode(prev); + } + if (prev === other) { + assert_equals(result, Node.DOCUMENT_POSITION_PRECEDING); + return; + } + + // "Return DOCUMENT_POSITION_FOLLOWING." + assert_equals(result, Node.DOCUMENT_POSITION_FOLLOWING); + }, referenceName + ".compareDocumentPosition(" + otherName + ")"); + }); +}); + +testDiv.parentNode.removeChild(testDiv); +</script> +<!-- vim: set expandtab tabstop=2 shiftwidth=2: --> diff --git a/testing/web-platform/tests/dom/nodes/Node-constants.html b/testing/web-platform/tests/dom/nodes/Node-constants.html new file mode 100644 index 0000000000..33e7c10e73 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-constants.html @@ -0,0 +1,39 @@ +<!doctype html> +<title>Node constants</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../constants.js"></script> +<div id="log"></div> +<script> +var objects; +setup(function() { + objects = [ + [Node, "Node interface object"], + [Node.prototype, "Node prototype object"], + [document.createElement("foo"), "Element object"], + [document.createTextNode("bar"), "Text object"] + ] +}) +testConstants(objects, [ + ["ELEMENT_NODE", 1], + ["ATTRIBUTE_NODE", 2], + ["TEXT_NODE", 3], + ["CDATA_SECTION_NODE", 4], + ["ENTITY_REFERENCE_NODE", 5], + ["ENTITY_NODE", 6], + ["PROCESSING_INSTRUCTION_NODE", 7], + ["COMMENT_NODE", 8], + ["DOCUMENT_NODE", 9], + ["DOCUMENT_TYPE_NODE", 10], + ["DOCUMENT_FRAGMENT_NODE", 11], + ["NOTATION_NODE", 12] +], "nodeType") +testConstants(objects, [ + ["DOCUMENT_POSITION_DISCONNECTED", 0x01], + ["DOCUMENT_POSITION_PRECEDING", 0x02], + ["DOCUMENT_POSITION_FOLLOWING", 0x04], + ["DOCUMENT_POSITION_CONTAINS", 0x08], + ["DOCUMENT_POSITION_CONTAINED_BY", 0x10], + ["DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", 0x20] +], "createDocumentPosition") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-contains-xml.xml b/testing/web-platform/tests/dom/nodes/Node-contains-xml.xml new file mode 100644 index 0000000000..f9b20d68d6 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-contains-xml.xml @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Node.nodeName</title> +<link rel="author" title="Olli Pettay" href="mailto:Olli@Pettay.fi"/> +<link rel="author" title="Ms2ger" href="mailto:Ms2ger@gmail.com"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<div id="test"> + <input type="button" id="testbutton"/> + <a id="link">Link text</a> +</div> +<script> +<![CDATA[ +test(function() { + assert_throws_js(TypeError, function() { + document.contains(); + }); + assert_throws_js(TypeError, function() { + document.contains(9); + }); +}, "Should throw TypeError if the arguments are wrong."); + +test(function() { + assert_equals(document.contains(null), false, "Document shouldn't contain null."); +}, "contains(null) should be false"); + +test(function() { + assert_equals(document.contains(document), true, "Document should contain itself!"); + assert_equals(document.contains(document.createElement("foo")), false, "Document shouldn't contain element which is't in the document"); + assert_equals(document.contains(document.createTextNode("foo")), false, "Document shouldn't contain text node which is't in the document"); +}, "document.contains"); + +test(function() { + var tb = document.getElementById("testbutton"); + assert_equals(tb.contains(tb), true, "Element should contain itself.") + assert_equals(document.contains(tb), true, "Document should contain element in it!"); + assert_equals(document.documentElement.contains(tb), true, "Element should contain element in it!"); +}, "contains with a button"); + +test(function() { + var link = document.getElementById("link"); + var text = link.firstChild; + assert_equals(document.contains(text), true, "Document should contain a text node in it."); + assert_equals(link.contains(text), true, "Element should contain a text node in it."); + assert_equals(text.contains(text), true, "Text node should contain itself."); + assert_equals(text.contains(link), false, "text node shouldn't contain its parent."); +}, "contains with a text node"); + +test(function() { + var pi = document.createProcessingInstruction("adf", "asd"); + assert_equals(pi.contains(document), false, "Processing instruction shouldn't contain document"); + assert_equals(document.contains(pi), false, "Document shouldn't contain newly created processing instruction"); + document.documentElement.appendChild(pi); + assert_equals(document.contains(pi), true, "Document should contain processing instruction"); +}, "contains with a processing instruction"); + +test(function() { + if ("createContextualFragment" in document.createRange()) { + var df = document.createRange().createContextualFragment("<div>foo</div>"); + assert_equals(df.contains(df.firstChild), true, "Document fragment should contain its child"); + assert_equals(df.contains(df.firstChild.firstChild), true, + "Document fragment should contain its descendant"); + assert_equals(df.contains(df), true, "Document fragment should contain itself."); + } +}, "contains with a document fragment"); + +test(function() { + var d = document.implementation.createHTMLDocument(""); + assert_equals(document.contains(d), false, + "Document shouldn't contain another document."); + assert_equals(document.contains(d.createElement("div")), false, + "Document shouldn't contain an element from another document."); + assert_equals(document.contains(d.documentElement), false, + "Document shouldn't contain an element from another document."); +}, "contaibs with another document"); +]]> +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Node-contains.html b/testing/web-platform/tests/dom/nodes/Node-contains.html new file mode 100644 index 0000000000..c44f072b11 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-contains.html @@ -0,0 +1,36 @@ +<!doctype html> +<title>Node.contains() tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testNodes.forEach(function(referenceName) { + var reference = eval(referenceName); + + test(function() { + assert_false(reference.contains(null)); + }, referenceName + ".contains(null)"); + + testNodes.forEach(function(otherName) { + var other = eval(otherName); + test(function() { + var ancestor = other; + while (ancestor && ancestor !== reference) { + ancestor = ancestor.parentNode; + } + if (ancestor === reference) { + assert_true(reference.contains(other)); + } else { + assert_false(reference.contains(other)); + } + }, referenceName + ".contains(" + otherName + ")"); + }); +}); + +testDiv.parentNode.removeChild(testDiv); +</script> +<!-- vim: set expandtab tabstop=2 shiftwidth=2: --> diff --git a/testing/web-platform/tests/dom/nodes/Node-insertBefore.html b/testing/web-platform/tests/dom/nodes/Node-insertBefore.html new file mode 100644 index 0000000000..ecb4d18314 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-insertBefore.html @@ -0,0 +1,297 @@ +<!DOCTYPE html> +<title>Node.insertBefore</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<!-- First test shared pre-insertion checks that work similarly for replaceChild + and insertBefore --> +<script> + var insertFunc = Node.prototype.insertBefore; +</script> +<script src="pre-insertion-validation-notfound.js"></script> +<script src="pre-insertion-validation-hierarchy.js"></script> +<script> +preInsertionValidateHierarchy("insertBefore"); + +function testLeafNode(nodeName, createNodeFunction) { + test(function() { + var node = createNodeFunction(); + assert_throws_js(TypeError, function() { node.insertBefore(null, null) }) + }, "Calling insertBefore with a non-Node first argument on a leaf node " + nodeName + " must throw TypeError.") + test(function() { + var node = createNodeFunction(); + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.insertBefore(document.createTextNode("fail"), null) }) + // Would be step 2. + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.insertBefore(node, null) }) + // Would be step 3. + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { node.insertBefore(node, document.createTextNode("child")) }) + }, "Calling insertBefore an a leaf node " + nodeName + " must throw HIERARCHY_REQUEST_ERR.") +} + +test(function() { + // WebIDL: first argument. + assert_throws_js(TypeError, function() { document.body.insertBefore(null, null) }) + assert_throws_js(TypeError, function() { document.body.insertBefore(null, document.body.firstChild) }) + assert_throws_js(TypeError, function() { document.body.insertBefore({'a':'b'}, document.body.firstChild) }) +}, "Calling insertBefore with a non-Node first argument must throw TypeError.") + +test(function() { + // WebIDL: second argument. + assert_throws_js(TypeError, function() { document.body.insertBefore(document.createTextNode("child")) }) + assert_throws_js(TypeError, function() { document.body.insertBefore(document.createTextNode("child"), {'a':'b'}) }) +}, "Calling insertBefore with second argument missing, or other than Node, null, or undefined, must throw TypeError.") + +testLeafNode("DocumentType", function () { return document.doctype; } ) +testLeafNode("Text", function () { return document.createTextNode("Foo") }) +testLeafNode("Comment", function () { return document.createComment("Foo") }) +testLeafNode("ProcessingInstruction", function () { return document.createProcessingInstruction("foo", "bar") }) + +test(function() { + // Step 2. + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { document.body.insertBefore(document.body, document.getElementById("log")) }) + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { document.body.insertBefore(document.documentElement, document.getElementById("log")) }) +}, "Calling insertBefore with an inclusive ancestor of the context object must throw HIERARCHY_REQUEST_ERR.") + +// Step 3. +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + assert_throws_dom("NotFoundError", function() { + a.insertBefore(b, c); + }); +}, "Calling insertBefore with a reference child whose parent is not the context node must throw a NotFoundError.") + +// Step 4.1. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var doc2 = document.implementation.createHTMLDocument("title2"); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doc2, doc.documentElement); + }); + + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doc.createTextNode("text"), doc.documentElement); + }); +}, "If the context node is a document, inserting a document or text node should throw a HierarchyRequestError.") + +// Step 4.2.1. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + doc.removeChild(doc.documentElement); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + df.appendChild(doc.createElement("b")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.firstChild); + }); + + df = doc.createDocumentFragment(); + df.appendChild(doc.createTextNode("text")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.firstChild); + }); + + df = doc.createDocumentFragment(); + df.appendChild(doc.createComment("comment")); + df.appendChild(doc.createTextNode("text")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.firstChild); + }); +}, "If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError.") + +// Step 4.2.2. +test(function() { + // The context node has an element child. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.doctype); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.documentElement); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, null); + }); +}, "If the context node is a document, inserting a DocumentFragment with an element if there already is an element child should throw a HierarchyRequestError.") +test(function() { + // /child/ is a doctype. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, doc.doctype); + }); +}, "If the context node is a document and a doctype is following the reference child, inserting a DocumentFragment with an element should throw a HierarchyRequestError.") +test(function() { + // /child/ is not null and a doctype is following /child/. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(df, comment); + }); +}, "If the context node is a document, inserting a DocumentFragment with an element before the doctype should throw a HierarchyRequestError.") + +// Step 4.3. +test(function() { + // The context node has an element child. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]); + + var a = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, doc.doctype); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, doc.documentElement); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, null); + }); +}, "If the context node is a document, inserting an element if there already is an element child should throw a HierarchyRequestError.") +test(function() { + // /child/ is a doctype. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var a = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, doc.doctype); + }); +}, "If the context node is a document, inserting an element before the doctype should throw a HierarchyRequestError.") +test(function() { + // /child/ is not null and a doctype is following /child/. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var a = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(a, comment); + }); +}, "If the context node is a document and a doctype is following the reference child, inserting an element should throw a HierarchyRequestError.") + +// Step 4.4. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + assert_array_equals(doc.childNodes, [comment, doc.doctype, doc.documentElement]); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, doc.doctype); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, doc.documentElement); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, null); + }); +}, "If the context node is a document, inserting a doctype if there already is a doctype child should throw a HierarchyRequestError.") +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + doc.removeChild(doc.doctype); + assert_array_equals(doc.childNodes, [doc.documentElement, comment]); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, comment); + }); +}, "If the context node is a document, inserting a doctype after the document element should throw a HierarchyRequestError.") +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + doc.removeChild(doc.doctype); + assert_array_equals(doc.childNodes, [doc.documentElement, comment]); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + doc.insertBefore(doctype, null); + }); +}, "If the context node is a document with and element child, appending a doctype should throw a HierarchyRequestError.") + +// Step 5. +test(function() { + var df = document.createDocumentFragment(); + var a = df.appendChild(document.createElement("a")); + + var doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", function() { + df.insertBefore(doc, a); + }); + assert_throws_dom("HierarchyRequestError", function() { + df.insertBefore(doc, null); + }); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + df.insertBefore(doctype, a); + }); + assert_throws_dom("HierarchyRequestError", function() { + df.insertBefore(doctype, null); + }); +}, "If the context node is a DocumentFragment, inserting a document or a doctype should throw a HierarchyRequestError.") +test(function() { + var el = document.createElement("div"); + var a = el.appendChild(document.createElement("a")); + + var doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", function() { + el.insertBefore(doc, a); + }); + assert_throws_dom("HierarchyRequestError", function() { + el.insertBefore(doc, null); + }); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + el.insertBefore(doctype, a); + }); + assert_throws_dom("HierarchyRequestError", function() { + el.insertBefore(doctype, null); + }); +}, "If the context node is an element, inserting a document or a doctype should throw a HierarchyRequestError.") + +// Step 7. +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + a.appendChild(b); + a.appendChild(c); + assert_array_equals(a.childNodes, [b, c]); + assert_equals(a.insertBefore(b, b), b); + assert_array_equals(a.childNodes, [b, c]); + assert_equals(a.insertBefore(c, c), c); + assert_array_equals(a.childNodes, [b, c]); +}, "Inserting a node before itself should not move the node"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-isConnected-shadow-dom.html b/testing/web-platform/tests/dom/nodes/Node-isConnected-shadow-dom.html new file mode 100644 index 0000000000..7d04dc32f2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isConnected-shadow-dom.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Test of Node.isConnected in a shadow tree</title> +<link rel="help" href="https://dom.spec.whatwg.org/#connected"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +function testIsConnected(mode) { + test(() => { + const host = document.createElement("div"); + document.body.appendChild(host); + + const root = host.attachShadow({ mode }); + + const node = document.createElement("div"); + root.appendChild(node); + + assert_true(node.isConnected); + }, `Node.isConnected in a ${mode} shadow tree`); +} + +for (const mode of ["closed", "open"]) { + testIsConnected(mode); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-isConnected.html b/testing/web-platform/tests/dom/nodes/Node-isConnected.html new file mode 100644 index 0000000000..da0b460de4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isConnected.html @@ -0,0 +1,95 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<head> +<title>Node.prototype.isConnected</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-isconnected"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script> + +"use strict"; + +test(function() { + var nodes = [document.createElement("div"), + document.createElement("div"), + document.createElement("div")]; + checkNodes([], nodes); + + // Append nodes[0]. + document.body.appendChild(nodes[0]); + checkNodes([nodes[0]], + [nodes[1], nodes[2]]); + + // Append nodes[1] and nodes[2] together. + nodes[1].appendChild(nodes[2]); + checkNodes([nodes[0]], + [nodes[1], nodes[2]]); + + nodes[0].appendChild(nodes[1]); + checkNodes(nodes, []); + + // Remove nodes[2]. + nodes[2].remove(); + checkNodes([nodes[0], nodes[1]], + [nodes[2]]); + + // Remove nodes[0] and nodes[1] together. + nodes[0].remove(); + checkNodes([], nodes); +}, "Test with ordinary child nodes"); + +test(function() { + var nodes = [document.createElement("iframe"), + document.createElement("iframe"), + document.createElement("iframe"), + document.createElement("iframe"), + document.createElement("div")]; + var frames = [nodes[0], + nodes[1], + nodes[2], + nodes[3]]; + checkNodes([], nodes); + + // Since we cannot append anything to the contentWindow of an iframe before it + // is appended to the main DOM tree, we append the iframes one after another. + document.body.appendChild(nodes[0]); + checkNodes([nodes[0]], + [nodes[1], nodes[2], nodes[3], nodes[4]]); + + frames[0].contentDocument.body.appendChild(nodes[1]); + checkNodes([nodes[0], nodes[1]], + [nodes[2], nodes[3], nodes[4]]); + + frames[1].contentDocument.body.appendChild(nodes[2]); + checkNodes([nodes[0], nodes[1], nodes[2]], + [nodes[3], nodes[4]]); + + frames[2].contentDocument.body.appendChild(nodes[3]); + checkNodes([nodes[0], nodes[1], nodes[2], nodes[3]], + [nodes[4]]); + + frames[3].contentDocument.body.appendChild(nodes[4]); + checkNodes(nodes, []); + + frames[3].remove(); + // Since node[4] is still under the doument of frame[3], it's still connected. + checkNodes([nodes[0], nodes[1], nodes[2], nodes[4]], + [nodes[3]]); + + frames[0].remove(); + // Since node[1] and node[2] are still under the doument of frame[0], they are + // still connected. + checkNodes([nodes[1], nodes[2], nodes[4]], + [nodes[0], nodes[3]]); +}, "Test with iframes"); + +// This helper function is used to check whether nodes should be connected. +function checkNodes(aConnectedNodes, aDisconnectedNodes) { + aConnectedNodes.forEach(node => assert_true(node.isConnected)); + aDisconnectedNodes.forEach(node => assert_false(node.isConnected)); +} + +</script> +</body> diff --git a/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe1.xml b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe1.xml new file mode 100644 index 0000000000..8077e73c27 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe1.xml @@ -0,0 +1 @@ +<!DOCTYPE foo [ <!ELEMENT foo (#PCDATA)> ]><foo/> diff --git a/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe2.xml b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe2.xml new file mode 100644 index 0000000000..eacc9d17af --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-iframe2.xml @@ -0,0 +1 @@ +<!DOCTYPE foo [ <!ELEMENT foo EMPTY> ]><foo/> diff --git a/testing/web-platform/tests/dom/nodes/Node-isEqualNode-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-xhtml.xhtml new file mode 100644 index 0000000000..3170643d2f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isEqualNode-xhtml.xhtml @@ -0,0 +1,84 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Node.isEqualNode</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +function testNullHandling(node) { + test(function() { + assert_false(node.isEqualNode(null)) + assert_false(node.isEqualNode(undefined)) + }) +} +[ + document.createElement("foo"), + document.createTextNode("foo"), + document.createProcessingInstruction("foo", "bar"), + document.createComment("foo"), + document, + document.implementation.createDocumentType("html", "", ""), + document.createDocumentFragment() +].forEach(testNullHandling) + +test(function() { + var a = document.createElement("foo") + a.setAttribute("a", "bar") + a.setAttribute("b", "baz") + var b = document.createElement("foo") + b.setAttribute("b", "baz") + b.setAttribute("a", "bar") + assert_true(a.isEqualNode(b)) +}, "isEqualNode should return true when the attributes are in a different order") + +test(function() { + var a = document.createElementNS("ns", "prefix:foo") + var b = document.createElementNS("ns", "prefix:foo") + assert_true(a.isEqualNode(b)) +}, "isEqualNode should return true if elements have same namespace, prefix, and local name") + +test(function() { + var a = document.createElementNS("ns1", "prefix:foo") + var b = document.createElementNS("ns2", "prefix:foo") + assert_false(a.isEqualNode(b)) +}, "isEqualNode should return false if elements have different namespace") + +test(function() { + var a = document.createElementNS("ns", "prefix1:foo") + var b = document.createElementNS("ns", "prefix2:foo") + assert_false(a.isEqualNode(b)) +}, "isEqualNode should return false if elements have different prefix") + +test(function() { + var a = document.createElementNS("ns", "prefix:foo1") + var b = document.createElementNS("ns", "prefix:foo2") + assert_false(a.isEqualNode(b)) +}, "isEqualNode should return false if elements have different local name") + +test(function() { + var a = document.createElement("foo") + a.setAttributeNS("ns", "x:a", "bar") + var b = document.createElement("foo") + b.setAttributeNS("ns", "y:a", "bar") + assert_true(a.isEqualNode(b)) +}, "isEqualNode should return true when the attributes have different prefixes") +var internalSubset = async_test("isEqualNode should return true when only the internal subsets of DocumentTypes differ.") +var wait = 2; +function iframeLoaded() { + if (!--wait) { + internalSubset.step(function() { + var doc1 = document.getElementById("subset1").contentDocument + var doc2 = document.getElementById("subset2").contentDocument + assert_true(doc1.doctype.isEqualNode(doc2.doctype), "doc1.doctype.isEqualNode(doc2.doctype)") + assert_true(doc1.isEqualNode(doc2), "doc1.isEqualNode(doc2)") + }) + internalSubset.done() + } +} +</script> +<iframe id="subset1" onload="iframeLoaded()" src="Node-isEqualNode-iframe1.xml" /> +<iframe id="subset2" onload="iframeLoaded()" src="Node-isEqualNode-iframe2.xml" /> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Node-isEqualNode.html b/testing/web-platform/tests/dom/nodes/Node-isEqualNode.html new file mode 100644 index 0000000000..9ff4c5b03c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isEqualNode.html @@ -0,0 +1,161 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Node.prototype.isEqualNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-isequalnode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(function() { + + var doctype1 = document.implementation.createDocumentType("qualifiedName", "publicId", "systemId"); + var doctype2 = document.implementation.createDocumentType("qualifiedName", "publicId", "systemId"); + var doctype3 = document.implementation.createDocumentType("qualifiedName2", "publicId", "systemId"); + var doctype4 = document.implementation.createDocumentType("qualifiedName", "publicId2", "systemId"); + var doctype5 = document.implementation.createDocumentType("qualifiedName", "publicId", "systemId3"); + + assert_true(doctype1.isEqualNode(doctype1), "self-comparison"); + assert_true(doctype1.isEqualNode(doctype2), "same properties"); + assert_false(doctype1.isEqualNode(doctype3), "different name"); + assert_false(doctype1.isEqualNode(doctype4), "different public ID"); + assert_false(doctype1.isEqualNode(doctype5), "different system ID"); + +}, "doctypes should be compared on name, public ID, and system ID"); + +test(function() { + + var element1 = document.createElementNS("namespace", "prefix:localName"); + var element2 = document.createElementNS("namespace", "prefix:localName"); + var element3 = document.createElementNS("namespace2", "prefix:localName"); + var element4 = document.createElementNS("namespace", "prefix2:localName"); + var element5 = document.createElementNS("namespace", "prefix:localName2"); + + var element6 = document.createElementNS("namespace", "prefix:localName"); + element6.setAttribute("foo", "bar"); + + assert_true(element1.isEqualNode(element1), "self-comparison"); + assert_true(element1.isEqualNode(element2), "same properties"); + assert_false(element1.isEqualNode(element3), "different namespace"); + assert_false(element1.isEqualNode(element4), "different prefix"); + assert_false(element1.isEqualNode(element5), "different local name"); + assert_false(element1.isEqualNode(element6), "different number of attributes"); + +}, "elements should be compared on namespace, namespace prefix, local name, and number of attributes"); + +test(function() { + + var element1 = document.createElement("element"); + element1.setAttributeNS("namespace", "prefix:localName", "value"); + + var element2 = document.createElement("element"); + element2.setAttributeNS("namespace", "prefix:localName", "value"); + + var element3 = document.createElement("element"); + element3.setAttributeNS("namespace2", "prefix:localName", "value"); + + var element4 = document.createElement("element"); + element4.setAttributeNS("namespace", "prefix2:localName", "value"); + + var element5 = document.createElement("element"); + element5.setAttributeNS("namespace", "prefix:localName2", "value"); + + var element6 = document.createElement("element"); + element6.setAttributeNS("namespace", "prefix:localName", "value2"); + + assert_true(element1.isEqualNode(element1), "self-comparison"); + assert_true(element1.isEqualNode(element2), "attribute with same properties"); + assert_false(element1.isEqualNode(element3), "attribute with different namespace"); + assert_true(element1.isEqualNode(element4), "attribute with different prefix"); + assert_false(element1.isEqualNode(element5), "attribute with different local name"); + assert_false(element1.isEqualNode(element6), "attribute with different value"); + +}, "elements should be compared on attribute namespace, local name, and value"); + +test(function() { + + var pi1 = document.createProcessingInstruction("target", "data"); + var pi2 = document.createProcessingInstruction("target", "data"); + var pi3 = document.createProcessingInstruction("target2", "data"); + var pi4 = document.createProcessingInstruction("target", "data2"); + + assert_true(pi1.isEqualNode(pi1), "self-comparison"); + assert_true(pi1.isEqualNode(pi2), "same properties"); + assert_false(pi1.isEqualNode(pi3), "different target"); + assert_false(pi1.isEqualNode(pi4), "different data"); + +}, "processing instructions should be compared on target and data"); + +test(function() { + + var text1 = document.createTextNode("data"); + var text2 = document.createTextNode("data"); + var text3 = document.createTextNode("data2"); + + assert_true(text1.isEqualNode(text1), "self-comparison"); + assert_true(text1.isEqualNode(text2), "same properties"); + assert_false(text1.isEqualNode(text3), "different data"); + +}, "text nodes should be compared on data"); + +test(function() { + + var comment1 = document.createComment("data"); + var comment2 = document.createComment("data"); + var comment3 = document.createComment("data2"); + + assert_true(comment1.isEqualNode(comment1), "self-comparison"); + assert_true(comment1.isEqualNode(comment2), "same properties"); + assert_false(comment1.isEqualNode(comment3), "different data"); + +}, "comments should be compared on data"); + +test(function() { + + var documentFragment1 = document.createDocumentFragment(); + var documentFragment2 = document.createDocumentFragment(); + + assert_true(documentFragment1.isEqualNode(documentFragment1), "self-comparison"); + assert_true(documentFragment1.isEqualNode(documentFragment2), "same properties"); + +}, "document fragments should not be compared based on properties"); + +test(function() { + + var document1 = document.implementation.createDocument("", ""); + var document2 = document.implementation.createDocument("", ""); + + assert_true(document1.isEqualNode(document1), "self-comparison"); + assert_true(document1.isEqualNode(document2), "another empty XML document"); + + var htmlDoctype = document.implementation.createDocumentType("html", "", ""); + var document3 = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", htmlDoctype); + document3.documentElement.appendChild(document3.createElement("head")); + document3.documentElement.appendChild(document3.createElement("body")); + var document4 = document.implementation.createHTMLDocument(); + assert_true(document3.isEqualNode(document4), "default HTML documents, created different ways"); + +}, "documents should not be compared based on properties"); + +test(function() { + + testDeepEquality(function() { return document.createElement("foo") }); + testDeepEquality(function() { return document.createDocumentFragment() }); + testDeepEquality(function() { return document.implementation.createDocument("", "") }); + testDeepEquality(function() { return document.implementation.createHTMLDocument() }); + + function testDeepEquality(parentFactory) { + // Some ad-hoc tests of deep equality + + var parentA = parentFactory(); + var parentB = parentFactory(); + + parentA.appendChild(document.createComment("data")); + assert_false(parentA.isEqualNode(parentB)); + parentB.appendChild(document.createComment("data")); + assert_true(parentA.isEqualNode(parentB)); + } + +}, "node equality testing should test descendant equality too"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-isSameNode.html b/testing/web-platform/tests/dom/nodes/Node-isSameNode.html new file mode 100644 index 0000000000..b37442ac80 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-isSameNode.html @@ -0,0 +1,111 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Node.prototype.isSameNode</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-issamenode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +"use strict"; + +test(function() { + + var doctype1 = document.implementation.createDocumentType("qualifiedName", "publicId", "systemId"); + var doctype2 = document.implementation.createDocumentType("qualifiedName", "publicId", "systemId"); + + assert_true(doctype1.isSameNode(doctype1), "self-comparison"); + assert_false(doctype1.isSameNode(doctype2), "same properties"); + assert_false(doctype1.isSameNode(null), "with null other node"); +}, "doctypes should be compared on reference"); + +test(function() { + + var element1 = document.createElementNS("namespace", "prefix:localName"); + var element2 = document.createElementNS("namespace", "prefix:localName"); + + assert_true(element1.isSameNode(element1), "self-comparison"); + assert_false(element1.isSameNode(element2), "same properties"); + assert_false(element1.isSameNode(null), "with null other node"); + +}, "elements should be compared on reference (namespaced element)"); + +test(function() { + + var element1 = document.createElement("element"); + element1.setAttributeNS("namespace", "prefix:localName", "value"); + + var element2 = document.createElement("element"); + element2.setAttributeNS("namespace", "prefix:localName", "value"); + + assert_true(element1.isSameNode(element1), "self-comparison"); + assert_false(element1.isSameNode(element2), "same properties"); + assert_false(element1.isSameNode(null), "with null other node"); + +}, "elements should be compared on reference (namespaced attribute)"); + +test(function() { + + var pi1 = document.createProcessingInstruction("target", "data"); + var pi2 = document.createProcessingInstruction("target", "data"); + + assert_true(pi1.isSameNode(pi1), "self-comparison"); + assert_false(pi1.isSameNode(pi2), "different target"); + assert_false(pi1.isSameNode(null), "with null other node"); + +}, "processing instructions should be compared on reference"); + +test(function() { + + var text1 = document.createTextNode("data"); + var text2 = document.createTextNode("data"); + + assert_true(text1.isSameNode(text1), "self-comparison"); + assert_false(text1.isSameNode(text2), "same properties"); + assert_false(text1.isSameNode(null), "with null other node"); + +}, "text nodes should be compared on reference"); + +test(function() { + + var comment1 = document.createComment("data"); + var comment2 = document.createComment("data"); + + assert_true(comment1.isSameNode(comment1), "self-comparison"); + assert_false(comment1.isSameNode(comment2), "same properties"); + assert_false(comment1.isSameNode(null), "with null other node"); + +}, "comments should be compared on reference"); + +test(function() { + + var documentFragment1 = document.createDocumentFragment(); + var documentFragment2 = document.createDocumentFragment(); + + assert_true(documentFragment1.isSameNode(documentFragment1), "self-comparison"); + assert_false(documentFragment1.isSameNode(documentFragment2), "same properties"); + assert_false(documentFragment1.isSameNode(null), "with null other node"); + +}, "document fragments should be compared on reference"); + +test(function() { + + var document1 = document.implementation.createDocument("", ""); + var document2 = document.implementation.createDocument("", ""); + + assert_true(document1.isSameNode(document1), "self-comparison"); + assert_false(document1.isSameNode(document2), "another empty XML document"); + assert_false(document1.isSameNode(null), "with null other node"); + +}, "documents should be compared on reference"); + +test(function() { + + var attr1 = document.createAttribute('href'); + var attr2 = document.createAttribute('href'); + + assert_true(attr1.isSameNode(attr1), "self-comparison"); + assert_false(attr1.isSameNode(attr2), "same name"); + assert_false(attr1.isSameNode(null), "with null other node"); + +}, "attributes should be compared on reference"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-lookupNamespaceURI.html b/testing/web-platform/tests/dom/nodes/Node-lookupNamespaceURI.html new file mode 100644 index 0000000000..74c1ac8bd7 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-lookupNamespaceURI.html @@ -0,0 +1,124 @@ +<!DOCTYPE html> +<html> +<head> +<title>LookupNamespaceURI and IsDefaultNamespace tests</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +</head> +<body> +<h1>LookupNamespaceURI and IsDefaultNamespace</h1> +<div id="log"/> +<script> +function lookupNamespaceURI(node, prefix, expected, name) { + test(function() { + assert_equals(node.lookupNamespaceURI(prefix), expected); + }, name); +} + +function isDefaultNamespace(node, namespace, expected, name) { + test(function() { + assert_equals(node.isDefaultNamespace(namespace), expected); + }, name); +} + + +var frag = document.createDocumentFragment(); +lookupNamespaceURI(frag, null, null, 'DocumentFragment should have null namespace, prefix null'); +lookupNamespaceURI(frag, '', null, 'DocumentFragment should have null namespace, prefix ""'); +lookupNamespaceURI(frag, 'foo', null, 'DocumentFragment should have null namespace, prefix "foo"'); +lookupNamespaceURI(frag, 'xmlns', null, 'DocumentFragment should have null namespace, prefix "xmlns"'); +isDefaultNamespace(frag, null, true, 'DocumentFragment is in default namespace, prefix null'); +isDefaultNamespace(frag, '', true, 'DocumentFragment is in default namespace, prefix ""'); +isDefaultNamespace(frag, 'foo', false, 'DocumentFragment is in default namespace, prefix "foo"'); +isDefaultNamespace(frag, 'xmlns', false, 'DocumentFragment is in default namespace, prefix "xmlns"'); + +var docType = document.doctype; +lookupNamespaceURI(docType, null, null, 'DocumentType should have null namespace, prefix null'); +lookupNamespaceURI(docType, '', null, 'DocumentType should have null namespace, prefix ""'); +lookupNamespaceURI(docType, 'foo', null, 'DocumentType should have null namespace, prefix "foo"'); +lookupNamespaceURI(docType, 'xmlns', null, 'DocumentType should have null namespace, prefix "xmlns"'); +isDefaultNamespace(docType, null, true, 'DocumentType is in default namespace, prefix null'); +isDefaultNamespace(docType, '', true, 'DocumentType is in default namespace, prefix ""'); +isDefaultNamespace(docType, 'foo', false, 'DocumentType is in default namespace, prefix "foo"'); +isDefaultNamespace(docType, 'xmlns', false, 'DocumentType is in default namespace, prefix "xmlns"'); + +var fooElem = document.createElementNS('fooNamespace', 'prefix:elem'); +fooElem.setAttribute('bar', 'value'); + +lookupNamespaceURI(fooElem, null, null, 'Element should have null namespace, prefix null'); +lookupNamespaceURI(fooElem, '', null, 'Element should have null namespace, prefix ""'); +lookupNamespaceURI(fooElem, 'fooNamespace', null, 'Element should not have namespace matching prefix with namespaceURI value'); +lookupNamespaceURI(fooElem, 'xmlns', null, 'Element should not have XMLNS namespace'); +lookupNamespaceURI(fooElem, 'prefix', 'fooNamespace', 'Element has namespace URI matching prefix'); +isDefaultNamespace(fooElem, null, true, 'Empty namespace is not default, prefix null'); +isDefaultNamespace(fooElem, '', true, 'Empty namespace is not default, prefix ""'); +isDefaultNamespace(fooElem, 'fooNamespace', false, 'fooNamespace is not default'); +isDefaultNamespace(fooElem, 'http://www.w3.org/2000/xmlns/', false, 'xmlns namespace is not default'); + +fooElem.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'barURI'); +fooElem.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'bazURI'); + +lookupNamespaceURI(fooElem, null, 'bazURI', 'Element should have baz namespace, prefix null'); +lookupNamespaceURI(fooElem, '', 'bazURI', 'Element should have baz namespace, prefix ""'); +lookupNamespaceURI(fooElem, 'xmlns', null, 'Element does not has namespace with xlmns prefix'); +lookupNamespaceURI(fooElem, 'bar', 'barURI', 'Element has bar namespace'); + +isDefaultNamespace(fooElem, null, false, 'Empty namespace is not default on fooElem, prefix null'); +isDefaultNamespace(fooElem, '', false, 'Empty namespace is not default on fooElem, prefix ""'); +isDefaultNamespace(fooElem, 'barURI', false, 'bar namespace is not default'); +isDefaultNamespace(fooElem, 'bazURI', true, 'baz namespace is default'); + +var comment = document.createComment('comment'); +fooElem.appendChild(comment); + +lookupNamespaceURI(comment, null, 'bazURI', 'Comment should inherit baz namespace'); +lookupNamespaceURI(comment, '', 'bazURI', 'Comment should inherit baz namespace'); +lookupNamespaceURI(comment, 'prefix', 'fooNamespace', 'Comment should inherit namespace URI matching prefix'); +lookupNamespaceURI(comment, 'bar', 'barURI', 'Comment should inherit bar namespace'); + +isDefaultNamespace(comment, null, false, 'For comment, empty namespace is not default, prefix null'); +isDefaultNamespace(comment, '', false, 'For comment, empty namespace is not default, prefix ""'); +isDefaultNamespace(comment, 'fooNamespace', false, 'For comment, fooNamespace is not default'); +isDefaultNamespace(comment, 'http://www.w3.org/2000/xmlns/', false, 'For comment, xmlns namespace is not default'); +isDefaultNamespace(comment, 'barURI', false, 'For comment, inherited bar namespace is not default'); +isDefaultNamespace(comment, 'bazURI', true, 'For comment, inherited baz namespace is default'); + +var fooChild = document.createElementNS('childNamespace', 'childElem'); +fooElem.appendChild(fooChild); + +lookupNamespaceURI(fooChild, null, 'childNamespace', 'Child element should inherit baz namespace'); +lookupNamespaceURI(fooChild, '', 'childNamespace', 'Child element should have null namespace'); +lookupNamespaceURI(fooChild, 'xmlns', null, 'Child element should not have XMLNS namespace'); +lookupNamespaceURI(fooChild, 'prefix', 'fooNamespace', 'Child element has namespace URI matching prefix'); + +isDefaultNamespace(fooChild, null, false, 'Empty namespace is not default for child, prefix null'); +isDefaultNamespace(fooChild, '', false, 'Empty namespace is not default for child, prefix ""'); +isDefaultNamespace(fooChild, 'fooNamespace', false, 'fooNamespace is not default for child'); +isDefaultNamespace(fooChild, 'http://www.w3.org/2000/xmlns/', false, 'xmlns namespace is not default for child'); +isDefaultNamespace(fooChild, 'barURI', false, 'bar namespace is not default for child'); +isDefaultNamespace(fooChild, 'bazURI', false, 'baz namespace is default for child'); +isDefaultNamespace(fooChild, 'childNamespace', true, 'childNamespace is default for child'); + +document.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:bar', 'barURI'); +document.documentElement.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'bazURI'); + +lookupNamespaceURI(document, null, 'http://www.w3.org/1999/xhtml', 'Document should have xhtml namespace, prefix null'); +lookupNamespaceURI(document, '', 'http://www.w3.org/1999/xhtml', 'Document should have xhtml namespace, prefix ""'); +lookupNamespaceURI(document, 'prefix', null, 'Document has no namespace URI matching prefix'); +lookupNamespaceURI(document, 'bar', 'barURI', 'Document has bar namespace'); + +isDefaultNamespace(document, null, false, 'For document, empty namespace is not default, prefix null'); +isDefaultNamespace(document, '', false, 'For document, empty namespace is not default, prefix ""'); +isDefaultNamespace(document, 'fooNamespace', false, 'For document, fooNamespace is not default'); +isDefaultNamespace(document, 'http://www.w3.org/2000/xmlns/', false, 'For document, xmlns namespace is not default'); +isDefaultNamespace(document, 'barURI', false, 'For document, bar namespace is not default'); +isDefaultNamespace(document, 'bazURI', false, 'For document, baz namespace is not default'); +isDefaultNamespace(document, 'http://www.w3.org/1999/xhtml', true, 'For document, xhtml namespace is default'); + +var comment = document.createComment('comment'); +document.appendChild(comment); +lookupNamespaceURI(comment, 'bar', null, 'Comment does not have bar namespace'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Node-lookupPrefix.xhtml b/testing/web-platform/tests/dom/nodes/Node-lookupPrefix.xhtml new file mode 100644 index 0000000000..50a487c58c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-lookupPrefix.xhtml @@ -0,0 +1,31 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:x="test"> +<head> +<title>Node.lookupPrefix</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body xmlns:s="test"> +<div id="log"/> +<x xmlns:t="test"><!--comment--><?test test?>TEST<x/></x> +<script> +function lookupPrefix(node, ns, prefix) { + test(function() { + assert_equals(node.lookupPrefix(ns), prefix) + }) +} +var x = document.getElementsByTagName("x")[0]; +lookupPrefix(document, "test", "x") // XXX add test for when there is no documentElement +lookupPrefix(document, null, null) +lookupPrefix(x, "http://www.w3.org/1999/xhtml", null) +lookupPrefix(x, "something", null) +lookupPrefix(x, null, null) +lookupPrefix(x, "test", "t") +lookupPrefix(x.parentNode, "test", "s") +lookupPrefix(x.firstChild, "test", "t") +lookupPrefix(x.childNodes[1], "test", "t") +lookupPrefix(x.childNodes[2], "test", "t") +lookupPrefix(x.lastChild, "test", "t") +x.parentNode.removeChild(x) +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Node-mutation-adoptNode.html b/testing/web-platform/tests/dom/nodes/Node-mutation-adoptNode.html new file mode 100644 index 0000000000..9c9594c07b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-mutation-adoptNode.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node-manipulation-adopted</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument"> +<link rel=help href="https://dom.spec.whatwg.org/#mutation-algorithms"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +"use strict"; + +test(() => { + const old = document.implementation.createHTMLDocument(""); + const div = old.createElement("div"); + div.appendChild(old.createTextNode("text")); + assert_equals(div.ownerDocument, old); + assert_equals(div.firstChild.ownerDocument, old); + document.body.appendChild(div); + assert_equals(div.ownerDocument, document); + assert_equals(div.firstChild.ownerDocument, document); +}, "simple append of foreign div with text"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-nodeName-xhtml.xhtml b/testing/web-platform/tests/dom/nodes/Node-nodeName-xhtml.xhtml new file mode 100644 index 0000000000..bc478af8b6 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-nodeName-xhtml.xhtml @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>Node.nodeName</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml", + SVGNS = "http://www.w3.org/2000/svg" + assert_equals(document.createElementNS(HTMLNS, "I").nodeName, "I") + assert_equals(document.createElementNS(HTMLNS, "i").nodeName, "i") + assert_equals(document.createElementNS(SVGNS, "svg").nodeName, "svg") + assert_equals(document.createElementNS(SVGNS, "SVG").nodeName, "SVG") + assert_equals(document.createElementNS(HTMLNS, "x:b").nodeName, "x:b") +}, "For Element nodes, nodeName should return the same as tagName.") +test(function() { + assert_equals(document.createTextNode("foo").nodeName, "#text") +}, "For Text nodes, nodeName should return \"#text\".") +test(function() { + assert_equals(document.createProcessingInstruction("foo", "bar").nodeName, + "foo") +}, "For ProcessingInstruction nodes, nodeName should return the target.") +test(function() { + assert_equals(document.createComment("foo").nodeName, "#comment") +}, "For Comment nodes, nodeName should return \"#comment\".") +test(function() { + assert_equals(document.nodeName, "#document") +}, "For Document nodes, nodeName should return \"#document\".") +test(function() { + assert_equals(document.doctype.nodeName, "html") +}, "For DocumentType nodes, nodeName should return the name.") +test(function() { + assert_equals(document.createDocumentFragment().nodeName, + "#document-fragment") +}, "For DocumentFragment nodes, nodeName should return \"#document-fragment\".") +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Node-nodeName.html b/testing/web-platform/tests/dom/nodes/Node-nodeName.html new file mode 100644 index 0000000000..911f93455c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-nodeName.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>Node.nodeName</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var HTMLNS = "http://www.w3.org/1999/xhtml", + SVGNS = "http://www.w3.org/2000/svg" + assert_equals(document.createElementNS(HTMLNS, "I").nodeName, "I") + assert_equals(document.createElementNS(HTMLNS, "i").nodeName, "I") + assert_equals(document.createElementNS(SVGNS, "svg").nodeName, "svg") + assert_equals(document.createElementNS(SVGNS, "SVG").nodeName, "SVG") + assert_equals(document.createElementNS(HTMLNS, "x:b").nodeName, "X:B") +}, "For Element nodes, nodeName should return the same as tagName.") +test(function() { + assert_equals(document.createTextNode("foo").nodeName, "#text") +}, "For Text nodes, nodeName should return \"#text\".") +test(function() { + assert_equals(document.createComment("foo").nodeName, "#comment") +}, "For Comment nodes, nodeName should return \"#comment\".") +test(function() { + assert_equals(document.nodeName, "#document") +}, "For Document nodes, nodeName should return \"#document\".") +test(function() { + assert_equals(document.doctype.nodeName, "html") +}, "For DocumentType nodes, nodeName should return the name.") +test(function() { + assert_equals(document.createDocumentFragment().nodeName, + "#document-fragment") +}, "For DocumentFragment nodes, nodeName should return \"#document-fragment\".") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-nodeValue.html b/testing/web-platform/tests/dom/nodes/Node-nodeValue.html new file mode 100644 index 0000000000..79ce80b875 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-nodeValue.html @@ -0,0 +1,71 @@ +<!doctype html> +<meta charset=utf-8> +<title>Node.nodeValue</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-node-nodevalue"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var the_text = document.createTextNode("A span!"); + assert_equals(the_text.nodeValue, "A span!"); + assert_equals(the_text.data, "A span!"); + the_text.nodeValue = "test again"; + assert_equals(the_text.nodeValue, "test again"); + assert_equals(the_text.data, "test again"); + the_text.nodeValue = null; + assert_equals(the_text.nodeValue, ""); + assert_equals(the_text.data, ""); +}, "Text.nodeValue"); + +test(function() { + var the_comment = document.createComment("A comment!"); + assert_equals(the_comment.nodeValue, "A comment!"); + assert_equals(the_comment.data, "A comment!"); + the_comment.nodeValue = "test again"; + assert_equals(the_comment.nodeValue, "test again"); + assert_equals(the_comment.data, "test again"); + the_comment.nodeValue = null; + assert_equals(the_comment.nodeValue, ""); + assert_equals(the_comment.data, ""); +}, "Comment.nodeValue"); + +test(function() { + var the_pi = document.createProcessingInstruction("pi", "A PI!"); + assert_equals(the_pi.nodeValue, "A PI!"); + assert_equals(the_pi.data, "A PI!"); + the_pi.nodeValue = "test again"; + assert_equals(the_pi.nodeValue, "test again"); + assert_equals(the_pi.data, "test again"); + the_pi.nodeValue = null; + assert_equals(the_pi.nodeValue, ""); + assert_equals(the_pi.data, ""); +}, "ProcessingInstruction.nodeValue"); + +test(function() { + var the_link = document.createElement("a"); + assert_equals(the_link.nodeValue, null); + the_link.nodeValue = "foo"; + assert_equals(the_link.nodeValue, null); +}, "Element.nodeValue"); + +test(function() { + assert_equals(document.nodeValue, null); + document.nodeValue = "foo"; + assert_equals(document.nodeValue, null); +}, "Document.nodeValue"); + +test(function() { + var the_frag = document.createDocumentFragment(); + assert_equals(the_frag.nodeValue, null); + the_frag.nodeValue = "foo"; + assert_equals(the_frag.nodeValue, null); +}, "DocumentFragment.nodeValue"); + +test(function() { + var the_doctype = document.doctype; + assert_equals(the_doctype.nodeValue, null); + the_doctype.nodeValue = "foo"; + assert_equals(the_doctype.nodeValue, null); +}, "DocumentType.nodeValue"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-normalize.html b/testing/web-platform/tests/dom/nodes/Node-normalize.html new file mode 100644 index 0000000000..4d455996e5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-normalize.html @@ -0,0 +1,83 @@ +<!DOCTYPE html> +<title>Node.normalize()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var df = document.createDocumentFragment(), + t1 = document.createTextNode("1"), + t2 = document.createTextNode("2"), + t3 = document.createTextNode("3"), + t4 = document.createTextNode("4") + df.appendChild(t1) + df.appendChild(t2) + assert_equals(df.childNodes.length, 2) + assert_equals(df.textContent, "12") + var el = document.createElement('x') + df.appendChild(el) + el.appendChild(t3) + el.appendChild(t4) + document.normalize() + assert_equals(el.childNodes.length, 2) + assert_equals(el.textContent, "34") + assert_equals(df.childNodes.length, 3) + assert_equals(t1.data, "1") + df.normalize() + assert_equals(df.childNodes.length, 2) + assert_equals(df.firstChild, t1) + assert_equals(t1.data, "12") + assert_equals(t2.data, "2") + assert_equals(el.firstChild, t3) + assert_equals(t3.data, "34") + assert_equals(t4.data, "4") +}) + +// https://www.w3.org/Bugs/Public/show_bug.cgi?id=19837 +test(function() { + var div = document.createElement("div") + var t1 = div.appendChild(document.createTextNode("")) + var t2 = div.appendChild(document.createTextNode("a")) + var t3 = div.appendChild(document.createTextNode("")) + assert_array_equals(div.childNodes, [t1, t2, t3]) + div.normalize(); + assert_array_equals(div.childNodes, [t2]) +}, "Empty text nodes separated by a non-empty text node") +test(function() { + var div = document.createElement("div") + var t1 = div.appendChild(document.createTextNode("")) + var t2 = div.appendChild(document.createTextNode("")) + assert_array_equals(div.childNodes, [t1, t2]) + div.normalize(); + assert_array_equals(div.childNodes, []) +}, "Empty text nodes") + +// The specification for normalize is clear that only "exclusive Text +// nodes" are to be modified. This excludes CDATASection nodes, which +// derive from Text. Naïve implementations may fail to skip +// CDATASection nodes, or even worse, try to test textContent or +// nodeValue without taking care to check the node type. They will +// fail this test. +test(function() { + // We create an XML document so that we can create CDATASection. + // Except for the CDATASection the result should be the same for + // an HTML document. (No non-Text node should be touched.) + var doc = new DOMParser().parseFromString("<div/>", "text/xml") + var div = doc.documentElement + var t1 = div.appendChild(doc.createTextNode("a")) + // The first parameter is the "target" of the processing + // instruction, and the 2nd is the text content. + var t2 = div.appendChild(doc.createProcessingInstruction("pi", "")) + var t3 = div.appendChild(doc.createTextNode("b")) + var t4 = div.appendChild(doc.createCDATASection("")) + var t5 = div.appendChild(doc.createTextNode("c")) + var t6 = div.appendChild(doc.createComment("")) + var t7 = div.appendChild(doc.createTextNode("d")) + var t8 = div.appendChild(doc.createElement("el")) + var t9 = div.appendChild(doc.createTextNode("e")) + var expected = [t1, t2, t3, t4, t5, t6, t7, t8, t9] + assert_array_equals(div.childNodes, expected) + div.normalize() + assert_array_equals(div.childNodes, expected) +}, "Non-text nodes with empty textContent values.") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-parentElement.html b/testing/web-platform/tests/dom/nodes/Node-parentElement.html new file mode 100644 index 0000000000..bc564bee0e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-parentElement.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<title>Node.parentElement</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + assert_equals(document.parentElement, null) +}, "When the parent is null, parentElement should be null") +test(function() { + assert_equals(document.doctype.parentElement, null) +}, "When the parent is a document, parentElement should be null (doctype)") +test(function() { + assert_equals(document.documentElement.parentElement, null) +}, "When the parent is a document, parentElement should be null (element)") +test(function() { + var comment = document.appendChild(document.createComment("foo")) + assert_equals(comment.parentElement, null) +}, "When the parent is a document, parentElement should be null (comment)") +test(function() { + var df = document.createDocumentFragment() + assert_equals(df.parentElement, null) + var el = document.createElement("div") + assert_equals(el.parentElement, null) + df.appendChild(el) + assert_equals(el.parentNode, df) + assert_equals(el.parentElement, null) +}, "parentElement should return null for children of DocumentFragments (element)") +test(function() { + var df = document.createDocumentFragment() + assert_equals(df.parentElement, null) + var text = document.createTextNode("bar") + assert_equals(text.parentElement, null) + df.appendChild(text) + assert_equals(text.parentNode, df) + assert_equals(text.parentElement, null) +}, "parentElement should return null for children of DocumentFragments (text)") +test(function() { + var df = document.createDocumentFragment() + var parent = document.createElement("div") + df.appendChild(parent) + var el = document.createElement("div") + assert_equals(el.parentElement, null) + parent.appendChild(el) + assert_equals(el.parentElement, parent) +}, "parentElement should work correctly with DocumentFragments (element)") +test(function() { + var df = document.createDocumentFragment() + var parent = document.createElement("div") + df.appendChild(parent) + var text = document.createTextNode("bar") + assert_equals(text.parentElement, null) + parent.appendChild(text) + assert_equals(text.parentElement, parent) +}, "parentElement should work correctly with DocumentFragments (text)") +test(function() { + var parent = document.createElement("div") + var el = document.createElement("div") + assert_equals(el.parentElement, null) + parent.appendChild(el) + assert_equals(el.parentElement, parent) +}, "parentElement should work correctly in disconnected subtrees (element)") +test(function() { + var parent = document.createElement("div") + var text = document.createTextNode("bar") + assert_equals(text.parentElement, null) + parent.appendChild(text) + assert_equals(text.parentElement, parent) +}, "parentElement should work correctly in disconnected subtrees (text)") +test(function() { + var el = document.createElement("div") + assert_equals(el.parentElement, null) + document.body.appendChild(el) + assert_equals(el.parentElement, document.body) +}, "parentElement should work correctly in a document (element)") +test(function() { + var text = document.createElement("div") + assert_equals(text.parentElement, null) + document.body.appendChild(text) + assert_equals(text.parentElement, document.body) +}, "parentElement should work correctly in a document (text)") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-parentNode-iframe.html b/testing/web-platform/tests/dom/nodes/Node-parentNode-iframe.html new file mode 100644 index 0000000000..88bc5ab436 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-parentNode-iframe.html @@ -0,0 +1 @@ +<a name='c'>c</a>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/Node-parentNode.html b/testing/web-platform/tests/dom/nodes/Node-parentNode.html new file mode 100644 index 0000000000..cff6178627 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-parentNode.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<title>Node.parentNode</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +// XXX need to test for more node types +test(function() { + assert_equals(document.parentNode, null) +}, "Document") +test(function() { + assert_equals(document.doctype.parentNode, document) +}, "Doctype") +test(function() { + assert_equals(document.documentElement.parentNode, document) +}, "Root element") +test(function() { + var el = document.createElement("div") + assert_equals(el.parentNode, null) + document.body.appendChild(el) + assert_equals(el.parentNode, document.body) +}, "Element") +var t = async_test("Removed iframe"); +function testIframe(iframe) { + t.step(function() { + var doc = iframe.contentDocument; + iframe.parentNode.removeChild(iframe); + assert_equals(doc.firstChild.parentNode, doc); + }); + t.done(); +} +</script> +<iframe id=a src="Node-parentNode-iframe.html" onload="testIframe(this)"></iframe> diff --git a/testing/web-platform/tests/dom/nodes/Node-properties.html b/testing/web-platform/tests/dom/nodes/Node-properties.html new file mode 100644 index 0000000000..10f92e7d7e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-properties.html @@ -0,0 +1,688 @@ +<!doctype html> +<title>Node assorted property tests</title> +<link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> +<meta charset=utf-8> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; +/** + * First we define a data structure to tell us what tests to run. The keys + * will be eval()ed, and are mostly global variables defined in common.js. The + * values are objects, which maps properties to expected values. So + * + * foo: { + * bar: "baz", + * quz: 7, + * }, + * + * will test that eval("foo.bar") === "baz" and eval("foo.quz") === 7. "foo" + * and "bar" could thus be expressions, like "document.documentElement" and + * "childNodes[4]" respectively. + * + * To avoid repetition, some values are automatically added based on others. + * For instance, if we specify nodeType: Node.TEXT_NODE, we'll automatically + * also test nodeName: "#text". This is handled by code after this variable is + * defined. + */ +var expected = { + testDiv: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: document.body, + parentElement: document.body, + "childNodes.length": 6, + "childNodes[0]": paras[0], + "childNodes[1]": paras[1], + "childNodes[2]": paras[2], + "childNodes[3]": paras[3], + "childNodes[4]": paras[4], + "childNodes[5]": comment, + previousSibling: null, + nextSibling: document.getElementById("log"), + textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\nIjklmnop\nQrstuvwxYzabcdefGhijklmn", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "div", + tagName: "DIV", + id: "test", + "children[0]": paras[0], + "children[1]": paras[1], + "children[2]": paras[2], + "children[3]": paras[3], + "children[4]": paras[4], + previousElementSibling: null, + // nextSibling isn't explicitly set + //nextElementSibling: , + childElementCount: 5, + }, + detachedDiv: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: null, + parentElement: null, + "childNodes.length": 2, + "childNodes[0]": detachedPara1, + "childNodes[1]": detachedPara2, + previousSibling: null, + nextSibling: null, + textContent: "OpqrstuvWxyzabcd", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "div", + tagName: "DIV", + "children[0]": detachedPara1, + "children[1]": detachedPara2, + previousElementSibling: null, + nextElementSibling: null, + childElementCount: 2, + }, + detachedPara1: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: detachedDiv, + parentElement: detachedDiv, + "childNodes.length": 1, + previousSibling: null, + nextSibling: detachedPara2, + textContent: "Opqrstuv", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + previousElementSibling: null, + nextElementSibling: detachedPara2, + childElementCount: 0, + }, + detachedPara2: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: detachedDiv, + parentElement: detachedDiv, + "childNodes.length": 1, + previousSibling: detachedPara1, + nextSibling: null, + textContent: "Wxyzabcd", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + previousElementSibling: detachedPara1, + nextElementSibling: null, + childElementCount: 0, + }, + document: { + // Node + nodeType: Node.DOCUMENT_NODE, + "childNodes.length": 2, + "childNodes[0]": document.doctype, + "childNodes[1]": document.documentElement, + + // Document + URL: String(location), + compatMode: "CSS1Compat", + characterSet: "UTF-8", + contentType: "text/html", + doctype: doctype, + //documentElement: , + }, + foreignDoc: { + // Node + nodeType: Node.DOCUMENT_NODE, + "childNodes.length": 3, + "childNodes[0]": foreignDoc.doctype, + "childNodes[1]": foreignDoc.documentElement, + "childNodes[2]": foreignComment, + + // Document + URL: "about:blank", + compatMode: "CSS1Compat", + characterSet: "UTF-8", + contentType: "text/html", + //doctype: , + //documentElement: , + }, + foreignPara1: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: foreignDoc, + parentNode: foreignDoc.body, + parentElement: foreignDoc.body, + "childNodes.length": 1, + previousSibling: null, + nextSibling: foreignPara2, + textContent: "Efghijkl", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + previousElementSibling: null, + nextElementSibling: foreignPara2, + childElementCount: 0, + }, + foreignPara2: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: foreignDoc, + parentNode: foreignDoc.body, + parentElement: foreignDoc.body, + "childNodes.length": 1, + previousSibling: foreignPara1, + nextSibling: foreignTextNode, + textContent: "Mnopqrst", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + previousElementSibling: foreignPara1, + nextElementSibling: null, + childElementCount: 0, + }, + xmlDoc: { + // Node + nodeType: Node.DOCUMENT_NODE, + "childNodes.length": 4, + "childNodes[0]": xmlDoctype, + "childNodes[1]": xmlElement, + "childNodes[2]": processingInstruction, + "childNodes[3]": xmlComment, + + // Document + URL: "about:blank", + compatMode: "CSS1Compat", + characterSet: "UTF-8", + contentType: "application/xml", + //doctype: , + //documentElement: , + }, + xmlElement: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: xmlDoc, + parentNode: xmlDoc, + parentElement: null, + "childNodes.length": 1, + "childNodes[0]": xmlTextNode, + previousSibling: xmlDoctype, + nextSibling: processingInstruction, + textContent: "do re mi fa so la ti", + + // Element + namespaceURI: null, + prefix: null, + localName: "igiveuponcreativenames", + tagName: "igiveuponcreativenames", + previousElementSibling: null, + nextElementSibling: null, + childElementCount: 0, + }, + detachedXmlElement: { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: xmlDoc, + parentNode: null, + parentElement: null, + "childNodes.length": 0, + previousSibling: null, + nextSibling: null, + textContent: "", + + // Element + namespaceURI: null, + prefix: null, + localName: "everyone-hates-hyphenated-element-names", + tagName: "everyone-hates-hyphenated-element-names", + previousElementSibling: null, + nextElementSibling: null, + childElementCount: 0, + }, + detachedTextNode: { + // Node + nodeType: Node.TEXT_NODE, + ownerDocument: document, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "Uvwxyzab", + + // Text + wholeText: "Uvwxyzab", + }, + foreignTextNode: { + // Node + nodeType: Node.TEXT_NODE, + ownerDocument: foreignDoc, + parentNode: foreignDoc.body, + parentElement: foreignDoc.body, + previousSibling: foreignPara2, + nextSibling: null, + nodeValue: "I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.", + + // Text + wholeText: "I admit that I harbor doubts about whether we really need so many things to test, but it's too late to stop now.", + }, + detachedForeignTextNode: { + // Node + nodeType: Node.TEXT_NODE, + ownerDocument: foreignDoc, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "Cdefghij", + + // Text + wholeText: "Cdefghij", + }, + xmlTextNode: { + // Node + nodeType: Node.TEXT_NODE, + ownerDocument: xmlDoc, + parentNode: xmlElement, + parentElement: xmlElement, + previousSibling: null, + nextSibling: null, + nodeValue: "do re mi fa so la ti", + + // Text + wholeText: "do re mi fa so la ti", + }, + detachedXmlTextNode: { + // Node + nodeType: Node.TEXT_NODE, + ownerDocument: xmlDoc, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "Klmnopqr", + + // Text + wholeText: "Klmnopqr", + }, + processingInstruction: { + // Node + nodeType: Node.PROCESSING_INSTRUCTION_NODE, + ownerDocument: xmlDoc, + parentNode: xmlDoc, + parentElement: null, + previousSibling: xmlElement, + nextSibling: xmlComment, + nodeValue: 'Did you know that ":syn sync fromstart" is very useful when using vim to edit large amounts of JavaScript embedded in HTML?', + + // ProcessingInstruction + target: "somePI", + }, + detachedProcessingInstruction: { + // Node + nodeType: Node.PROCESSING_INSTRUCTION_NODE, + ownerDocument: xmlDoc, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "chirp chirp chirp", + + // ProcessingInstruction + target: "whippoorwill", + }, + comment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + previousSibling: paras[4], + nextSibling: null, + nodeValue: "Alphabet soup?", + }, + detachedComment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: document, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "Stuvwxyz", + }, + foreignComment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: foreignDoc, + parentNode: foreignDoc, + parentElement: null, + previousSibling: foreignDoc.documentElement, + nextSibling: null, + nodeValue: '"Commenter" and "commentator" mean different things. I\'ve seen non-native speakers trip up on this.', + }, + detachedForeignComment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: foreignDoc, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "אריה יהודה", + }, + xmlComment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: xmlDoc, + parentNode: xmlDoc, + parentElement: null, + previousSibling: processingInstruction, + nextSibling: null, + nodeValue: "I maliciously created a comment that will break incautious XML serializers, but Firefox threw an exception, so all I got was this lousy T-shirt", + }, + detachedXmlComment: { + // Node + nodeType: Node.COMMENT_NODE, + ownerDocument: xmlDoc, + parentNode: null, + parentElement: null, + previousSibling: null, + nextSibling: null, + nodeValue: "בן חיים אליעזר", + }, + docfrag: { + // Node + nodeType: Node.DOCUMENT_FRAGMENT_NODE, + ownerDocument: document, + "childNodes.length": 0, + textContent: "", + }, + foreignDocfrag: { + // Node + nodeType: Node.DOCUMENT_FRAGMENT_NODE, + ownerDocument: foreignDoc, + "childNodes.length": 0, + textContent: "", + }, + xmlDocfrag: { + // Node + nodeType: Node.DOCUMENT_FRAGMENT_NODE, + ownerDocument: xmlDoc, + "childNodes.length": 0, + textContent: "", + }, + doctype: { + // Node + nodeType: Node.DOCUMENT_TYPE_NODE, + ownerDocument: document, + parentNode: document, + previousSibling: null, + nextSibling: document.documentElement, + + // DocumentType + name: "html", + publicId: "", + systemId: "", + }, + foreignDoctype: { + // Node + nodeType: Node.DOCUMENT_TYPE_NODE, + ownerDocument: foreignDoc, + parentNode: foreignDoc, + previousSibling: null, + nextSibling: foreignDoc.documentElement, + + // DocumentType + name: "html", + publicId: "", + systemId: "", + }, + xmlDoctype: { + // Node + nodeType: Node.DOCUMENT_TYPE_NODE, + ownerDocument: xmlDoc, + parentNode: xmlDoc, + previousSibling: null, + nextSibling: xmlElement, + + // DocumentType + name: "qorflesnorf", + publicId: "abcde", + systemId: "x\"'y", + }, + "paras[0]": { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + "childNodes.length": 1, + previousSibling: null, + nextSibling: paras[1], + textContent: "A\u0308b\u0308c\u0308d\u0308e\u0308f\u0308g\u0308h\u0308\n", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + id: "a", + previousElementSibling: null, + nextElementSibling: paras[1], + childElementCount: 0, + }, + "paras[1]": { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + "childNodes.length": 1, + previousSibling: paras[0], + nextSibling: paras[2], + textContent: "Ijklmnop\n", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + id: "b", + previousElementSibling: paras[0], + nextElementSibling: paras[2], + childElementCount: 0, + }, + "paras[2]": { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + "childNodes.length": 1, + previousSibling: paras[1], + nextSibling: paras[3], + textContent: "Qrstuvwx", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + id: "c", + previousElementSibling: paras[1], + nextElementSibling: paras[3], + childElementCount: 0, + }, + "paras[3]": { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + "childNodes.length": 1, + previousSibling: paras[2], + nextSibling: paras[4], + textContent: "Yzabcdef", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + id: "d", + previousElementSibling: paras[2], + nextElementSibling: paras[4], + childElementCount: 0, + }, + "paras[4]": { + // Node + nodeType: Node.ELEMENT_NODE, + ownerDocument: document, + parentNode: testDiv, + parentElement: testDiv, + "childNodes.length": 1, + previousSibling: paras[3], + nextSibling: comment, + textContent: "Ghijklmn", + + // Element + namespaceURI: "http://www.w3.org/1999/xhtml", + prefix: null, + localName: "p", + tagName: "P", + id: "e", + previousElementSibling: paras[3], + nextElementSibling: null, + childElementCount: 0, + }, +}; + +for (var node in expected) { + // Now we set various default values by node type. + switch (expected[node].nodeType) { + case Node.ELEMENT_NODE: + expected[node].nodeName = expected[node].tagName; + expected[node].nodeValue = null; + expected[node]["children.length"] = expected[node].childElementCount; + + if (expected[node].id === undefined) { + expected[node].id = ""; + } + if (expected[node].className === undefined) { + expected[node].className = ""; + } + + var len = expected[node].childElementCount; + if (len === 0) { + expected[node].firstElementChild = + expected[node].lastElementChild = null; + } else { + // If we have expectations for the first/last child in children, + // use those. Otherwise, at least check that .firstElementChild == + // .children[0] and .lastElementChild == .children[len - 1], even + // if we aren't sure what they should be. + expected[node].firstElementChild = expected[node]["children[0]"] + ? expected[node]["children[0]"] + : eval(node).children[0]; + expected[node].lastElementChild = + expected[node]["children[" + (len - 1) + "]"] + ? expected[node]["children[" + (len - 1) + "]"] + : eval(node).children[len - 1]; + } + break; + + case Node.TEXT_NODE: + expected[node].nodeName = "#text"; + expected[node]["childNodes.length"] = 0; + expected[node].textContent = expected[node].data = + expected[node].nodeValue; + expected[node].length = expected[node].nodeValue.length; + break; + + case Node.PROCESSING_INSTRUCTION_NODE: + expected[node].nodeName = expected[node].target; + expected[node]["childNodes.length"] = 0; + expected[node].textContent = expected[node].data = + expected[node].nodeValue; + expected[node].length = expected[node].nodeValue.length; + break; + + case Node.COMMENT_NODE: + expected[node].nodeName = "#comment"; + expected[node]["childNodes.length"] = 0; + expected[node].textContent = expected[node].data = + expected[node].nodeValue; + expected[node].length = expected[node].nodeValue.length; + break; + + case Node.DOCUMENT_NODE: + expected[node].nodeName = "#document"; + expected[node].ownerDocument = expected[node].parentNode = + expected[node].parentElement = expected[node].previousSibling = + expected[node].nextSibling = expected[node].nodeValue = + expected[node].textContent = null; + expected[node].documentURI = expected[node].URL; + expected[node].charset = expected[node].inputEncoding = + expected[node].characterSet; + break; + + case Node.DOCUMENT_TYPE_NODE: + expected[node].nodeName = expected[node].name; + expected[node]["childNodes.length"] = 0; + expected[node].parentElement = expected[node].nodeValue = + expected[node].textContent = null; + break; + + case Node.DOCUMENT_FRAGMENT_NODE: + expected[node].nodeName = "#document-fragment"; + expected[node].parentNode = expected[node].parentElement = + expected[node].previousSibling = expected[node].nextSibling = + expected[node].nodeValue = null; + break; + } + + // Now we set some further default values that are independent of node + // type. + var len = expected[node]["childNodes.length"]; + if (len === 0) { + expected[node].firstChild = expected[node].lastChild = null; + } else { + // If we have expectations for the first/last child in childNodes, use + // those. Otherwise, at least check that .firstChild == .childNodes[0] + // and .lastChild == .childNodes[len - 1], even if we aren't sure what + // they should be. + expected[node].firstChild = expected[node]["childNodes[0]"] + ? expected[node]["childNodes[0]"] + : eval(node).childNodes[0]; + expected[node].lastChild = + expected[node]["childNodes[" + (len - 1) + "]"] + ? expected[node]["childNodes[" + (len - 1) + "]"] + : eval(node).childNodes[len - 1]; + } + expected[node]["hasChildNodes()"] = !!expected[node]["childNodes.length"]; + + // Finally, we test! + for (var prop in expected[node]) { + test(function() { + assert_equals(eval(node + "." + prop), expected[node][prop]); + }, node + "." + prop); + } +} + +testDiv.parentNode.removeChild(testDiv); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-removeChild.html b/testing/web-platform/tests/dom/nodes/Node-removeChild.html new file mode 100644 index 0000000000..6158423359 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-removeChild.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<title>Node.removeChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="creators.js"></script> +<div id="log"></div> +<iframe src=about:blank></iframe> +<script> +var documents = [ + [function() { return document }, "the main document"], + [function() { return frames[0].document }, "a frame document"], + [function() { return document.implementation.createHTMLDocument() }, + "a synthetic document"], +]; + +documents.forEach(function(d) { + var get = d[0], description = d[1] + for (var p in creators) { + var creator = creators[p]; + test(function() { + var doc = get(); + var s = doc[creator]("a") + assert_equals(s.ownerDocument, doc) + assert_throws_dom("NOT_FOUND_ERR", function() { document.body.removeChild(s) }) + assert_equals(s.ownerDocument, doc) + }, "Passing a detached " + p + " from " + description + + " to removeChild should not affect it.") + + test(function() { + var doc = get(); + var s = doc[creator]("b") + doc.documentElement.appendChild(s) + assert_equals(s.ownerDocument, doc) + assert_throws_dom("NOT_FOUND_ERR", function() { document.body.removeChild(s) }) + assert_equals(s.ownerDocument, doc) + }, "Passing a non-detached " + p + " from " + description + + " to removeChild should not affect it.") + + test(function() { + var doc = get(); + var s = doc[creator]("test") + doc.body.appendChild(s) + assert_equals(s.ownerDocument, doc) + assert_throws_dom( + "NOT_FOUND_ERR", + (doc.defaultView || self).DOMException, + function() { s.removeChild(doc) } + ); + }, "Calling removeChild on a " + p + " from " + description + + " with no children should throw NOT_FOUND_ERR.") + } +}); + +test(function() { + assert_throws_js(TypeError, function() { document.body.removeChild(null) }) + assert_throws_js(TypeError, function() { document.body.removeChild({'a':'b'}) }) +}, "Passing a value that is not a Node reference to removeChild should throw TypeError.") +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-replaceChild.html b/testing/web-platform/tests/dom/nodes/Node-replaceChild.html new file mode 100644 index 0000000000..74aac67d43 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-replaceChild.html @@ -0,0 +1,349 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.replaceChild</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body><a><b></b><c></c></a> +<div id="log"></div> +<!-- First test shared pre-insertion checks that work similarly for replaceChild + and insertBefore --> +<script> + var insertFunc = Node.prototype.replaceChild; +</script> +<script src="pre-insertion-validation-notfound.js"></script> +<script> +// IDL. +test(function() { + var a = document.createElement("div"); + assert_throws_js(TypeError, function() { + a.replaceChild(null, null); + }); + + var b = document.createElement("div"); + assert_throws_js(TypeError, function() { + a.replaceChild(b, null); + }); + assert_throws_js(TypeError, function() { + a.replaceChild(null, b); + }); +}, "Passing null to replaceChild should throw a TypeError.") + +// Step 3. +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + assert_throws_dom("NotFoundError", function() { + a.replaceChild(b, c); + }); + + var d = document.createElement("div"); + d.appendChild(b); + assert_throws_dom("NotFoundError", function() { + a.replaceChild(b, c); + }); + assert_throws_dom("NotFoundError", function() { + a.replaceChild(b, a); + }); +}, "If child's parent is not the context node, a NotFoundError exception should be thrown"); + +// Step 1. +test(function() { + var nodes = getNonParentNodes(); + + var a = document.createElement("div"); + var b = document.createElement("div"); + nodes.forEach(function(node) { + assert_throws_dom("HierarchyRequestError", function() { + node.replaceChild(a, b); + }); + }); +}, "If the context node is not a node that can contain children, a HierarchyRequestError exception should be thrown") + +// Step 2. +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + + assert_throws_dom("HierarchyRequestError", function() { + a.replaceChild(a, a); + }); + + a.appendChild(b); + assert_throws_dom("HierarchyRequestError", function() { + a.replaceChild(a, b); + }); + + var c = document.createElement("div"); + c.appendChild(a); + assert_throws_dom("HierarchyRequestError", function() { + a.replaceChild(c, b); + }); +}, "If node is an inclusive ancestor of the context node, a HierarchyRequestError should be thrown.") + +// Steps 4/5. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var doc2 = document.implementation.createHTMLDocument("title2"); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(doc2, doc.documentElement); + }); + + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(doc.createTextNode("text"), doc.documentElement); + }); +}, "If the context node is a document, inserting a document or text node should throw a HierarchyRequestError.") + +// Step 6.1. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + df.appendChild(doc.createElement("b")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, doc.documentElement); + }); + + df = doc.createDocumentFragment(); + df.appendChild(doc.createTextNode("text")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, doc.documentElement); + }); + + df = doc.createDocumentFragment(); + df.appendChild(doc.createComment("comment")); + df.appendChild(doc.createTextNode("text")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, doc.documentElement); + }); +}, "If the context node is a document, inserting a DocumentFragment that contains a text node or too many elements should throw a HierarchyRequestError.") +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + doc.removeChild(doc.documentElement); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + df.appendChild(doc.createElement("b")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, doc.doctype); + }); +}, "If the context node is a document (without element children), inserting a DocumentFragment that contains multiple elements should throw a HierarchyRequestError.") + +// Step 6.1. +test(function() { + // The context node has an element child that is not /child/. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, doc.doctype); + }); +}, "If the context node is a document, inserting a DocumentFragment with an element if there already is an element child should throw a HierarchyRequestError.") +test(function() { + // A doctype is following /child/. + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(df, comment); + }); +}, "If the context node is a document, inserting a DocumentFragment with an element before the doctype should throw a HierarchyRequestError.") + +// Step 6.2. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + assert_array_equals(doc.childNodes, [doc.doctype, doc.documentElement, comment]); + + var a = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(a, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(a, doc.doctype); + }); +}, "If the context node is a document, inserting an element if there already is an element child should throw a HierarchyRequestError.") +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + doc.removeChild(doc.documentElement); + assert_array_equals(doc.childNodes, [comment, doc.doctype]); + + var a = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(a, comment); + }); +}, "If the context node is a document, inserting an element before the doctype should throw a HierarchyRequestError.") + +// Step 6.3. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.insertBefore(doc.createComment("foo"), doc.firstChild); + assert_array_equals(doc.childNodes, [comment, doc.doctype, doc.documentElement]); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(doctype, comment); + }); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(doctype, doc.documentElement); + }); +}, "If the context node is a document, inserting a doctype if there already is a doctype child should throw a HierarchyRequestError.") +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var comment = doc.appendChild(doc.createComment("foo")); + doc.removeChild(doc.doctype); + assert_array_equals(doc.childNodes, [doc.documentElement, comment]); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + doc.replaceChild(doctype, comment); + }); +}, "If the context node is a document, inserting a doctype after the document element should throw a HierarchyRequestError.") + +// Steps 4/5. +test(function() { + var df = document.createDocumentFragment(); + var a = df.appendChild(document.createElement("a")); + + var doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", function() { + df.replaceChild(doc, a); + }); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + df.replaceChild(doctype, a); + }); +}, "If the context node is a DocumentFragment, inserting a document or a doctype should throw a HierarchyRequestError.") +test(function() { + var el = document.createElement("div"); + var a = el.appendChild(document.createElement("a")); + + var doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", function() { + el.replaceChild(doc, a); + }); + + var doctype = document.implementation.createDocumentType("html", "", ""); + assert_throws_dom("HierarchyRequestError", function() { + el.replaceChild(doctype, a); + }); +}, "If the context node is an element, inserting a document or a doctype should throw a HierarchyRequestError.") + +// Step 6. +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + a.appendChild(b); + a.appendChild(c); + assert_array_equals(a.childNodes, [b, c]); + assert_equals(a.replaceChild(c, b), b); + assert_array_equals(a.childNodes, [c]); +}, "Replacing a node with its next sibling should work (2 children)"); +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + var d = document.createElement("div"); + var e = document.createElement("div"); + a.appendChild(b); + a.appendChild(c); + a.appendChild(d); + a.appendChild(e); + assert_array_equals(a.childNodes, [b, c, d, e]); + assert_equals(a.replaceChild(d, c), c); + assert_array_equals(a.childNodes, [b, d, e]); +}, "Replacing a node with its next sibling should work (4 children)"); +test(function() { + var a = document.createElement("div"); + var b = document.createElement("div"); + var c = document.createElement("div"); + a.appendChild(b); + a.appendChild(c); + assert_array_equals(a.childNodes, [b, c]); + assert_equals(a.replaceChild(b, b), b); + assert_array_equals(a.childNodes, [b, c]); + assert_equals(a.replaceChild(c, c), c); + assert_array_equals(a.childNodes, [b, c]); +}, "Replacing a node with itself should not move the node"); + +// Step 7. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var doctype = doc.doctype; + assert_array_equals(doc.childNodes, [doctype, doc.documentElement]); + + var doc2 = document.implementation.createHTMLDocument("title2"); + var doctype2 = doc2.doctype; + assert_array_equals(doc2.childNodes, [doctype2, doc2.documentElement]); + + doc.replaceChild(doc2.doctype, doc.doctype); + assert_array_equals(doc.childNodes, [doctype2, doc.documentElement]); + assert_array_equals(doc2.childNodes, [doc2.documentElement]); + assert_equals(doctype.parentNode, null); + assert_equals(doctype.ownerDocument, doc); + assert_equals(doctype2.parentNode, doc); + assert_equals(doctype2.ownerDocument, doc); +}, "If the context node is a document, inserting a new doctype should work.") + +// Bugs. +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var df = doc.createDocumentFragment(); + var a = df.appendChild(doc.createElement("a")); + assert_equals(doc.documentElement, doc.replaceChild(df, doc.documentElement)); + assert_array_equals(doc.childNodes, [doc.doctype, a]); +}, "Replacing the document element with a DocumentFragment containing a single element should work."); +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var df = doc.createDocumentFragment(); + var a = df.appendChild(doc.createComment("a")); + var b = df.appendChild(doc.createElement("b")); + var c = df.appendChild(doc.createComment("c")); + assert_equals(doc.documentElement, doc.replaceChild(df, doc.documentElement)); + assert_array_equals(doc.childNodes, [doc.doctype, a, b, c]); +}, "Replacing the document element with a DocumentFragment containing a single element and comments should work."); +test(function() { + var doc = document.implementation.createHTMLDocument("title"); + var a = doc.createElement("a"); + assert_equals(doc.documentElement, doc.replaceChild(a, doc.documentElement)); + assert_array_equals(doc.childNodes, [doc.doctype, a]); +}, "Replacing the document element with a single element should work."); +test(function() { + document.addEventListener("DOMNodeRemoved", function(e) { + document.body.appendChild(document.createElement("x")); + }, false); + var a = document.body.firstChild, b = a.firstChild, c = b.nextSibling; + assert_equals(a.replaceChild(c, b), b); + assert_equals(b.parentNode, null); + assert_equals(a.firstChild, c); + assert_equals(c.parentNode, a); +}, "replaceChild should work in the presence of mutation events.") +test(function() { + var TEST_ID = "findme"; + var gBody = document.getElementsByTagName("body")[0]; + var parent = document.createElement("div"); + gBody.appendChild(parent); + var child = document.createElement("div"); + parent.appendChild(child); + var df = document.createDocumentFragment(); + var fragChild = df.appendChild(document.createElement("div")); + fragChild.setAttribute("id", TEST_ID); + parent.replaceChild(df, child); + assert_equals(document.getElementById(TEST_ID), fragChild, "should not be null"); +}, "Replacing an element with a DocumentFragment should allow a child of the DocumentFragment to be found by Id.") + +</script> diff --git a/testing/web-platform/tests/dom/nodes/Node-textContent.html b/testing/web-platform/tests/dom/nodes/Node-textContent.html new file mode 100644 index 0000000000..cf2e072087 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Node-textContent.html @@ -0,0 +1,265 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node.textContent</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +// XXX mutation observers? +// XXX Range gravitation? + +var documents, doctypes; +setup(function() { + documents = [ + [document, "parser"], + [document.implementation.createDocument("", "test", null), "createDocument"], + [document.implementation.createHTMLDocument("title"), "createHTMLDocument"], + ] + doctypes = [ + [document.doctype, "parser"], + [document.implementation.createDocumentType("x", "", ""), "script"], + ] +}) + +// Getting +// DocumentFragment, Element: +test(function() { + var element = document.createElement("div") + assert_equals(element.textContent, "") +}, "For an empty Element, textContent should be the empty string") + +test(function() { + assert_equals(document.createDocumentFragment().textContent, "") +}, "For an empty DocumentFragment, textContent should be the empty string") + +test(function() { + var el = document.createElement("div") + el.appendChild(document.createComment(" abc ")) + el.appendChild(document.createTextNode("\tDEF\t")) + el.appendChild(document.createProcessingInstruction("x", " ghi ")) + assert_equals(el.textContent, "\tDEF\t") +}, "Element with children") + +test(function() { + var el = document.createElement("div") + var child = document.createElement("div") + el.appendChild(child) + child.appendChild(document.createComment(" abc ")) + child.appendChild(document.createTextNode("\tDEF\t")) + child.appendChild(document.createProcessingInstruction("x", " ghi ")) + assert_equals(el.textContent, "\tDEF\t") +}, "Element with descendants") + +test(function() { + var df = document.createDocumentFragment() + df.appendChild(document.createComment(" abc ")) + df.appendChild(document.createTextNode("\tDEF\t")) + df.appendChild(document.createProcessingInstruction("x", " ghi ")) + assert_equals(df.textContent, "\tDEF\t") +}, "DocumentFragment with children") + +test(function() { + var df = document.createDocumentFragment() + var child = document.createElement("div") + df.appendChild(child) + child.appendChild(document.createComment(" abc ")) + child.appendChild(document.createTextNode("\tDEF\t")) + child.appendChild(document.createProcessingInstruction("x", " ghi ")) + assert_equals(df.textContent, "\tDEF\t") +}, "DocumentFragment with descendants") + +// Text, ProcessingInstruction, Comment: +test(function() { + assert_equals(document.createTextNode("").textContent, "") +}, "For an empty Text, textContent should be the empty string") + +test(function() { + assert_equals(document.createProcessingInstruction("x", "").textContent, "") +}, "For an empty ProcessingInstruction, textContent should be the empty string") + +test(function() { + assert_equals(document.createComment("").textContent, "") +}, "For an empty Comment, textContent should be the empty string") + +test(function() { + assert_equals(document.createTextNode("abc").textContent, "abc") +}, "For a Text with data, textContent should be that data") + +test(function() { + assert_equals(document.createProcessingInstruction("x", "abc").textContent, + "abc") +}, "For a ProcessingInstruction with data, textContent should be that data") + +test(function() { + assert_equals(document.createComment("abc").textContent, "abc") +}, "For a Comment with data, textContent should be that data") + +// Any other node: +documents.forEach(function(argument) { + var doc = argument[0], creator = argument[1] + test(function() { + assert_equals(doc.textContent, null) + }, "For Documents created by " + creator + ", textContent should be null") +}) + +doctypes.forEach(function(argument) { + var doctype = argument[0], creator = argument[1] + test(function() { + assert_equals(doctype.textContent, null) + }, "For DocumentType created by " + creator + ", textContent should be null") +}) + +// Setting +// DocumentFragment, Element: +var testArgs = [ + [null, null], + [undefined, null], + ["", null], + [42, "42"], + ["abc", "abc"], + ["<b>xyz<\/b>", "<b>xyz<\/b>"], + ["d\0e", "d\0e"] + // XXX unpaired surrogate? +] +testArgs.forEach(function(aValue) { + var argument = aValue[0], expectation = aValue[1] + var check = function(aElementOrDocumentFragment) { + if (expectation === null) { + assert_equals(aElementOrDocumentFragment.textContent, "") + assert_equals(aElementOrDocumentFragment.firstChild, null) + } else { + assert_equals(aElementOrDocumentFragment.textContent, expectation) + assert_equals(aElementOrDocumentFragment.childNodes.length, 1, + "Should have one child") + var firstChild = aElementOrDocumentFragment.firstChild + assert_true(firstChild instanceof Text, "child should be a Text") + assert_equals(firstChild.data, expectation) + } + } + + test(function() { + var el = document.createElement("div") + el.textContent = argument + check(el) + }, "Element without children set to " + format_value(argument)) + + test(function() { + var el = document.createElement("div") + var text = el.appendChild(document.createTextNode("")) + el.textContent = argument + check(el) + assert_equals(text.parentNode, null, + "Preexisting Text should have been removed") + }, "Element with empty text node as child set to " + format_value(argument)) + + test(function() { + var el = document.createElement("div") + el.appendChild(document.createComment(" abc ")) + el.appendChild(document.createTextNode("\tDEF\t")) + el.appendChild(document.createProcessingInstruction("x", " ghi ")) + el.textContent = argument + check(el) + }, "Element with children set to " + format_value(argument)) + + test(function() { + var el = document.createElement("div") + var child = document.createElement("div") + el.appendChild(child) + child.appendChild(document.createComment(" abc ")) + child.appendChild(document.createTextNode("\tDEF\t")) + child.appendChild(document.createProcessingInstruction("x", " ghi ")) + el.textContent = argument + check(el) + assert_equals(child.childNodes.length, 3, + "Should not have changed the internal structure of the removed nodes.") + }, "Element with descendants set to " + format_value(argument)) + + test(function() { + var df = document.createDocumentFragment() + df.textContent = argument + check(df) + }, "DocumentFragment without children set to " + format_value(argument)) + + test(function() { + var df = document.createDocumentFragment() + var text = df.appendChild(document.createTextNode("")) + df.textContent = argument + check(df) + assert_equals(text.parentNode, null, + "Preexisting Text should have been removed") + }, "DocumentFragment with empty text node as child set to " + format_value(argument)) + + test(function() { + var df = document.createDocumentFragment() + df.appendChild(document.createComment(" abc ")) + df.appendChild(document.createTextNode("\tDEF\t")) + df.appendChild(document.createProcessingInstruction("x", " ghi ")) + df.textContent = argument + check(df) + }, "DocumentFragment with children set to " + format_value(argument)) + + test(function() { + var df = document.createDocumentFragment() + var child = document.createElement("div") + df.appendChild(child) + child.appendChild(document.createComment(" abc ")) + child.appendChild(document.createTextNode("\tDEF\t")) + child.appendChild(document.createProcessingInstruction("x", " ghi ")) + df.textContent = argument + check(df) + assert_equals(child.childNodes.length, 3, + "Should not have changed the internal structure of the removed nodes.") + }, "DocumentFragment with descendants set to " + format_value(argument)) +}) + +// Text, ProcessingInstruction, Comment: +test(function() { + var text = document.createTextNode("abc") + text.textContent = "def" + assert_equals(text.textContent, "def") + assert_equals(text.data, "def") +}, "For a Text, textContent should set the data") + +test(function() { + var pi = document.createProcessingInstruction("x", "abc") + pi.textContent = "def" + assert_equals(pi.textContent, "def") + assert_equals(pi.data, "def") + assert_equals(pi.target, "x") +}, "For a ProcessingInstruction, textContent should set the data") + +test(function() { + var comment = document.createComment("abc") + comment.textContent = "def" + assert_equals(comment.textContent, "def") + assert_equals(comment.data, "def") +}, "For a Comment, textContent should set the data") + +// Any other node: +documents.forEach(function(argument) { + var doc = argument[0], creator = argument[1] + test(function() { + var root = doc.documentElement + doc.textContent = "a" + assert_equals(doc.textContent, null) + assert_equals(doc.documentElement, root) + }, "For Documents created by " + creator + ", setting textContent should do nothing") +}) + +doctypes.forEach(function(argument) { + var doctype = argument[0], creator = argument[1] + test(function() { + var props = { + name: doctype.name, + publicId: doctype.publicId, + systemId: doctype.systemId, + } + doctype.textContent = "b" + assert_equals(doctype.textContent, null) + assert_equals(doctype.name, props.name, "name should not change") + assert_equals(doctype.publicId, props.publicId, "publicId should not change") + assert_equals(doctype.systemId, props.systemId, "systemId should not change") + }, "For DocumentType created by " + creator + ", setting textContent should do nothing") +}) + +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-Iterable.html b/testing/web-platform/tests/dom/nodes/NodeList-Iterable.html new file mode 100644 index 0000000000..fcbee175cb --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-Iterable.html @@ -0,0 +1,61 @@ +<!doctype html> +<meta charset="utf-8"> +<title>NodeList Iterable Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + <p id="1"></p> + <p id="2"></p> + <p id="3"></p> + <p id="4"></p> + <p id="5"></p> + + <div id="live"><b id="b1">1</b><b id="b2">2</b><b id="b3">3</b></div> +<script> + var paragraphs; + setup(function() { + paragraphs = document.querySelectorAll('p'); + }) + test(function() { + assert_true('length' in paragraphs); + }, 'NodeList has length method.'); + test(function() { + assert_true('values' in paragraphs); + }, 'NodeList has values method.'); + test(function() { + assert_true('entries' in paragraphs); + }, 'NodeList has entries method.'); + test(function() { + assert_true('forEach' in paragraphs); + }, 'NodeList has forEach method.'); + test(function() { + assert_true(Symbol.iterator in paragraphs); + }, 'NodeList has Symbol.iterator.'); + test(function() { + var ids = "12345", idx=0; + for(var node of paragraphs){ + assert_equals(node.getAttribute('id'), ids[idx++]); + } + }, 'NodeList is iterable via for-of loop.'); + + test(function() { + assert_array_equals(Object.keys(paragraphs), ['0', '1', '2', '3', '4']); + }, 'NodeList responds to Object.keys correctly'); + + test(function() { + var container = document.getElementById('live'); + var nodeList = container.childNodes; + + var ids = []; + for (var el of nodeList) { + ids.push(el.id); + assert_equals(el.localName, 'b'); + if (ids.length < 3) { + var newEl = document.createElement('b'); + newEl.id = 'after' + el.id; + container.appendChild(newEl); + } + } + + assert_array_equals(ids, ['b1', 'b2', 'b3', 'afterb1', 'afterb2']); + }, 'live NodeLists are for-of iterable and update appropriately'); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-live-mutations.window.js b/testing/web-platform/tests/dom/nodes/NodeList-live-mutations.window.js new file mode 100644 index 0000000000..a11fed1e38 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-live-mutations.window.js @@ -0,0 +1,79 @@ +function testNodeList(name, hooks) { + test(() => { + const nodes = { + root: document.createElement("div"), + div1: document.createElement("div"), + div2: document.createElement("div"), + p: document.createElement("p") + }; + + const list = nodes.root.childNodes; + + hooks.initial(list, nodes); + + nodes.root.appendChild(nodes.div1); + nodes.root.appendChild(nodes.p); + nodes.root.appendChild(nodes.div2); + + hooks.afterInsertion(list, nodes); + + nodes.root.removeChild(nodes.div1); + + hooks.afterRemoval(list, nodes); + }, `NodeList live mutations: ${name}`); +} + +testNodeList("NodeList.length", { + initial(list) { + assert_equals(list.length, 0); + }, + afterInsertion(list) { + assert_equals(list.length, 3); + }, + afterRemoval(list) { + assert_equals(list.length, 2); + } +}); + +testNodeList("NodeList.item(index)", { + initial(list) { + assert_equals(list.item(0), null); + }, + afterInsertion(list, nodes) { + assert_equals(list.item(0), nodes.div1); + assert_equals(list.item(1), nodes.p); + assert_equals(list.item(2), nodes.div2); + }, + afterRemoval(list, nodes) { + assert_equals(list.item(0), nodes.p); + assert_equals(list.item(1), nodes.div2); + } +}); + +testNodeList("NodeList[index]", { + initial(list) { + assert_equals(list[0], undefined); + }, + afterInsertion(list, nodes) { + assert_equals(list[0], nodes.div1); + assert_equals(list[1], nodes.p); + assert_equals(list[2], nodes.div2); + }, + afterRemoval(list, nodes) { + assert_equals(list[0], nodes.p); + assert_equals(list[1], nodes.div2); + } +}); + +testNodeList("NodeList ownPropertyNames", { + initial(list) { + assert_object_equals(Object.getOwnPropertyNames(list), []); + }, + afterInsertion(list) { + assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1", "2"]); + }, + afterRemoval(list) { + assert_object_equals(Object.getOwnPropertyNames(list), ["0", "1"]); + } +}); + diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-1.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-1.html new file mode 100644 index 0000000000..c5c58f9d12 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-1.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.defineProperty(nodeList, "length", { get() { return 10; } }); + + assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-2.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-2.html new file mode 100644 index 0000000000..bac0511202 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-2.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.setPrototypeOf(nodeList, { get length() { return 10; } }); + + assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-3.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-3.html new file mode 100644 index 0000000000..9690aab3c1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-3.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } }); + + assert_equals(indexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html new file mode 100644 index 0000000000..5ce4146757 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-1.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.defineProperty(nodeList, "length", { get() { return 10; } }); + + assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html new file mode 100644 index 0000000000..57814ed5ac --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-2.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.setPrototypeOf(nodeList, { get length() { return 10; } }); + + assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html new file mode 100644 index 0000000000..838f376dd2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/NodeList-static-length-getter-tampered-indexOf-3.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<meta name=timeout content=long> +<title>NodeList (static collection) "length" getter tampered (Array.prototype.indexOf)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> + +<script src="support/NodeList-static-length-tampered.js"></script> +<script> +test(() => { + const nodeList = makeStaticNodeList(100); + + for (var i = 0; i < 50; i++) { + if (i === 25) + Object.defineProperty(NodeList.prototype, "length", { get() { return 10; } }); + + assert_equals(arrayIndexOfNodeList(nodeList), i >= 25 ? -1 : 50); + } +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-append.html b/testing/web-platform/tests/dom/nodes/ParentNode-append.html new file mode 100644 index 0000000000..4e101f73a2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-append.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ParentNode.append</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-append"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="pre-insertion-validation-hierarchy.js"></script> +<script> +preInsertionValidateHierarchy("append"); + +function test_append(node, nodeName) { + test(function() { + const parent = node.cloneNode(); + parent.append(); + assert_array_equals(parent.childNodes, []); + }, nodeName + '.append() without any argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.append(null); + assert_equals(parent.childNodes[0].textContent, 'null'); + }, nodeName + '.append() with null as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.append(undefined); + assert_equals(parent.childNodes[0].textContent, 'undefined'); + }, nodeName + '.append() with undefined as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.append('text'); + assert_equals(parent.childNodes[0].textContent, 'text'); + }, nodeName + '.append() with only text as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + const x = document.createElement('x'); + parent.append(x); + assert_array_equals(parent.childNodes, [x]); + }, nodeName + '.append() with only one element as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + const child = document.createElement('test'); + parent.appendChild(child); + parent.append(null); + assert_equals(parent.childNodes[0], child); + assert_equals(parent.childNodes[1].textContent, 'null'); + }, nodeName + '.append() with null as an argument, on a parent having a child.'); + + test(function() { + const parent = node.cloneNode(); + const x = document.createElement('x'); + const child = document.createElement('test'); + parent.appendChild(child); + parent.append(x, 'text'); + assert_equals(parent.childNodes[0], child); + assert_equals(parent.childNodes[1], x); + assert_equals(parent.childNodes[2].textContent, 'text'); + }, nodeName + '.append() with one element and text as argument, on a parent having a child.'); +} + +test_append(document.createElement('div'), 'Element'); +test_append(document.createDocumentFragment(), 'DocumentFragment'); +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-children.html b/testing/web-platform/tests/dom/nodes/ParentNode-children.html new file mode 100644 index 0000000000..6621e7d9de --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-children.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ParentNode.children</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-children"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<div style="display: none"> + <ul><li id='test'>1</li><li>2</li><li>3</li><li>4</li></ul> +</div> +<script> +test(() => { + var node = document.getElementById("test"); + var parentNode = node.parentNode; + var children = parentNode.children; + assert_true(children instanceof HTMLCollection); + var li = document.createElement("li"); + assert_equals(children.length, 4); + + parentNode.appendChild(li); + assert_equals(children.length, 5); + + parentNode.removeChild(li); + assert_equals(children.length, 4); +}, "ParentNode.children should be a live collection"); +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-prepend.html b/testing/web-platform/tests/dom/nodes/ParentNode-prepend.html new file mode 100644 index 0000000000..f6aa38a2dd --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-prepend.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ParentNode.prepend</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-prepend"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="pre-insertion-validation-hierarchy.js"></script> +<script> +preInsertionValidateHierarchy("prepend"); + +function test_prepend(node, nodeName) { + test(function() { + const parent = node.cloneNode(); + parent.prepend(); + assert_array_equals(parent.childNodes, []); + }, nodeName + '.prepend() without any argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.prepend(null); + assert_equals(parent.childNodes[0].textContent, 'null'); + }, nodeName + '.prepend() with null as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.prepend(undefined); + assert_equals(parent.childNodes[0].textContent, 'undefined'); + }, nodeName + '.prepend() with undefined as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + parent.prepend('text'); + assert_equals(parent.childNodes[0].textContent, 'text'); + }, nodeName + '.prepend() with only text as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + const x = document.createElement('x'); + parent.prepend(x); + assert_array_equals(parent.childNodes, [x]); + }, nodeName + '.prepend() with only one element as an argument, on a parent having no child.'); + + test(function() { + const parent = node.cloneNode(); + const child = document.createElement('test'); + parent.appendChild(child); + parent.prepend(null); + assert_equals(parent.childNodes[0].textContent, 'null'); + assert_equals(parent.childNodes[1], child); + }, nodeName + '.prepend() with null as an argument, on a parent having a child.'); + + test(function() { + const parent = node.cloneNode(); + const x = document.createElement('x'); + const child = document.createElement('test'); + parent.appendChild(child); + parent.prepend(x, 'text'); + assert_equals(parent.childNodes[0], x); + assert_equals(parent.childNodes[1].textContent, 'text'); + assert_equals(parent.childNodes[2], child); + }, nodeName + '.prepend() with one element and text as argument, on a parent having a child.'); +} + +test_prepend(document.createElement('div'), 'Element'); +test_prepend(document.createDocumentFragment(), 'DocumentFragment'); +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.html new file mode 100644 index 0000000000..8dc1354551 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.html @@ -0,0 +1,377 @@ +<!DOCTYPE html> +<html id="html" lang="en"> +<head id="head"> + <meta id="meta" charset="UTF-8"> + <title id="title">Selectors-API Test Suite: HTML with Selectors Level 2 using TestHarness: Test Document</title> + + <!-- Links for :link and :visited pseudo-class test --> + <link id="pseudo-link-link1" href=""> + <link id="pseudo-link-link2" href="http://example.org/"> + <link id="pseudo-link-link3"> + <style> + @namespace ns "http://www.w3.org/1999/xhtml"; + /* Declare the namespace prefix used in tests. This declaration should not be used by the API. */ + </style> +</head> +<body id="body"> +<div id="root"> + <div id="target"></div> + + <div id="universal"> + <p id="universal-p1">Universal selector tests inside element with <code id="universal-code1">id="universal"</code>.</p> + <hr id="universal-hr1"> + <pre id="universal-pre1">Some preformatted text with some <span id="universal-span1">embedded code</span></pre> + <p id="universal-p2">This is a normal link: <a id="universal-a1" href="http://www.w3.org/">W3C</a></p> + <address id="universal-address1">Some more nested elements <code id="universal-code2"><a href="#" id="universal-a2">code hyperlink</a></code></address> + </div> + + <div id="attr-presence"> + <div class="attr-presence-div1" id="attr-presence-div1" align="center"></div> + <div class="attr-presence-div2" id="attr-presence-div2" align=""></div> + <div class="attr-presence-div3" id="attr-presence-div3" valign="center"></div> + <div class="attr-presence-div4" id="attr-presence-div4" alignv="center"></div> + <p id="attr-presence-p1"><a id="attr-presence-a1" tItLe=""></a><span id="attr-presence-span1" TITLE="attr-presence-span1"></span><i id="attr-presence-i1"></i></p> + <pre id="attr-presence-pre1" data-attr-presence="pre1"></pre> + <blockquote id="attr-presence-blockquote1" data-attr-presence="blockquote1"></blockquote> + <ul id="attr-presence-ul1" data-中文=""></ul> + + <select id="attr-presence-select1"> + <option id="attr-presence-select1-option1">A</option> + <option id="attr-presence-select1-option2">B</option> + <option id="attr-presence-select1-option3">C</option> + <option id="attr-presence-select1-option4">D</option> + </select> + <select id="attr-presence-select2"> + <option id="attr-presence-select2-option1">A</option> + <option id="attr-presence-select2-option2">B</option> + <option id="attr-presence-select2-option3">C</option> + <option id="attr-presence-select2-option4" selected="selected">D</option> + </select> + <select id="attr-presence-select3" multiple="multiple"> + <option id="attr-presence-select3-option1">A</option> + <option id="attr-presence-select3-option2" selected="">B</option> + <option id="attr-presence-select3-option3" selected="selected">C</option> + <option id="attr-presence-select3-option4">D</option> + </select> + </div> + + <div id="attr-value"> + <div id="attr-value-div1" align="center"></div> + <div id="attr-value-div2" align=""></div> + <div id="attr-value-div3" data-attr-value="é"></div> + <div id="attr-value-div4" data-attr-value_foo="é"></div> + + <form id="attr-value-form1"> + <input id="attr-value-input1" type="text"> + <input id="attr-value-input2" type="password"> + <input id="attr-value-input3" type="hidden"> + <input id="attr-value-input4" type="radio"> + <input id="attr-value-input5" type="checkbox"> + <input id="attr-value-input6" type="radio"> + <input id="attr-value-input7" type="text"> + <input id="attr-value-input8" type="hidden"> + <input id="attr-value-input9" type="radio"> + </form> + + <div id="attr-value-div5" data-attr-value="中文"></div> + </div> + + <div id="attr-whitespace"> + <div id="attr-whitespace-div1" class="foo div1 bar"></div> + <div id="attr-whitespace-div2" class=""></div> + <div id="attr-whitespace-div3" class="foo div3 bar"></div> + + <div id="attr-whitespace-div4" data-attr-whitespace="foo é bar"></div> + <div id="attr-whitespace-div5" data-attr-whitespace_foo="é foo"></div> + + <a id="attr-whitespace-a1" rel="next bookmark"></a> + <a id="attr-whitespace-a2" rel="tag nofollow"></a> + <a id="attr-whitespace-a3" rel="tag bookmark"></a> + <a id="attr-whitespace-a4" rel="book mark"></a> <!-- Intentional space in "book mark" --> + <a id="attr-whitespace-a5" rel="nofollow"></a> + <a id="attr-whitespace-a6" rev="bookmark nofollow"></a> + <a id="attr-whitespace-a7" rel="prev next tag alternate nofollow author help icon noreferrer prefetch search stylesheet tag"></a> + + <p id="attr-whitespace-p1" title="Chinese 中文 characters"></p> + </div> + + <div id="attr-hyphen"> + <div id="attr-hyphen-div1"></div> + <div id="attr-hyphen-div2" lang="fr"></div> + <div id="attr-hyphen-div3" lang="en-AU"></div> + <div id="attr-hyphen-div4" lang="es"></div> + </div> + + <div id="attr-begins"> + <a id="attr-begins-a1" href="http://www.example.org"></a> + <a id="attr-begins-a2" href="http://example.org/"></a> + <a id="attr-begins-a3" href="http://www.example.com/"></a> + + <div id="attr-begins-div1" lang="fr"></div> + <div id="attr-begins-div2" lang="en-AU"></div> + <div id="attr-begins-div3" lang="es"></div> + <div id="attr-begins-div4" lang="en-US"></div> + <div id="attr-begins-div5" lang="en"></div> + + <p id="attr-begins-p1" class=" apple"></p> <!-- Intentional space in class value " apple". --> + </div> + + <div id="attr-ends"> + <a id="attr-ends-a1" href="http://www.example.org"></a> + <a id="attr-ends-a2" href="http://example.org/"></a> + <a id="attr-ends-a3" href="http://www.example.org"></a> + + <div id="attr-ends-div1" lang="fr"></div> + <div id="attr-ends-div2" lang="de-CH"></div> + <div id="attr-ends-div3" lang="es"></div> + <div id="attr-ends-div4" lang="fr-CH"></div> + + <p id="attr-ends-p1" class="apple "></p> <!-- Intentional space in class value "apple ". --> + </div> + + <div id="attr-contains"> + <a id="attr-contains-a1" href="http://www.example.org"></a> + <a id="attr-contains-a2" href="http://example.org/"></a> + <a id="attr-contains-a3" href="http://www.example.com/"></a> + + <div id="attr-contains-div1" lang="fr"></div> + <div id="attr-contains-div2" lang="en-AU"></div> + <div id="attr-contains-div3" lang="de-CH"></div> + <div id="attr-contains-div4" lang="es"></div> + <div id="attr-contains-div5" lang="fr-CH"></div> + <div id="attr-contains-div6" lang="en-US"></div> + + <p id="attr-contains-p1" class=" apple banana orange "></p> + </div> + + <div id="pseudo-nth"> + <table id="pseudo-nth-table1"> + <tr id="pseudo-nth-tr1"><td id="pseudo-nth-td1"></td><td id="pseudo-nth-td2"></td><td id="pseudo-nth-td3"></td><td id="pseudo-nth-td4"></td><td id="pseudo-nth--td5"></td><td id="pseudo-nth-td6"></td></tr> + <tr id="pseudo-nth-tr2"><td id="pseudo-nth-td7"></td><td id="pseudo-nth-td8"></td><td id="pseudo-nth-td9"></td><td id="pseudo-nth-td10"></td><td id="pseudo-nth-td11"></td><td id="pseudo-nth-td12"></td></tr> + <tr id="pseudo-nth-tr3"><td id="pseudo-nth-td13"></td><td id="pseudo-nth-td14"></td><td id="pseudo-nth-td15"></td><td id="pseudo-nth-td16"></td><td id="pseudo-nth-td17"></td><td id="pseudo-nth-td18"></td></tr> + </table> + + <ol id="pseudo-nth-ol1"> + <li id="pseudo-nth-li1"></li> + <li id="pseudo-nth-li2"></li> + <li id="pseudo-nth-li3"></li> + <li id="pseudo-nth-li4"></li> + <li id="pseudo-nth-li5"></li> + <li id="pseudo-nth-li6"></li> + <li id="pseudo-nth-li7"></li> + <li id="pseudo-nth-li8"></li> + <li id="pseudo-nth-li9"></li> + <li id="pseudo-nth-li10"></li> + <li id="pseudo-nth-li11"></li> + <li id="pseudo-nth-li12"></li> + </ol> + + <p id="pseudo-nth-p1"> + <span id="pseudo-nth-span1">span1</span> + <em id="pseudo-nth-em1">em1</em> + <!-- comment node--> + <em id="pseudo-nth-em2">em2</em> + <span id="pseudo-nth-span2">span2</span> + <strong id="pseudo-nth-strong1">strong1</strong> + <em id="pseudo-nth-em3">em3</em> + <span id="pseudo-nth-span3">span3</span> + <span id="pseudo-nth-span4">span4</span> + <strong id="pseudo-nth-strong2">strong2</strong> + <em id="pseudo-nth-em4">em4</em> + </p> + </div> + + <div id="pseudo-first-child"> + <div id="pseudo-first-child-div1"></div> + <div id="pseudo-first-child-div2"></div> + <div id="pseudo-first-child-div3"></div> + + <p id="pseudo-first-child-p1"><span id="pseudo-first-child-span1"></span><span id="pseudo-first-child-span2"></span></p> + <p id="pseudo-first-child-p2"><span id="pseudo-first-child-span3"></span><span id="pseudo-first-child-span4"></span></p> + <p id="pseudo-first-child-p3"><span id="pseudo-first-child-span5"></span><span id="pseudo-first-child-span6"></span></p> + </div> + + <div id="pseudo-last-child"> + <p id="pseudo-last-child-p1"><span id="pseudo-last-child-span1"></span><span id="pseudo-last-child-span2"></span></p> + <p id="pseudo-last-child-p2"><span id="pseudo-last-child-span3"></span><span id="pseudo-last-child-span4"></span></p> + <p id="pseudo-last-child-p3"><span id="pseudo-last-child-span5"></span><span id="pseudo-last-child-span6"></span></p> + + <div id="pseudo-last-child-div1"></div> + <div id="pseudo-last-child-div2"></div> + <div id="pseudo-last-child-div3"></div> + </div> + + <div id="pseudo-only"> + <p id="pseudo-only-p1"> + <span id="pseudo-only-span1"></span> + </p> + <p id="pseudo-only-p2"> + <span id="pseudo-only-span2"></span> + <span id="pseudo-only-span3"></span> + </p> + <p id="pseudo-only-p3"> + <span id="pseudo-only-span4"></span> + <em id="pseudo-only-em1"></em> + <span id="pseudo-only-span5"></span> + </p> + </div>> + + <div id="pseudo-empty"> + <p id="pseudo-empty-p1"></p> + <p id="pseudo-empty-p2"><!-- comment node --></p> + <p id="pseudo-empty-p3"> </p> + <p id="pseudo-empty-p4">Text node</p> + <p id="pseudo-empty-p5"><span id="pseudo-empty-span1"></span></p> + </div> + + <div id="pseudo-link"> + <a id="pseudo-link-a1" href="">with href</a> + <a id="pseudo-link-a2" href="http://example.org/">with href</a> + <a id="pseudo-link-a3">without href</a> + <map name="pseudo-link-map1" id="pseudo-link-map1"> + <area id="pseudo-link-area1" href=""> + <area id="pseudo-link-area2"> + </map> + </div> + + <div id="pseudo-lang"> + <div id="pseudo-lang-div1"></div> + <div id="pseudo-lang-div2" lang="fr"></div> + <div id="pseudo-lang-div3" lang="en-AU"></div> + <div id="pseudo-lang-div4" lang="es"></div> + </div> + + <div id="pseudo-ui"> + <input id="pseudo-ui-input1" type="text"> + <input id="pseudo-ui-input2" type="password"> + <input id="pseudo-ui-input3" type="radio"> + <input id="pseudo-ui-input4" type="radio" checked="checked"> + <input id="pseudo-ui-input5" type="checkbox"> + <input id="pseudo-ui-input6" type="checkbox" checked="checked"> + <input id="pseudo-ui-input7" type="submit"> + <input id="pseudo-ui-input8" type="button"> + <input id="pseudo-ui-input9" type="hidden"> + <textarea id="pseudo-ui-textarea1"></textarea> + <button id="pseudo-ui-button1">Enabled</button> + + <input id="pseudo-ui-input10" disabled="disabled" type="text"> + <input id="pseudo-ui-input11" disabled="disabled" type="password"> + <input id="pseudo-ui-input12" disabled="disabled" type="radio"> + <input id="pseudo-ui-input13" disabled="disabled" type="radio" checked="checked"> + <input id="pseudo-ui-input14" disabled="disabled" type="checkbox"> + <input id="pseudo-ui-input15" disabled="disabled" type="checkbox" checked="checked"> + <input id="pseudo-ui-input16" disabled="disabled" type="submit"> + <input id="pseudo-ui-input17" disabled="disabled" type="button"> + <input id="pseudo-ui-input18" disabled="disabled" type="hidden"> + <textarea id="pseudo-ui-textarea2" disabled="disabled"></textarea> + <button id="pseudo-ui-button2" disabled="disabled">Disabled</button> + </div> + + <div id="not"> + <div id="not-div1"></div> + <div id="not-div2"></div> + <div id="not-div3"></div> + + <p id="not-p1"><span id="not-span1"></span><em id="not-em1"></em></p> + <p id="not-p2"><span id="not-span2"></span><em id="not-em2"></em></p> + <p id="not-p3"><span id="not-span3"></span><em id="not-em3"></em></p> + </div> + + <div id="pseudo-element">All pseudo-element tests</div> + + <div id="class"> + <p id="class-p1" class="foo class-p bar"></p> + <p id="class-p2" class="class-p foo bar"></p> + <p id="class-p3" class="foo bar class-p"></p> + + <!-- All permutations of the classes should match --> + <div id="class-div1" class="apple orange banana"></div> + <div id="class-div2" class="apple banana orange"></div> + <p id="class-p4" class="orange apple banana"></p> + <div id="class-div3" class="orange banana apple"></div> + <p id="class-p6" class="banana apple orange"></p> + <div id="class-div4" class="banana orange apple"></div> + <div id="class-div5" class="apple orange"></div> + <div id="class-div6" class="apple banana"></div> + <div id="class-div7" class="orange banana"></div> + + <span id="class-span1" class="台北Táiběi 台北"></span> + <span id="class-span2" class="台北"></span> + + <span id="class-span3" class="foo:bar"></span> + <span id="class-span4" class="test.foo[5]bar"></span> + </div> + + <div id="id"> + <div id="id-div1"></div> + <div id="id-div2"></div> + + <ul id="id-ul1"> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + </ul> + + <span id="台北Táiběi"></span> + <span id="台北"></span> + + <span id="#foo:bar"></span> + <span id="test.foo[5]bar"></span> + </div> + + <div id="descendant"> + <div id="descendant-div1" class="descendant-div1"> + <div id="descendant-div2" class="descendant-div2"> + <div id="descendant-div3" class="descendant-div3"> + </div> + </div> + </div> + <div id="descendant-div4" class="descendant-div4"></div> + </div> + + <div id="child"> + <div id="child-div1" class="child-div1"> + <div id="child-div2" class="child-div2"> + <div id="child-div3" class="child-div3"> + </div> + </div> + </div> + <div id="child-div4" class="child-div4"></div> + </div> + + <div id="adjacent"> + <div id="adjacent-div1" class="adjacent-div1"></div> + <div id="adjacent-div2" class="adjacent-div2"> + <div id="adjacent-div3" class="adjacent-div3"></div> + </div> + <div id="adjacent-div4" class="adjacent-div4"> + <p id="adjacent-p1" class="adjacent-p1"></p> + <div id="adjacent-div5" class="adjacent-div5"></div> + </div> + <div id="adjacent-div6" class="adjacent-div6"></div> + <p id="adjacent-p2" class="adjacent-p2"></p> + <p id="adjacent-p3" class="adjacent-p3"></p> + </div> + + <div id="sibling"> + <div id="sibling-div1" class="sibling-div"></div> + <div id="sibling-div2" class="sibling-div"> + <div id="sibling-div3" class="sibling-div"></div> + </div> + <div id="sibling-div4" class="sibling-div"> + <p id="sibling-p1" class="sibling-p"></p> + <div id="sibling-div5" class="sibling-div"></div> + </div> + <div id="sibling-div6" class="sibling-div"></div> + <p id="sibling-p2" class="sibling-p"></p> + <p id="sibling-p3" class="sibling-p"></p> + </div> + + <div id="group"> + <em id="group-em1"></em> + <strong id="group-strong1"></strong> + </div> +</div> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.xht b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.xht new file mode 100644 index 0000000000..0e9b925f58 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-content.xht @@ -0,0 +1,372 @@ +<!DOCTYPE html> +<html id="html" lang="en" xmlns="http://www.w3.org/1999/xhtml"> +<head id="head"> + <title id="title">Selectors-API Test Suite: HTML with Selectors Level 2 using TestHarness: Test Document</title> + + <!-- Links for :link and :visited pseudo-class test --> + <link id="pseudo-link-link1" href=""/> + <link id="pseudo-link-link2" href="http://example.org/"/> + <link id="pseudo-link-link3"/> +</head> +<body id="body"> +<div id="root"> + <div id="target"></div> + + <div id="universal"> + <p id="universal-p1">Universal selector tests inside element with <code id="universal-code1">id="universal"</code>.</p> + <hr id="universal-hr1"/> + <pre id="universal-pre1">Some preformatted text with some <span id="universal-span1">embedded code</span></pre> + <p id="universal-p2">This is a normal link: <a id="universal-a1" href="http://www.w3.org/">W3C</a></p> + <address id="universal-address1">Some more nested elements <code id="universal-code2"><a href="#" id="universal-a2">code hyperlink</a></code></address> + </div> + + <div id="attr-presence"> + <div class="attr-presence-div1" id="attr-presence-div1" align="center"></div> + <div class="attr-presence-div2" id="attr-presence-div2" align=""></div> + <div class="attr-presence-div3" id="attr-presence-div3" valign="center"></div> + <div class="attr-presence-div4" id="attr-presence-div4" alignv="center"></div> + <p id="attr-presence-p1"><a id="attr-presence-a1" tItLe=""></a><span id="attr-presence-span1" TITLE="attr-presence-span1"></span><i id="attr-presence-i1"></i></p> + <pre id="attr-presence-pre1" data-attr-presence="pre1"></pre> + <blockquote id="attr-presence-blockquote1" data-attr-presence="blockquote1"></blockquote> + <ul id="attr-presence-ul1" data-中文=""></ul> + + <select id="attr-presence-select1"> + <option id="attr-presence-select1-option1">A</option> + <option id="attr-presence-select1-option2">B</option> + <option id="attr-presence-select1-option3">C</option> + <option id="attr-presence-select1-option4">D</option> + </select> + <select id="attr-presence-select2"> + <option id="attr-presence-select2-option1">A</option> + <option id="attr-presence-select2-option2">B</option> + <option id="attr-presence-select2-option3">C</option> + <option id="attr-presence-select2-option4" selected="selected">D</option> + </select> + <select id="attr-presence-select3" multiple="multiple"> + <option id="attr-presence-select3-option1">A</option> + <option id="attr-presence-select3-option2" selected="">B</option> + <option id="attr-presence-select3-option3" selected="selected">C</option> + <option id="attr-presence-select3-option4">D</option> + </select> + </div> + + <div id="attr-value"> + <div id="attr-value-div1" align="center"></div> + <div id="attr-value-div2" align=""></div> + <div id="attr-value-div3" data-attr-value="é"></div> + <div id="attr-value-div4" data-attr-value_foo="é"></div> + + <form id="attr-value-form1"> + <input id="attr-value-input1" type="text"/> + <input id="attr-value-input2" type="password"/> + <input id="attr-value-input3" type="hidden"/> + <input id="attr-value-input4" type="radio"/> + <input id="attr-value-input5" type="checkbox"/> + <input id="attr-value-input6" type="radio"/> + <input id="attr-value-input7" type="text"/> + <input id="attr-value-input8" type="hidden"/> + <input id="attr-value-input9" type="radio"/> + </form> + + <div id="attr-value-div5" data-attr-value="中文"></div> + </div> + + <div id="attr-whitespace"> + <div id="attr-whitespace-div1" class="foo div1 bar"></div> + <div id="attr-whitespace-div2" class=""></div> + <div id="attr-whitespace-div3" class="foo div3 bar"></div> + + <div id="attr-whitespace-div4" data-attr-whitespace="foo é bar"></div> + <div id="attr-whitespace-div5" data-attr-whitespace_foo="é foo"></div> + + <a id="attr-whitespace-a1" rel="next bookmark"></a> + <a id="attr-whitespace-a2" rel="tag nofollow"></a> + <a id="attr-whitespace-a3" rel="tag bookmark"></a> + <a id="attr-whitespace-a4" rel="book mark"></a> <!-- Intentional space in "book mark" --> + <a id="attr-whitespace-a5" rel="nofollow"></a> + <a id="attr-whitespace-a6" rev="bookmark nofollow"></a> + <a id="attr-whitespace-a7" rel="prev next tag alternate nofollow author help icon noreferrer prefetch search stylesheet tag"></a> + + <p id="attr-whitespace-p1" title="Chinese 中文 characters"></p> + </div> + + <div id="attr-hyphen"> + <div id="attr-hyphen-div1"></div> + <div id="attr-hyphen-div2" lang="fr"></div> + <div id="attr-hyphen-div3" lang="en-AU"></div> + <div id="attr-hyphen-div4" lang="es"></div> + </div> + + <div id="attr-begins"> + <a id="attr-begins-a1" href="http://www.example.org"></a> + <a id="attr-begins-a2" href="http://example.org/"></a> + <a id="attr-begins-a3" href="http://www.example.com/"></a> + + <div id="attr-begins-div1" lang="fr"></div> + <div id="attr-begins-div2" lang="en-AU"></div> + <div id="attr-begins-div3" lang="es"></div> + <div id="attr-begins-div4" lang="en-US"></div> + <div id="attr-begins-div5" lang="en"></div> + + <p id="attr-begins-p1" class=" apple"></p> <!-- Intentional space in class value " apple". --> + </div> + + <div id="attr-ends"> + <a id="attr-ends-a1" href="http://www.example.org"></a> + <a id="attr-ends-a2" href="http://example.org/"></a> + <a id="attr-ends-a3" href="http://www.example.org"></a> + + <div id="attr-ends-div1" lang="fr"></div> + <div id="attr-ends-div2" lang="de-CH"></div> + <div id="attr-ends-div3" lang="es"></div> + <div id="attr-ends-div4" lang="fr-CH"></div> + + <p id="attr-ends-p1" class="apple "></p> <!-- Intentional space in class value "apple ". --> + </div> + + <div id="attr-contains"> + <a id="attr-contains-a1" href="http://www.example.org"></a> + <a id="attr-contains-a2" href="http://example.org/"></a> + <a id="attr-contains-a3" href="http://www.example.com/"></a> + + <div id="attr-contains-div1" lang="fr"></div> + <div id="attr-contains-div2" lang="en-AU"></div> + <div id="attr-contains-div3" lang="de-CH"></div> + <div id="attr-contains-div4" lang="es"></div> + <div id="attr-contains-div5" lang="fr-CH"></div> + <div id="attr-contains-div6" lang="en-US"></div> + + <p id="attr-contains-p1" class=" apple banana orange "></p> + </div> + + <div id="pseudo-nth"> + <table id="pseudo-nth-table1"> + <tr id="pseudo-nth-tr1"><td id="pseudo-nth-td1"></td><td id="pseudo-nth-td2"></td><td id="pseudo-nth-td3"></td><td id="pseudo-nth-td4"></td><td id="pseudo-nth--td5"></td><td id="pseudo-nth-td6"></td></tr> + <tr id="pseudo-nth-tr2"><td id="pseudo-nth-td7"></td><td id="pseudo-nth-td8"></td><td id="pseudo-nth-td9"></td><td id="pseudo-nth-td10"></td><td id="pseudo-nth-td11"></td><td id="pseudo-nth-td12"></td></tr> + <tr id="pseudo-nth-tr3"><td id="pseudo-nth-td13"></td><td id="pseudo-nth-td14"></td><td id="pseudo-nth-td15"></td><td id="pseudo-nth-td16"></td><td id="pseudo-nth-td17"></td><td id="pseudo-nth-td18"></td></tr> + </table> + + <ol id="pseudo-nth-ol1"> + <li id="pseudo-nth-li1"></li> + <li id="pseudo-nth-li2"></li> + <li id="pseudo-nth-li3"></li> + <li id="pseudo-nth-li4"></li> + <li id="pseudo-nth-li5"></li> + <li id="pseudo-nth-li6"></li> + <li id="pseudo-nth-li7"></li> + <li id="pseudo-nth-li8"></li> + <li id="pseudo-nth-li9"></li> + <li id="pseudo-nth-li10"></li> + <li id="pseudo-nth-li11"></li> + <li id="pseudo-nth-li12"></li> + </ol> + + <p id="pseudo-nth-p1"> + <span id="pseudo-nth-span1">span1</span> + <em id="pseudo-nth-em1">em1</em> + <!-- comment node--> + <em id="pseudo-nth-em2">em2</em> + <span id="pseudo-nth-span2">span2</span> + <strong id="pseudo-nth-strong1">strong1</strong> + <em id="pseudo-nth-em3">em3</em> + <span id="pseudo-nth-span3">span3</span> + <span id="pseudo-nth-span4">span4</span> + <strong id="pseudo-nth-strong2">strong2</strong> + <em id="pseudo-nth-em4">em4</em> + </p> + </div> + + <div id="pseudo-first-child"> + <div id="pseudo-first-child-div1"></div> + <div id="pseudo-first-child-div2"></div> + <div id="pseudo-first-child-div3"></div> + + <p id="pseudo-first-child-p1"><span id="pseudo-first-child-span1"></span><span id="pseudo-first-child-span2"></span></p> + <p id="pseudo-first-child-p2"><span id="pseudo-first-child-span3"></span><span id="pseudo-first-child-span4"></span></p> + <p id="pseudo-first-child-p3"><span id="pseudo-first-child-span5"></span><span id="pseudo-first-child-span6"></span></p> + </div> + + <div id="pseudo-last-child"> + <p id="pseudo-last-child-p1"><span id="pseudo-last-child-span1"></span><span id="pseudo-last-child-span2"></span></p> + <p id="pseudo-last-child-p2"><span id="pseudo-last-child-span3"></span><span id="pseudo-last-child-span4"></span></p> + <p id="pseudo-last-child-p3"><span id="pseudo-last-child-span5"></span><span id="pseudo-last-child-span6"></span></p> + + <div id="pseudo-last-child-div1"></div> + <div id="pseudo-last-child-div2"></div> + <div id="pseudo-last-child-div3"></div> + </div> + + <div id="pseudo-only"> + <p id="pseudo-only-p1"> + <span id="pseudo-only-span1"></span> + </p> + <p id="pseudo-only-p2"> + <span id="pseudo-only-span2"></span> + <span id="pseudo-only-span3"></span> + </p> + <p id="pseudo-only-p3"> + <span id="pseudo-only-span4"></span> + <em id="pseudo-only-em1"></em> + <span id="pseudo-only-span5"></span> + </p> + </div>> + + <div id="pseudo-empty"> + <p id="pseudo-empty-p1"></p> + <p id="pseudo-empty-p2"><!-- comment node --></p> + <p id="pseudo-empty-p3"> </p> + <p id="pseudo-empty-p4">Text node</p> + <p id="pseudo-empty-p5"><span id="pseudo-empty-span1"></span></p> + </div> + + <div id="pseudo-link"> + <a id="pseudo-link-a1" href="">with href</a> + <a id="pseudo-link-a2" href="http://example.org/">with href</a> + <a id="pseudo-link-a3">without href</a> + <map name="pseudo-link-map1" id="pseudo-link-map1"> + <area id="pseudo-link-area1" href=""/> + <area id="pseudo-link-area2"/> + </map> + </div> + + <div id="pseudo-lang"> + <div id="pseudo-lang-div1"></div> + <div id="pseudo-lang-div2" lang="fr"></div> + <div id="pseudo-lang-div3" lang="en-AU"></div> + <div id="pseudo-lang-div4" lang="es"></div> + </div> + + <div id="pseudo-ui"> + <input id="pseudo-ui-input1" type="text"/> + <input id="pseudo-ui-input2" type="password"/> + <input id="pseudo-ui-input3" type="radio"/> + <input id="pseudo-ui-input4" type="radio" checked="checked"/> + <input id="pseudo-ui-input5" type="checkbox"/> + <input id="pseudo-ui-input6" type="checkbox" checked="checked"/> + <input id="pseudo-ui-input7" type="submit"/> + <input id="pseudo-ui-input8" type="button"/> + <input id="pseudo-ui-input9" type="hidden"/> + <textarea id="pseudo-ui-textarea1"></textarea> + <button id="pseudo-ui-button1">Enabled</button> + + <input id="pseudo-ui-input10" disabled="disabled" type="text"/> + <input id="pseudo-ui-input11" disabled="disabled" type="password"/> + <input id="pseudo-ui-input12" disabled="disabled" type="radio"/> + <input id="pseudo-ui-input13" disabled="disabled" type="radio" checked="checked"/> + <input id="pseudo-ui-input14" disabled="disabled" type="checkbox"/> + <input id="pseudo-ui-input15" disabled="disabled" type="checkbox" checked="checked"/> + <input id="pseudo-ui-input16" disabled="disabled" type="submit"/> + <input id="pseudo-ui-input17" disabled="disabled" type="button"/> + <input id="pseudo-ui-input18" disabled="disabled" type="hidden"/> + <textarea id="pseudo-ui-textarea2" disabled="disabled"></textarea> + <button id="pseudo-ui-button2" disabled="disabled">Disabled</button> + </div> + + <div id="not"> + <div id="not-div1"></div> + <div id="not-div2"></div> + <div id="not-div3"></div> + + <p id="not-p1"><span id="not-span1"></span><em id="not-em1"></em></p> + <p id="not-p2"><span id="not-span2"></span><em id="not-em2"></em></p> + <p id="not-p3"><span id="not-span3"></span><em id="not-em3"></em></p> + </div> + + <div id="pseudo-element">All pseudo-element tests</div> + + <div id="class"> + <p id="class-p1" class="foo class-p bar"></p> + <p id="class-p2" class="class-p foo bar"></p> + <p id="class-p3" class="foo bar class-p"></p> + + <!-- All permutations of the classes should match --> + <div id="class-div1" class="apple orange banana"></div> + <div id="class-div2" class="apple banana orange"></div> + <p id="class-p4" class="orange apple banana"></p> + <div id="class-div3" class="orange banana apple"></div> + <p id="class-p6" class="banana apple orange"></p> + <div id="class-div4" class="banana orange apple"></div> + <div id="class-div5" class="apple orange"></div> + <div id="class-div6" class="apple banana"></div> + <div id="class-div7" class="orange banana"></div> + + <span id="class-span1" class="台北Táiběi 台北"></span> + <span id="class-span2" class="台北"></span> + + <span id="class-span3" class="foo:bar"></span> + <span id="class-span4" class="test.foo[5]bar"></span> + </div> + + <div id="id"> + <div id="id-div1"></div> + <div id="id-div2"></div> + + <ul id="id-ul1"> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + <li id="id-li-duplicate"></li> + </ul> + + <span id="台北Táiběi"></span> + <span id="台北"></span> + + <span id="#foo:bar"></span> + <span id="test.foo[5]bar"></span> + </div> + + <div id="descendant"> + <div id="descendant-div1" class="descendant-div1"> + <div id="descendant-div2" class="descendant-div2"> + <div id="descendant-div3" class="descendant-div3"> + </div> + </div> + </div> + <div id="descendant-div4" class="descendant-div4"></div> + </div> + + <div id="child"> + <div id="child-div1" class="child-div1"> + <div id="child-div2" class="child-div2"> + <div id="child-div3" class="child-div3"> + </div> + </div> + </div> + <div id="child-div4" class="child-div4"></div> + </div> + + <div id="adjacent"> + <div id="adjacent-div1" class="adjacent-div1"></div> + <div id="adjacent-div2" class="adjacent-div2"> + <div id="adjacent-div3" class="adjacent-div3"></div> + </div> + <div id="adjacent-div4" class="adjacent-div4"> + <p id="adjacent-p1" class="adjacent-p1"></p> + <div id="adjacent-div5" class="adjacent-div5"></div> + </div> + <div id="adjacent-div6" class="adjacent-div6"></div> + <p id="adjacent-p2" class="adjacent-p2"></p> + <p id="adjacent-p3" class="adjacent-p3"></p> + </div> + + <div id="sibling"> + <div id="sibling-div1" class="sibling-div"></div> + <div id="sibling-div2" class="sibling-div"> + <div id="sibling-div3" class="sibling-div"></div> + </div> + <div id="sibling-div4" class="sibling-div"> + <p id="sibling-p1" class="sibling-p"></p> + <div id="sibling-div5" class="sibling-div"></div> + </div> + <div id="sibling-div6" class="sibling-div"></div> + <p id="sibling-p2" class="sibling-p"></p> + <p id="sibling-p3" class="sibling-p"></p> + </div> + + <div id="group"> + <em id="group-em1"></em> + <strong id="group-strong1"></strong> + </div> +</div> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht new file mode 100644 index 0000000000..f2d94da1da --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All-xht.xht @@ -0,0 +1,124 @@ +<!DOCTYPE html> +<html id="html" lang="en" xmlns="http://www.w3.org/1999/xhtml"> +<head id="head"> +<meta name="timeout" content="long" /> +<title>Selectors-API Test Suite: XHTML</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="selectors.js"></script> +<script src="ParentNode-querySelector-All.js"></script> +<style>iframe { visibility: hidden; position: absolute; }</style> +</head> +<body> +<div id="log">This test requires JavaScript.</div> + +<script><![CDATA[ +async_test(function() { + var frame = document.createElement("iframe"); + var self = this; + frame.onload = function() { + // :target doesn't work before a page rendering on some browsers. We run + // tests after an animation frame because it may be later than the first + // page rendering. + requestAnimationFrame(self.step_func_done(init.bind(self, frame))); + }; + frame.src = "ParentNode-querySelector-All-content.xht#target"; + document.body.appendChild(frame); +}) + +function init(target) { + /* + * This test suite tests Selectors API methods in 4 different contexts: + * 1. Document node + * 2. In-document Element node + * 3. Detached Element node (an element with no parent, not in the document) + * 4. Document Fragment node + * + * For each context, the following tests are run: + * + * The interface check tests ensure that each type of node exposes the Selectors API methods + * + * The special selector tests verify the result of passing special values for the selector parameter, + * to ensure that the correct WebIDL processing is performed, such as stringification of null and + * undefined and missing parameter. The universal selector is also tested here, rather than with the + * rest of ordinary selectors for practical reasons. + * + * The static list verification tests ensure that the node lists returned by the method remain unchanged + * due to subsequent document modication, and that a new list is generated each time the method is + * invoked based on the current state of the document. + * + * The invalid selector tests ensure that SyntaxError is thrown for invalid forms of selectors + * + * The valid selector tests check the result from querying many different types of selectors, with a + * list of expected elements. This checks that querySelector() always returns the first result from + * querySelectorAll(), and that all matching elements are correctly returned in tree-order. The tests + * can be limited by specifying the test types to run, using the testType variable. The constants for this + * can be found in selectors.js. + * + * All the selectors tested for both the valid and invalid selector tests are found in selectors.js. + * See comments in that file for documentation of the format used. + * + * The ParentNode-querySelector-All.js file contains all the common test functions for running each of the aforementioned tests + */ + + var testType = TEST_QSA; + var docType = "xhtml"; // Only run tests suitable for XHTML + + // Prepare the nodes for testing + var doc = target.contentDocument; // Document Node tests + + var element = doc.getElementById("root"); // In-document Element Node tests + + //Setup the namespace tests + setupSpecialElements(doc, element); + + var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document + // Element tests, but after running the Document tests. This + // tests that no elements that are not descendants of element + // are selected. + + traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying + elem.setAttribute("data-clone", ""); // that none of these elements ever match. + }); + + + var detached = element.cloneNode(true); // Detached Element Node tests + + var fragment = doc.createDocumentFragment(); // Fragment Node tests + fragment.appendChild(element.cloneNode(true)); + + var empty = document.createElement("div"); // Empty Node tests + + // Setup Tests + interfaceCheck("Document", doc); + interfaceCheck("Detached Element", detached); + interfaceCheck("Fragment", fragment); + interfaceCheck("In-document Element", element); + + runSpecialSelectorTests("Document", doc); + runSpecialSelectorTests("Detached Element", detached); + runSpecialSelectorTests("Fragment", fragment); + runSpecialSelectorTests("In-document Element", element); + + verifyStaticList("Document", doc, doc); + verifyStaticList("Detached Element", doc, detached); + verifyStaticList("Fragment", doc, fragment); + verifyStaticList("In-document Element", doc, element); + + runInvalidSelectorTest("Document", doc, invalidSelectors); + runInvalidSelectorTest("Detached Element", detached, invalidSelectors); + runInvalidSelectorTest("Fragment", fragment, invalidSelectors); + runInvalidSelectorTest("In-document Element", element, invalidSelectors); + runInvalidSelectorTest("Empty Element", empty, invalidSelectors); + + runValidSelectorTest("Document", doc, validSelectors, testType, docType); + runValidSelectorTest("Detached Element", detached, validSelectors, testType, docType); + runValidSelectorTest("Fragment", fragment, validSelectors, testType, docType); + + doc.body.appendChild(outOfScope); // Append before in-document Element tests. + // None of these elements should match + runValidSelectorTest("In-document Element", element, validSelectors, testType, docType); +} +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.html new file mode 100644 index 0000000000..7d68e7f297 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.html @@ -0,0 +1,120 @@ +<!DOCTYPE html> +<meta charset="UTF-8"> +<meta name=timeout content=long> +<title>Selectors-API Test Suite: HTML</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="selectors.js"></script> +<script src="ParentNode-querySelector-All.js"></script> +<style>iframe { visibility: hidden; position: absolute; }</style> + +<div id="log">This test requires JavaScript.</div> + +<script> +async_test(function() { + var frame = document.createElement("iframe"); + var self = this; + frame.onload = function() { + // :target doesn't work before a page rendering on some browsers. We run + // tests after an animation frame because it may be later than the first + // page rendering. + requestAnimationFrame(self.step_func_done(init.bind(self, frame))); + }; + frame.src = "ParentNode-querySelector-All-content.html#target"; + document.body.appendChild(frame); +}); + +function init(target) { + /* + * This test suite tests Selectors API methods in 4 different contexts: + * 1. Document node + * 2. In-document Element node + * 3. Detached Element node (an element with no parent, not in the document) + * 4. Document Fragment node + * + * For each context, the following tests are run: + * + * The interface check tests ensure that each type of node exposes the Selectors API methods + * + * The special selector tests verify the result of passing special values for the selector parameter, + * to ensure that the correct WebIDL processing is performed, such as stringification of null and + * undefined and missing parameter. The universal selector is also tested here, rather than with the + * rest of ordinary selectors for practical reasons. + * + * The static list verification tests ensure that the node lists returned by the method remain unchanged + * due to subsequent document modication, and that a new list is generated each time the method is + * invoked based on the current state of the document. + * + * The invalid selector tests ensure that SyntaxError is thrown for invalid forms of selectors + * + * The valid selector tests check the result from querying many different types of selectors, with a + * list of expected elements. This checks that querySelector() always returns the first result from + * querySelectorAll(), and that all matching elements are correctly returned in tree-order. The tests + * can be limited by specifying the test types to run, using the testType variable. The constants for this + * can be found in selectors.js. + * + * All the selectors tested for both the valid and invalid selector tests are found in selectors.js. + * See comments in that file for documentation of the format used. + * + * The ParentNode-querySelector-All.js file contains all the common test functions for running each of the aforementioned tests + */ + + var testType = TEST_QSA; + var docType = "html"; // Only run tests suitable for HTML + + // Prepare the nodes for testing + var doc = target.contentDocument; // Document Node tests + + var element = doc.getElementById("root"); // In-document Element Node tests + + //Setup the namespace tests + setupSpecialElements(doc, element); + + var outOfScope = element.cloneNode(true); // Append this to the body before running the in-document + // Element tests, but after running the Document tests. This + // tests that no elements that are not descendants of element + // are selected. + + traverse(outOfScope, function(elem) { // Annotate each element as being a clone; used for verifying + elem.setAttribute("data-clone", ""); // that none of these elements ever match. + }); + + + var detached = element.cloneNode(true); // Detached Element Node tests + + var fragment = doc.createDocumentFragment(); // Fragment Node tests + fragment.appendChild(element.cloneNode(true)); + + var empty = document.createElement("div"); // Empty Node tests + + // Setup Tests + interfaceCheck("Document", doc); + interfaceCheck("Detached Element", detached); + interfaceCheck("Fragment", fragment); + interfaceCheck("In-document Element", element); + + runSpecialSelectorTests("Document", doc); + runSpecialSelectorTests("Detached Element", detached); + runSpecialSelectorTests("Fragment", fragment); + runSpecialSelectorTests("In-document Element", element); + + verifyStaticList("Document", doc, doc); + verifyStaticList("Detached Element", doc, detached); + verifyStaticList("Fragment", doc, fragment); + verifyStaticList("In-document Element", doc, element); + + runInvalidSelectorTest("Document", doc, invalidSelectors); + runInvalidSelectorTest("Detached Element", detached, invalidSelectors); + runInvalidSelectorTest("Fragment", fragment, invalidSelectors); + runInvalidSelectorTest("In-document Element", element, invalidSelectors); + runInvalidSelectorTest("Empty Element", empty, invalidSelectors); + + runValidSelectorTest("Document", doc, validSelectors, testType, docType); + runValidSelectorTest("Detached Element", detached, validSelectors, testType, docType); + runValidSelectorTest("Fragment", fragment, validSelectors, testType, docType); + + doc.body.appendChild(outOfScope); // Append before in-document Element tests. + // None of these elements should match + runValidSelectorTest("In-document Element", element, validSelectors, testType, docType); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.js b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.js new file mode 100644 index 0000000000..3c6c503179 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.js @@ -0,0 +1,261 @@ +// Require selectors.js to be included before this. + +/* + * Create and append special elements that cannot be created correctly with HTML markup alone. + */ +function setupSpecialElements(doc, parent) { + // Setup null and undefined tests + parent.appendChild(doc.createElement("null")); + parent.appendChild(doc.createElement("undefined")); + + // Setup namespace tests + var anyNS = doc.createElement("div"); + var noNS = doc.createElement("div"); + anyNS.id = "any-namespace"; + noNS.id = "no-namespace"; + + var divs; + div = [doc.createElement("div"), + doc.createElementNS("http://www.w3.org/1999/xhtml", "div"), + doc.createElementNS("", "div"), + doc.createElementNS("http://www.example.org/ns", "div")]; + + div[0].id = "any-namespace-div1"; + div[1].id = "any-namespace-div2"; + div[2].setAttribute("id", "any-namespace-div3"); // Non-HTML elements can't use .id property + div[3].setAttribute("id", "any-namespace-div4"); + + for (var i = 0; i < div.length; i++) { + anyNS.appendChild(div[i]) + } + + div = [doc.createElement("div"), + doc.createElementNS("http://www.w3.org/1999/xhtml", "div"), + doc.createElementNS("", "div"), + doc.createElementNS("http://www.example.org/ns", "div")]; + + div[0].id = "no-namespace-div1"; + div[1].id = "no-namespace-div2"; + div[2].setAttribute("id", "no-namespace-div3"); // Non-HTML elements can't use .id property + div[3].setAttribute("id", "no-namespace-div4"); + + for (i = 0; i < div.length; i++) { + noNS.appendChild(div[i]) + } + + parent.appendChild(anyNS); + parent.appendChild(noNS); + + var span = doc.getElementById("attr-presence-i1"); + span.setAttributeNS("http://www.example.org/ns", "title", ""); +} + +/* + * Check that the querySelector and querySelectorAll methods exist on the given Node + */ +function interfaceCheck(type, obj) { + test(function() { + var q = typeof obj.querySelector === "function"; + assert_true(q, type + " supports querySelector."); + }, type + " supports querySelector") + + test(function() { + var qa = typeof obj.querySelectorAll === "function"; + assert_true( qa, type + " supports querySelectorAll."); + }, type + " supports querySelectorAll") + + test(function() { + var list = obj.querySelectorAll("div"); + if (obj.ownerDocument) { // The object is not a Document + assert_true(list instanceof obj.ownerDocument.defaultView.NodeList, "The result should be an instance of a NodeList") + } else { // The object is a Document + assert_true(list instanceof obj.defaultView.NodeList, "The result should be an instance of a NodeList") + } + }, type + ".querySelectorAll returns NodeList instance") +} + +/* + * Verify that the NodeList returned by querySelectorAll is static and and that a new list is created after + * each call. A static list should not be affected by subsequent changes to the DOM. + */ +function verifyStaticList(type, doc, root) { + var pre, post, preLength; + + test(function() { + pre = root.querySelectorAll("div"); + preLength = pre.length; + + var div = doc.createElement("div"); + (root.body || root).appendChild(div); + + assert_equals(pre.length, preLength, "The length of the NodeList should not change.") + }, type + ": static NodeList") + + test(function() { + post = root.querySelectorAll("div"), + assert_equals(post.length, preLength + 1, "The length of the new NodeList should be 1 more than the previous list.") + }, type + ": new NodeList") +} + +/* + * Verify handling of special values for the selector parameter, including stringification of + * null and undefined, and the handling of the empty string. + */ +function runSpecialSelectorTests(type, root) { + let global = (root.ownerDocument || root).defaultView; + + test(function() { // 1 + assert_equals(root.querySelectorAll(null).length, 1, "This should find one element with the tag name 'NULL'."); + }, type + ".querySelectorAll null") + + test(function() { // 2 + assert_equals(root.querySelectorAll(undefined).length, 1, "This should find one element with the tag name 'UNDEFINED'."); + }, type + ".querySelectorAll undefined") + + test(function() { // 3 + assert_throws_js(global.TypeError, function() { + root.querySelectorAll(); + }, "This should throw a TypeError.") + }, type + ".querySelectorAll no parameter") + + test(function() { // 4 + var elm = root.querySelector(null) + assert_not_equals(elm, null, "This should find an element."); + assert_equals(elm.tagName.toUpperCase(), "NULL", "The tag name should be 'NULL'.") + }, type + ".querySelector null") + + test(function() { // 5 + var elm = root.querySelector(undefined) + assert_not_equals(elm, undefined, "This should find an element."); + assert_equals(elm.tagName.toUpperCase(), "UNDEFINED", "The tag name should be 'UNDEFINED'.") + }, type + ".querySelector undefined") + + test(function() { // 6 + assert_throws_js(global.TypeError, function() { + root.querySelector(); + }, "This should throw a TypeError.") + }, type + ".querySelector no parameter") + + test(function() { // 7 + result = root.querySelectorAll("*"); + var i = 0; + traverse(root, function(elem) { + if (elem !== root) { + assert_equals(elem, result[i], "The result in index " + i + " should be in tree order."); + i++; + } + }) + }, type + ".querySelectorAll tree order"); +} + +/* + * Execute queries with the specified valid selectors for both querySelector() and querySelectorAll() + * Only run these tests when results are expected. Don't run for syntax error tests. + */ +function runValidSelectorTest(type, root, selectors, testType, docType) { + var nodeType = ""; + switch (root.nodeType) { + case Node.DOCUMENT_NODE: + nodeType = "document"; + break; + case Node.ELEMENT_NODE: + nodeType = root.parentNode ? "element" : "detached"; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + nodeType = "fragment"; + break; + default: + assert_unreached(); + nodeType = "unknown"; // This should never happen. + } + + for (var i = 0; i < selectors.length; i++) { + var s = selectors[i]; + var n = s["name"]; + var q = s["selector"]; + var e = s["expect"]; + + if ((!s["exclude"] || (s["exclude"].indexOf(nodeType) === -1 && s["exclude"].indexOf(docType) === -1)) + && (s["testType"] & testType) ) { + var foundall, found; + + test(function() { + foundall = root.querySelectorAll(q); + assert_not_equals(foundall, null, "The method should not return null.") + assert_equals(foundall.length, e.length, "The method should return the expected number of matches.") + + for (var i = 0; i < e.length; i++) { + assert_not_equals(foundall[i], null, "The item in index " + i + " should not be null.") + assert_equals(foundall[i].getAttribute("id"), e[i], "The item in index " + i + " should have the expected ID."); + assert_false(foundall[i].hasAttribute("data-clone"), "This should not be a cloned element."); + } + }, type + ".querySelectorAll: " + n + ": " + q); + + test(function() { + found = root.querySelector(q); + + if (e.length > 0) { + assert_not_equals(found, null, "The method should return a match.") + assert_equals(found.getAttribute("id"), e[0], "The method should return the first match."); + assert_equals(found, foundall[0], "The result should match the first item from querySelectorAll."); + assert_false(found.hasAttribute("data-clone"), "This should not be annotated as a cloned element."); + } else { + assert_equals(found, null, "The method should not match anything."); + } + }, type + ".querySelector: " + n + ": " + q); + } + } +} + +function windowFor(root) { + return root.defaultView || root.ownerDocument.defaultView; +} + +/* + * Execute queries with the specified invalid selectors for both querySelector() and querySelectorAll() + * Only run these tests when errors are expected. Don't run for valid selector tests. + */ +function runInvalidSelectorTest(type, root, selectors) { + for (var i = 0; i < selectors.length; i++) { + var s = selectors[i]; + var n = s["name"]; + var q = s["selector"]; + + test(function() { + assert_throws_dom("SyntaxError", windowFor(root).DOMException, function() { + root.querySelector(q) + }); + }, type + ".querySelector: " + n + ": " + q); + + test(function() { + assert_throws_dom("SyntaxError", windowFor(root).DOMException, function() { + root.querySelectorAll(q) + }); + }, type + ".querySelectorAll: " + n + ": " + q); + } +} + +function traverse(elem, fn) { + if (elem.nodeType === elem.ELEMENT_NODE) { + fn(elem); + } + elem = elem.firstChild; + while (elem) { + traverse(elem, fn); + elem = elem.nextSibling; + } +} + +function getNodeType(node) { + switch (node.nodeType) { + case Node.DOCUMENT_NODE: + return "document"; + case Node.ELEMENT_NODE: + return node.parentNode ? "element" : "detached"; + case Node.DOCUMENT_FRAGMENT_NODE: + return "fragment"; + default: + assert_unreached(); + return "unknown"; // This should never happen. + } +} diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-case-insensitive.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-case-insensitive.html new file mode 100644 index 0000000000..e461ee5016 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-case-insensitive.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) must work with the i and *= selectors</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2551 --> + +<input name="User" id="testInput"></input> + +<script> +"use strict"; +const input = document.getElementById("testInput"); + +test(() => { + assert_equals(document.querySelector("input[name*=user i]"), input); +}, "querySelector"); + +test(() => { + assert_array_equals(document.querySelectorAll("input[name*=user i]"), [input]); +}, "querySelectorAll"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-escapes.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-escapes.html new file mode 100644 index 0000000000..65a75e5c03 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-escapes.html @@ -0,0 +1,123 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>querySelector() with CSS escapes</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-parentnode-queryselector"> +<link rel="help" href="https://drafts.csswg.org/css-syntax/#consume-escaped-code-point"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="author" title="bellbind" href="mailto:bellbind@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +function testMatched(id, selector) { + test(() => { + const container = document.createElement("div"); + const child = document.createElement("span"); + child.id = id; + + container.appendChild(child); + + assert_equals(container.querySelector(selector), child); + }, `${JSON.stringify(id)} should match with ${JSON.stringify(selector)}`); +} + +function testNeverMatched(id, selector) { + test(() => { + const container = document.createElement("div"); + const child = document.createElement("span"); + child.id = id; + + container.appendChild(child); + + assert_equals(container.querySelector(selector), null); + }, `${JSON.stringify(id)} should never match with ${JSON.stringify(selector)}`); +} + +// 4.3.7 from https://drafts.csswg.org/css-syntax/#consume-escaped-code-point +testMatched("nonescaped", "#nonescaped"); + +// - escape hex digit +testMatched("0nextIsWhiteSpace", "#\\30 nextIsWhiteSpace"); +testMatched("0nextIsNotHexLetters", "#\\30nextIsNotHexLetters"); +testMatched("0connectHexMoreThan6Hex", "#\\000030connectHexMoreThan6Hex"); +testMatched("0spaceMoreThan6Hex", "#\\000030 spaceMoreThan6Hex"); + +// - hex digit special replacement +// 1. zero points +testMatched("zero\u{fffd}", "#zero\\0"); +testNeverMatched("zero\u{0}", "#zero\\0"); +testMatched("zero\u{fffd}", "#zero\\000000"); +testNeverMatched("zero\u{0}", "#zero\\000000"); +// 2. surrogate points +testMatched("\u{fffd}surrogateFirst", "#\\d83d surrogateFirst"); +testNeverMatched("\ud83dsurrogateFirst", "#\\d83d surrogateFirst"); +testMatched("surrogateSecond\u{fffd}", "#surrogateSecond\\dd11"); +testNeverMatched("surrogateSecond\udd11", "#surrogateSecond\\dd11"); +testMatched("surrogatePair\u{fffd}\u{fffd}", "#surrogatePair\\d83d\\dd11"); +testNeverMatched("surrogatePair\u{1f511}", "#surrogatePair\\d83d\\dd11"); +// 3. out of range points +testMatched("outOfRange\u{fffd}", "#outOfRange\\110000"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\110030"); +testNeverMatched("outOfRange\u{30}", "#outOfRange\\110030"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\555555"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\ffffff"); + +// - escape EOF +testNeverMatched("eof\\", "#eof\\"); + +// - escape anythong else +testMatched(".comma", "#\\.comma"); +testMatched("-minus", "#\\-minus"); +testMatched("g", "#\\g"); + +// non edge cases +testMatched("aBMPRegular", "#\\61 BMPRegular"); +testMatched("\u{1f511}nonBMP", "#\\1f511 nonBMP"); +testMatched("00continueEscapes", "#\\30\\30 continueEscapes"); +testMatched("00continueEscapes", "#\\30 \\30 continueEscapes"); +testMatched("continueEscapes00", "#continueEscapes\\30 \\30 "); +testMatched("continueEscapes00", "#continueEscapes\\30 \\30"); +testMatched("continueEscapes00", "#continueEscapes\\30\\30 "); +testMatched("continueEscapes00", "#continueEscapes\\30\\30"); + +// ident tests case from CSS tests of chromium source: https://goo.gl/3Cxdov +testMatched("hello", "#hel\\6Co"); +testMatched("&B", "#\\26 B"); +testMatched("hello", "#hel\\6C o"); +testMatched("spaces", "#spac\\65\r\ns"); +testMatched("spaces", "#sp\\61\tc\\65\fs"); +testMatched("test\u{D799}", "#test\\D799"); +testMatched("\u{E000}", "#\\E000"); +testMatched("test", "#te\\s\\t"); +testMatched("spaces in\tident", "#spaces\\ in\\\tident"); +testMatched(".,:!", "#\\.\\,\\:\\!"); +testMatched("null\u{fffd}", "#null\\0"); +testMatched("null\u{fffd}", "#null\\0000"); +testMatched("large\u{fffd}", "#large\\110000"); +testMatched("large\u{fffd}", "#large\\23456a"); +testMatched("surrogate\u{fffd}", "#surrogate\\D800"); +testMatched("surrogate\u{fffd}", "#surrogate\\0DBAC"); +testMatched("\u{fffd}surrogate", "#\\00DFFFsurrogate"); +testMatched("\u{10ffff}", "#\\10fFfF"); +testMatched("\u{10ffff}0", "#\\10fFfF0"); +testMatched("\u{100000}00", "#\\10000000"); +testMatched("eof\u{fffd}", "#eof\\"); + +testMatched("simple-ident", "#simple-ident"); +testMatched("testing123", "#testing123"); +testMatched("_underscore", "#_underscore"); +testMatched("-text", "#-text"); +testMatched("-m", "#-\\6d"); +testMatched("--abc", "#--abc"); +testMatched("--", "#--"); +testMatched("--11", "#--11"); +testMatched("---", "#---"); +testMatched("\u{2003}", "#\u{2003}"); +testMatched("\u{A0}", "#\u{A0}"); +testMatched("\u{1234}", "#\u{1234}"); +testMatched("\u{12345}", "#\u{12345}"); +testMatched("\u{fffd}", "#\u{0}"); +testMatched("ab\u{fffd}c", "#ab\u{0}c"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-scope.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-scope.html new file mode 100644 index 0000000000..d984956d6c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelector-scope.html @@ -0,0 +1,33 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) scoped to a root element</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div><h1 id="test"></h1><p><span>hello</span></p></div> + +<script> +"use strict"; +const div = document.querySelector("div"); +const p = document.querySelector("p"); + +test(() => { + assert_equals(div.querySelector(":scope > p"), p); + assert_equals(div.querySelector(":scope > span"), null); +}, "querySelector with :scope"); + +test(() => { + assert_equals(div.querySelector("#test + p"), p); + assert_equals(p.querySelector("#test + p"), null); +}, "querySelector with id and sibling"); + +test(() => { + assert_array_equals(div.querySelectorAll(":scope > p"), [p]); + assert_array_equals(div.querySelectorAll(":scope > span"), []); +}, "querySelectorAll with :scope"); + +test(() => { + assert_array_equals(div.querySelectorAll("#test + p"), [p]); + assert_array_equals(p.querySelectorAll("#test + p"), []); +}, "querySelectorAll with id and sibling"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelectorAll-removed-elements.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectorAll-removed-elements.html new file mode 100644 index 0000000000..3cefc80906 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectorAll-removed-elements.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll must not return removed elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2519 --> + +<div id="container"></div> + +<script> +"use strict"; + +setup({ single_test: true }); + +const container = document.querySelector("#container"); +function getIDs() { + return [...container.querySelectorAll("a.test")].map(el => el.id); +} + +container.innerHTML = `<a id="link-a" class="test">a link</a>`; +assert_array_equals(getIDs(), ["link-a"], "Sanity check: initial setup"); + +container.innerHTML = `<a id="link-b" class="test"><img src="foo.jpg"></a>`; +assert_array_equals(getIDs(), ["link-b"], "After replacement"); + +container.innerHTML = `<a id="link-a" class="test">a link</a>`; +assert_array_equals(getIDs(), ["link-a"], "After changing back to the original HTML"); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-exclusive.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-exclusive.html new file mode 100644 index 0000000000..5cff9367cf --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-exclusive.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector/querySelectorAll should not include their thisArg</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2296 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const button = document.createElement("button"); + +assert_equals(button.querySelector("*"), null, "querySelector, '*', before modification"); +assert_equals(button.querySelector("button"), null, "querySelector, 'button', before modification"); +assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', before modification"); +assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', before modification"); +assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', before modification"); +assert_array_equals( + button.querySelectorAll("button, span"), [], + "querySelectorAll, 'button, span', before modification" +); + + +button.innerHTML = "text"; + +assert_equals(button.querySelector("*"), null, "querySelector, '*', after modification"); +assert_equals(button.querySelector("button"), null, "querySelector, 'button', after modification"); +assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', after modification"); +assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', after modification"); +assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', after modification"); +assert_array_equals( + button.querySelectorAll("button, span"), [], + "querySelectorAll, 'button, span', after modification" +); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-namespaces.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-namespaces.html new file mode 100644 index 0000000000..714999b3f0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-namespaces.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll must work with namespace attribute selectors on SVG</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2028 --> + +<svg id="thesvg" xlink:href="foo"></svg> + +<script> +"use strict"; + +setup({ single_test: true }); + +const el = document.getElementById("thesvg"); + +assert_equals(document.querySelector("[*|href]"), el); +assert_array_equals(document.querySelectorAll("[*|href]"), [el]); + +done(); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html new file mode 100644 index 0000000000..e08c6e6db1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) must work for attribute values that contain spaces and dashes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2542 --> + +<a title="test with - dash and space" id="testme">Test One</a> + +<script> +"use strict"; +const el = document.getElementById("testme"); + +test(() => { + assert_equals(document.querySelector("a[title='test with - dash and space']"), el); +}, "querySelector"); + +test(() => { + assert_equals(document.querySelector("a[title='test with - dash and space']"), el); +}, "querySelectorAll"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html b/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html new file mode 100644 index 0000000000..ee22009fcb --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ParentNode-replaceChildren.html @@ -0,0 +1,205 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>ParentNode.replaceChildren</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-replacechildren"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="pre-insertion-validation-hierarchy.js"></script> +<script> + preInsertionValidateHierarchy("replaceChildren"); + + function test_replacechildren(node, nodeName) { + test(() => { + const parent = node.cloneNode(); + parent.replaceChildren(); + assert_array_equals(parent.childNodes, []); + }, `${nodeName}.replaceChildren() without any argument, on a parent having no child.`); + + test(() => { + const parent = node.cloneNode(); + parent.replaceChildren(null); + assert_equals(parent.childNodes[0].textContent, 'null'); + }, `${nodeName}.replaceChildren() with null as an argument, on a parent having no child.`); + + test(() => { + const parent = node.cloneNode(); + parent.replaceChildren(undefined); + assert_equals(parent.childNodes[0].textContent, 'undefined'); + }, `${nodeName}.replaceChildren() with undefined as an argument, on a parent having no child.`); + + test(() => { + const parent = node.cloneNode(); + parent.replaceChildren('text'); + assert_equals(parent.childNodes[0].textContent, 'text'); + }, `${nodeName}.replaceChildren() with only text as an argument, on a parent having no child.`); + + test(() => { + const parent = node.cloneNode(); + const x = document.createElement('x'); + parent.replaceChildren(x); + assert_array_equals(parent.childNodes, [x]); + }, `${nodeName}.replaceChildren() with only one element as an argument, on a parent having no child.`); + + test(() => { + const parent = node.cloneNode(); + const child = document.createElement('test'); + parent.appendChild(child); + parent.replaceChildren(); + assert_array_equals(parent.childNodes, []); + }, `${nodeName}.replaceChildren() without any argument, on a parent having a child.`); + + test(() => { + const parent = node.cloneNode(); + const child = document.createElement('test'); + parent.appendChild(child); + parent.replaceChildren(null); + assert_equals(parent.childNodes.length, 1); + assert_equals(parent.childNodes[0].textContent, 'null'); + }, `${nodeName}.replaceChildren() with null as an argument, on a parent having a child.`); + + test(() => { + const parent = node.cloneNode(); + const x = document.createElement('x'); + const child = document.createElement('test'); + parent.appendChild(child); + parent.replaceChildren(x, 'text'); + assert_equals(parent.childNodes.length, 2); + assert_equals(parent.childNodes[0], x); + assert_equals(parent.childNodes[1].textContent, 'text'); + }, `${nodeName}.replaceChildren() with one element and text as argument, on a parent having a child.`); + + async_test(t => { + let phase = 0; + + const previousParent = node.cloneNode(); + const insertions = [ + document.createElement("test1"), + document.createElement("test2") + ]; + previousParent.append(...insertions); + + const parent = node.cloneNode(); + const children = [ + document.createElement("test3"), + document.createElement("test4") + ]; + parent.append(...children); + + const previousObserver = new MutationObserver(mutations => { + t.step(() => { + assert_equals(phase, 0); + assert_equals(mutations.length, 2); + for (const [i, mutation] of Object.entries(mutations)) { + assert_equals(mutation.type, "childList"); + assert_equals(mutation.addedNodes.length, 0); + assert_equals(mutation.removedNodes.length, 1); + assert_equals(mutation.removedNodes[0], insertions[i]); + } + phase = 1; + }); + }); + previousObserver.observe(previousParent, { childList: true }); + + const observer = new MutationObserver(mutations => { + t.step(() => { + assert_equals(phase, 1, "phase"); + assert_equals(mutations.length, 1, "mutations.length"); + const mutation = mutations[0]; + assert_equals(mutation.type, "childList", "mutation.type"); + assert_equals(mutation.addedNodes.length, 2, "added nodes length"); + assert_array_equals([...mutation.addedNodes], insertions, "added nodes"); + assert_equals(mutation.removedNodes.length, 2, "removed nodes length"); + assert_array_equals([...mutation.removedNodes], children, "removed nodes"); + }); + t.done(); + }); + observer.observe(parent, { childList: true }); + + parent.replaceChildren(...previousParent.children); + }, `${nodeName}.replaceChildren() should move nodes in the right order`); + } + + test_replacechildren(document.createElement('div'), 'Element'); + test_replacechildren(document.createDocumentFragment(), 'DocumentFragment'); + + async_test(t => { + let root = document.createElement("div"); + root.innerHTML = "<div id='a'>text<div id='b'>text2</div></div>"; + const a = root.firstChild; + const b = a.lastChild; + const txt = b.previousSibling; + const txt2 = b.firstChild; + + const observer = new MutationObserver((mutations) => { + + assert_equals(mutations.length, 2, "mutations.length"); + + assert_equals(mutations[0].target.id, "a", "Target of the removal"); + assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes"); + assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node"); + assert_equals(mutations[0].removedNodes[0], txt, "Should have removed txt node"); + + assert_equals(mutations[1].target.id, "b", "Target of the replaceChildren"); + assert_equals(mutations[1].removedNodes.length, 1, "Should have removed 1 node"); + assert_equals(mutations[1].removedNodes[0], txt2, "Should have removed txt2 node"); + assert_equals(mutations[1].addedNodes.length, 1, "Should have added a node"); + assert_equals(mutations[1].addedNodes[0], txt, "Should have added txt node"); + + observer.disconnect(); + t.done(); + }); + + observer.observe(a, { + subtree: true, + childList: true + }); + + b.replaceChildren(txt); + }, "There should be a MutationRecord for the node removed from another parent node."); + + async_test(t => { + // This is almost the same test as above, but passes two nodes to replaceChildren. + + let root = document.createElement("div"); + root.innerHTML = "<div id='a'><div id='c'></div>text<div id='b'>text2</div></div>"; + const a = root.firstChild; + const b = a.lastChild; + const c = a.firstChild; + const txt = b.previousSibling; + const txt2 = b.firstChild; + + const observer = new MutationObserver((mutations) => { + + assert_equals(mutations.length, 3, "mutations.length"); + + assert_equals(mutations[0].target.id, "a", "Target of the removal"); + assert_equals(mutations[0].addedNodes.length, 0, "Should not have added nodes"); + assert_equals(mutations[0].removedNodes.length, 1, "Should have 1 removed node"); + assert_equals(mutations[0].removedNodes[0], c, "Should have removed c node"); + + assert_equals(mutations[1].target.id, "a", "Target of the removal"); + assert_equals(mutations[1].addedNodes.length, 0, "Should not have added nodes"); + assert_equals(mutations[1].removedNodes.length, 1, "Should have 1 removed node"); + assert_equals(mutations[1].removedNodes[0], txt, "Should have removed txt node"); + + assert_equals(mutations[2].target.id, "b", "Target of the replaceChildren"); + assert_equals(mutations[2].removedNodes.length, 1, "Should have removed 1 node"); + assert_equals(mutations[2].removedNodes[0], txt2, "Should have removed txt2 node"); + assert_equals(mutations[2].addedNodes.length, 2, "Should have added a node"); + assert_equals(mutations[2].addedNodes[0], c, "Should have added c node"); + assert_equals(mutations[2].addedNodes[1], txt, "Should have added txt node"); + + observer.disconnect(); + t.done(); + }); + + observer.observe(a, { + subtree: true, + childList: true + }); + + b.replaceChildren(c, txt); + }, "There should be MutationRecords for the nodes removed from another parent node."); +</script> + +</html> diff --git a/testing/web-platform/tests/dom/nodes/ProcessingInstruction-escapes-1.xhtml b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-escapes-1.xhtml new file mode 100644 index 0000000000..d629a8464b --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-escapes-1.xhtml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?xml-stylesheet href="support/style.css" type="text/css"?> +<?xml-stylesheet href="data:text/css,A&'" type="text/css"?> +<?xml-stylesheet href="data:text/css,A&'" type="text/css"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>ProcessingInstruction numeric escapes</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-processinginstruction-target"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-characterdata-data"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +<![CDATA[ +test(function() { + var pienc = document.firstChild.nextSibling; + assert_true(pienc instanceof ProcessingInstruction) + assert_equals(pienc.target, "xml-stylesheet") + assert_equals(pienc.data, 'href="data:text/css,A&'" type="text/css"') + assert_equals(pienc.sheet.href, "data:text/css,A&'"); + + pienc = pienc.nextSibling; + assert_true(pienc instanceof ProcessingInstruction) + assert_equals(pienc.target, "xml-stylesheet") + assert_equals(pienc.data, 'href="data:text/css,A&'" type="text/css"') + assert_equals(pienc.sheet.href, "data:text/css,A&'"); +}) +]]> +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-1.xhtml b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-1.xhtml new file mode 100644 index 0000000000..4eaf86cbdc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-1.xhtml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title><?xml?> is not a ProcessingInstruction</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +test(function() { + assert_equals(document.firstChild, document.documentElement) +}) +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-2.xhtml b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-2.xhtml new file mode 100644 index 0000000000..d878c697c0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/ProcessingInstruction-literal-2.xhtml @@ -0,0 +1,21 @@ +<?xml-stylesheet href="support/style.css" type="text/css"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>ProcessingInstruction literals</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-processinginstruction-target"/> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-characterdata-data"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"/> +<script> +test(function() { + var pienc = document.firstChild; + assert_true(pienc instanceof ProcessingInstruction) + assert_equals(pienc.target, "xml-stylesheet") + assert_equals(pienc.data, 'href="support/style.css" type="text/css"') +}) +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/Text-constructor.html b/testing/web-platform/tests/dom/nodes/Text-constructor.html new file mode 100644 index 0000000000..dbd9a0be01 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Text-constructor.html @@ -0,0 +1,11 @@ +<!doctype html> +<meta charset=utf-8> +<title>Text constructor</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-text"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="Comment-Text-constructor.js"></script> +<div id="log"></div> +<script> +test_constructor("Text"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Text-splitText.html b/testing/web-platform/tests/dom/nodes/Text-splitText.html new file mode 100644 index 0000000000..2dd23018cb --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Text-splitText.html @@ -0,0 +1,53 @@ +<!doctype html> +<meta charset=utf-8> +<title>Text.splitText()</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-text-splittextoffset"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var text = document.createTextNode("camembert"); + assert_throws_dom("INDEX_SIZE_ERR", function () { text.splitText(10) }); +}, "Split text after end of data"); + +test(function() { + var text = document.createTextNode(""); + var new_text = text.splitText(0); + assert_equals(text.data, ""); + assert_equals(new_text.data, ""); +}, "Split empty text"); + +test(function() { + var text = document.createTextNode("comté"); + var new_text = text.splitText(0); + assert_equals(text.data, ""); + assert_equals(new_text.data, "comté"); +}, "Split text at beginning"); + +test(function() { + var text = document.createTextNode("comté"); + var new_text = text.splitText(5); + assert_equals(text.data, "comté"); + assert_equals(new_text.data, ""); +}, "Split text at end"); + +test(function() { + var text = document.createTextNode("comté"); + var new_text = text.splitText(3); + assert_equals(text.data, "com"); + assert_equals(new_text.data, "té"); + assert_equals(new_text.parentNode, null); +}, "Split root"); + +test(function() { + var parent = document.createElement('div'); + var text = document.createTextNode("bleu"); + parent.appendChild(text); + var new_text = text.splitText(2); + assert_equals(text.data, "bl"); + assert_equals(new_text.data, "eu"); + assert_equals(text.nextSibling, new_text); + assert_equals(new_text.parentNode, parent); +}, "Split child"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/Text-wholeText.html b/testing/web-platform/tests/dom/nodes/Text-wholeText.html new file mode 100644 index 0000000000..2467930da8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/Text-wholeText.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Text - wholeText</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-text-wholetext"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +"use strict"; + +test(() => { + const parent = document.createElement("div"); + + const t1 = document.createTextNode("a"); + const t2 = document.createTextNode("b"); + const t3 = document.createTextNode("c"); + + assert_equals(t1.wholeText, t1.textContent); + + parent.appendChild(t1); + + assert_equals(t1.wholeText, t1.textContent); + + parent.appendChild(t2); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent); + + parent.appendChild(t3); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent + t3.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent + t3.textContent); + assert_equals(t3.wholeText, t1.textContent + t2.textContent + t3.textContent); + + const a = document.createElement("a"); + a.textContent = "I'm an Anchor"; + parent.insertBefore(a, t3); + + const span = document.createElement("span"); + span.textContent = "I'm a Span"; + parent.appendChild(document.createElement("span")); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent); + assert_equals(t3.wholeText, t3.textContent); +}, "wholeText returns text of all Text nodes logically adjacent to the node, in document order."); +</script> diff --git a/testing/web-platform/tests/dom/nodes/adoption.window.js b/testing/web-platform/tests/dom/nodes/adoption.window.js new file mode 100644 index 0000000000..ad90aaf375 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/adoption.window.js @@ -0,0 +1,58 @@ +// Testing DocumentFragment with host separately as it has a different node document by design +test(() => { + const df = document.createElement("template").content; + const child = df.appendChild(new Text('hi')); + assert_not_equals(df.ownerDocument, document); + const nodeDocument = df.ownerDocument; + document.body.appendChild(df); + assert_equals(df.childNodes.length, 0); + assert_equals(child.ownerDocument, document); + assert_equals(df.ownerDocument, nodeDocument); +}, `appendChild() and DocumentFragment with host`); + +test(() => { + const df = document.createElement("template").content; + const child = df.appendChild(new Text('hi')); + const nodeDocument = df.ownerDocument; + document.adoptNode(df); + assert_equals(df.childNodes.length, 1); + assert_equals(child.ownerDocument, nodeDocument); + assert_equals(df.ownerDocument, nodeDocument); +}, `adoptNode() and DocumentFragment with host`); + +[ + { + "name": "DocumentFragment", + "creator": doc => doc.createDocumentFragment() + }, + { + "name": "ShadowRoot", + "creator": doc => doc.createElementNS("http://www.w3.org/1999/xhtml", "div").attachShadow({mode: "closed"}) + } +].forEach(dfTest => { + test(() => { + const doc = new Document(); + const df = dfTest.creator(doc); + const child = df.appendChild(new Text('hi')); + assert_equals(df.ownerDocument, doc); + + document.body.appendChild(df); + assert_equals(df.childNodes.length, 0); + assert_equals(child.ownerDocument, document); + assert_equals(df.ownerDocument, doc); + }, `appendChild() and ${dfTest.name}`); + + test(() => { + const doc = new Document(); + const df = dfTest.creator(doc); + const child = df.appendChild(new Text('hi')); + if (dfTest.name === "ShadowRoot") { + assert_throws_dom("HierarchyRequestError", () => document.adoptNode(df)); + } else { + document.adoptNode(df); + assert_equals(df.childNodes.length, 1); + assert_equals(child.ownerDocument, document); + assert_equals(df.ownerDocument, document); + } + }, `adoptNode() and ${dfTest.name}`); +}); diff --git a/testing/web-platform/tests/dom/nodes/append-on-Document.html b/testing/web-platform/tests/dom/nodes/append-on-Document.html new file mode 100644 index 0000000000..78f278b381 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/append-on-Document.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>DocumentType.append</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-append"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function test_append_on_Document() { + + var node = document.implementation.createDocument(null, null); + test(function() { + var parent = node.cloneNode(); + parent.append(); + assert_array_equals(parent.childNodes, []); + }, 'Document.append() without any argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + parent.append(x); + assert_array_equals(parent.childNodes, [x]); + }, 'Document.append() with only one element as an argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(x); + assert_throws_dom('HierarchyRequestError', function() { parent.append(y); }); + assert_array_equals(parent.childNodes, [x]); + }, 'Document.append() with only one element as an argument, on a Document having one child.'); + + test(function() { + var parent = node.cloneNode(); + assert_throws_dom('HierarchyRequestError', function() { parent.append('text'); }); + assert_array_equals(parent.childNodes, []); + }, 'Document.append() with text as an argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + var y = document.createElement('y'); + assert_throws_dom('HierarchyRequestError', function() { parent.append(x, y); }); + assert_array_equals(parent.childNodes, []); + }, 'Document.append() with two elements as the argument, on a Document having no child.'); + +} + +test_append_on_Document(); + +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/attributes-namednodemap.html b/testing/web-platform/tests/dom/nodes/attributes-namednodemap.html new file mode 100644 index 0000000000..96f9d30703 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/attributes-namednodemap.html @@ -0,0 +1,120 @@ +<!DOCTYPE HTML> +<title>Tests of some tricky semantics around NamedNodeMap and the element.attributes collection</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://dom.spec.whatwg.org/#interface-namednodemap"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-element-attributes"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const element = document.createElement("div"); + element.setAttribute("x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute set by setAttribute should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + const map = element.attributes; + + assert_equals(map.length, 0); + + const attr1 = document.createAttribute("attr1"); + map.setNamedItem(attr1); + assert_equals(map.attr1, attr1); + assert_equals(map.length, 1); + + const attr2 = document.createAttribute("attr2"); + map.setNamedItem(attr2); + assert_equals(map.attr2, attr2); + assert_equals(map.length, 2); + + const rm1 = map.removeNamedItem("attr1"); + assert_equals(rm1, attr1); + assert_equals(map.length, 1); + + const rm2 = map.removeNamedItem("attr2"); + assert_equals(rm2, attr2); + assert_equals(map.length, 0); + +}, "setNamedItem and removeNamedItem on `attributes` should add and remove fields from `attributes`"); + +test(() => { + + const element = document.createElement("div"); + const map = element.attributes; + + const fooAttribute = document.createAttribute("foo"); + map.setNamedItem(fooAttribute); + + const itemAttribute = document.createAttribute("item"); + map.setNamedItem(itemAttribute); + + assert_equals(map.foo, fooAttribute); + assert_equals(map.item, NamedNodeMap.prototype.item); + assert_equals(typeof map.item, "function"); + + map.removeNamedItem("item"); + assert_equals(map.item, NamedNodeMap.prototype.item); + assert_equals(typeof map.item, "function"); + +}, "setNamedItem and removeNamedItem on `attributes` should not interfere with existing method names"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS(null, "x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute with a null namespace should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute with a set namespace should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "setNamedItem", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(typeof element.attributes.setNamedItem, "function"); + +}, "setting an attribute should not overwrite the methods of an `NamedNodeMap` object"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "toString", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(typeof element.attributes.toString, "function"); + +}, "setting an attribute should not overwrite the methods defined by prototype ancestors of an `NamedNodeMap` object"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "length", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + +}, "setting an attribute should not overwrite the the length property of an `NamedNodeMap` object"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/attributes.html b/testing/web-platform/tests/dom/nodes/attributes.html new file mode 100644 index 0000000000..c6db7eb8aa --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/attributes.html @@ -0,0 +1,858 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Attributes tests</title> +<link rel=help href="https://dom.spec.whatwg.org/#attr"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattributens"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="attributes.js"></script> +<script src="productions.js"></script> +<div id="log"></div> +<span id="test1"></span> +<span class="&<>foo"></span> +<span id="test2"> + <span ~=""></span> + <span ~></span> + <span></span> +</span> +<script> +var XML = "http://www.w3.org/XML/1998/namespace" +var XMLNS = "http://www.w3.org/2000/xmlns/" + +// toggleAttribute exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], true) }) + } + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i]) }) + } + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.toggleAttribute(invalid_names[i], false) }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (toggleAttribute)") +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~", false) + }) + } + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~") + }) + } + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].toggleAttribute("~", true) + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (toggleAttribute)") + +// Step 2 +test(function() { + var el = document.createElement("div") + assert_true(el.toggleAttribute("ALIGN")) + assert_true(!el.hasAttributeNS("", "ALIGN")) + assert_true(el.hasAttributeNS("", "align")) + assert_true(el.hasAttribute("align")) + assert_true(!el.toggleAttribute("ALIGN")) + assert_true(!el.hasAttributeNS("", "ALIGN")) + assert_true(!el.hasAttributeNS("", "align")) + assert_true(!el.hasAttribute("align")) +}, "toggleAttribute should lowercase its name argument (upper case attribute)") +test(function() { + var el = document.createElement("div") + assert_true(el.toggleAttribute("CHEEseCaKe")) + assert_true(!el.hasAttributeNS("", "CHEEseCaKe")) + assert_true(el.hasAttributeNS("", "cheesecake")) + assert_true(el.hasAttribute("cheesecake")) +}, "toggleAttribute should lowercase its name argument (mixed case attribute)") + +// Step 3 +test(function() { + var el = document.createElement("foo") + var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"] + for (var i = 0; i < tests.length; i++) { + assert_true(el.toggleAttribute(tests[i])); + assert_true(el.hasAttribute(tests[i])); + } +}, "toggleAttribute should not throw even when qualifiedName starts with 'xmlns'") + +// Step 4 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < valid_names.length; i++) { + assert_true(el.toggleAttribute(valid_names[i])) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(!el.toggleAttribute(valid_names[i])) + assert_true(!el.hasAttribute(valid_names[i])) + // Check using force attr + assert_true(el.toggleAttribute(valid_names[i], true)) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(el.toggleAttribute(valid_names[i], true)) + assert_true(el.hasAttribute(valid_names[i])) + assert_true(!el.toggleAttribute(valid_names[i], false)) + assert_true(!el.hasAttribute(valid_names[i])) + } +}, "Basic functionality should be intact. (toggleAttribute)") + +// Step 5 +test(function() { + var el = document.createElement("foo") + el.toggleAttribute("a") + el.toggleAttribute("b") + el.setAttribute("a", "thing") + el.toggleAttribute("c") + attributes_are(el, [["a", "thing"], + ["b", ""], + ["c", ""]]) +}, "toggleAttribute should not change the order of previously set attributes.") +test(function() { + var el = document.createElement("baz") + el.setAttributeNS("ab", "attr", "fail") + el.setAttributeNS("kl", "attr", "pass") + el.toggleAttribute("attr") + attributes_are(el, [["attr", "pass", "kl"]]) +}, "toggleAttribute should set the first attribute with the given name") +test(function() { + // Based on a test by David Flanagan. + var el = document.createElement("baz") + el.setAttributeNS("foo", "foo:bar", "1"); + el.setAttributeNS("foo", "foo:bat", "2"); + assert_equals(el.getAttribute("foo:bar"), "1") + assert_equals(el.getAttribute("foo:bat"), "2") + attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar") + attr_is(el.attributes[1], "2", "bat", "foo", "foo", "foo:bat") + el.toggleAttribute("foo:bar"); + assert_true(!el.hasAttribute("foo:bar")) + attr_is(el.attributes[0], "2", "bat", "foo", "foo", "foo:bat") +}, "toggleAttribute should set the attribute with the given qualified name") + +test(function() { + var el = document.createElement("foo") + el.style = "color: red; background-color: green" + assert_equals(el.toggleAttribute("style"), false) +}, "Toggling element with inline style should make inline style disappear") + +// setAttribute exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < invalid_names.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { el.setAttribute(invalid_names[i], "test") }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (setAttribute)") +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].setAttribute("~", "test") + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (setAttribute)") + +// Step 2 +test(function() { + var el = document.createElement("div") + el.setAttribute("ALIGN", "left") + assert_equals(el.getAttributeNS("", "ALIGN"), null) + assert_equals(el.getAttributeNS("", "align"), "left") + assert_equals(el.getAttribute("align"), "left") +}, "setAttribute should lowercase its name argument (upper case attribute)") +test(function() { + var el = document.createElement("div") + el.setAttribute("CHEEseCaKe", "tasty") + assert_equals(el.getAttributeNS("", "CHEEseCaKe"), null) + assert_equals(el.getAttributeNS("", "cheesecake"), "tasty") + assert_equals(el.getAttribute("cheesecake"), "tasty") +}, "setAttribute should lowercase its name argument (mixed case attribute)") + +// Step 3 +test(function() { + var el = document.createElement("foo") + var tests = ["xmlns", "xmlns:a", "xmlnsx", "xmlns0"] + for (var i = 0; i < tests.length; i++) { + el.setAttribute(tests[i], "success"); + } +}, "setAttribute should not throw even when qualifiedName starts with 'xmlns'") + +// Step 4 +test(function() { + var el = document.createElement("foo") + for (var i = 0; i < valid_names.length; i++) { + el.setAttribute(valid_names[i], "test") + assert_equals(el.getAttribute(valid_names[i]), "test") + } +}, "Basic functionality should be intact.") + +// Step 5 +test(function() { + var el = document.createElement("foo") + el.setAttribute("a", "1") + el.setAttribute("b", "2") + el.setAttribute("a", "3") + el.setAttribute("c", "4") + attributes_are(el, [["a", "3"], + ["b", "2"], + ["c", "4"]]) +}, "setAttribute should not change the order of previously set attributes.") +test(function() { + var el = document.createElement("baz") + el.setAttributeNS("ab", "attr", "fail") + el.setAttributeNS("kl", "attr", "pass") + el.setAttribute("attr", "pass") + attributes_are(el, [["attr", "pass", "ab"], + ["attr", "pass", "kl"]]) +}, "setAttribute should set the first attribute with the given name") +test(function() { + // Based on a test by David Flanagan. + var el = document.createElement("baz") + el.setAttributeNS("foo", "foo:bar", "1"); + assert_equals(el.getAttribute("foo:bar"), "1") + attr_is(el.attributes[0], "1", "bar", "foo", "foo", "foo:bar") + el.setAttribute("foo:bar", "2"); + assert_equals(el.getAttribute("foo:bar"), "2") + attr_is(el.attributes[0], "2", "bar", "foo", "foo", "foo:bar") +}, "setAttribute should set the attribute with the given qualified name") + +// setAttributeNS exhaustive tests +// Step 1 +test(function() { + var el = document.createElement("foo") + for (var i = 0, il = invalid_names.length; i < il; ++i) { + assert_throws_dom("INVALID_CHARACTER_ERR", + function() { el.setAttributeNS("a", invalid_names[i], "fail") }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown. (setAttributeNS)") + +test(function() { + var el = document.getElementById("test2") + for (var i = 0; i < el.children.length; i++) { + assert_throws_dom("INVALID_CHARACTER_ERR", function() { + el.children[i].setAttributeNS(null, "~", "test") + }) + } +}, "When qualifiedName does not match the Name production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown, even if the attribute " + + "is already present. (setAttributeNS)") + +// Step 2 +test(function() { + var el = document.createElement("foo") + for (var i = 0, il = invalid_qnames.length; i < il; ++i) { + assert_throws_dom("INVALID_CHARACTER_ERR", + function() { el.setAttributeNS("a", invalid_qnames[i], "fail") }, + "Expected exception for " + invalid_qnames[i] + ".") + } +}, "When qualifiedName does not match the QName production, an " + + "INVALID_CHARACTER_ERR exception is to be thrown.") + +// Step 3 +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(null, "aa", "bb") + el.setAttributeNS("", "xx", "bb") + attributes_are(el, [["aa", "bb"], + ["xx", "bb"]]) +}, "null and the empty string should result in a null namespace.") + +// Step 4 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("", "aa:bb", "fail") }) + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(null, "aa:bb", "fail") }) +}, "A namespace is required to use a prefix.") + +// Step 5 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xml:bb", "fail") }) +}, "The xml prefix should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XML, "a:bb", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "bb", XML, "a", "a:bb") +}, "XML-namespaced attributes don't need an xml prefix") + +// Step 6 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xmlns:bb", "fail") }) +}, "The xmlns prefix should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS("a", "xmlns", "fail") }) +}, "The xmlns qualified name should not be allowed for arbitrary namespaces") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS("ns", "a:xmlns", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "xmlns", "ns", "a", "a:xmlns") +}, "xmlns should be allowed as local name") + +// Step 7 +test(function() { + var el = document.createElement("foo") + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(XMLNS, "a:xmlns", "fail") }) + assert_throws_dom("NAMESPACE_ERR", + function() { el.setAttributeNS(XMLNS, "b:foo", "fail") }) +}, "The XMLNS namespace should require xmlns as prefix or qualified name") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XMLNS, "xmlns:a", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "a", XMLNS, "xmlns", "xmlns:a") +}, "xmlns should be allowed as prefix in the XMLNS namespace") +test(function() { + var el = document.createElement("foo") + el.setAttributeNS(XMLNS, "xmlns", "pass") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "pass", "xmlns", XMLNS, null, "xmlns") +}, "xmlns should be allowed as qualified name in the XMLNS namespace") + +// Step 8-9 +test(function() { + var el = document.createElement("foo") + el.setAttributeNS("a", "foo:bar", "X") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "X", "bar", "a", "foo", "foo:bar") + + el.setAttributeNS("a", "quux:bar", "Y") + assert_equals(el.attributes.length, 1) + attr_is(el.attributes[0], "Y", "bar", "a", "foo", "foo:bar") + el.removeAttributeNS("a", "bar") +}, "Setting the same attribute with another prefix should not change the prefix") + +// Miscellaneous tests +test(function() { + var el = document.createElement("iframe") + el.setAttribute("src", "file:///home") + assert_equals(el.getAttribute("src"), "file:///home") +}, "setAttribute should not throw even if a load is not allowed") +test(function() { + var docFragment = document.createDocumentFragment() + var newOne = document.createElement("newElement") + newOne.setAttribute("newdomestic", "Yes") + docFragment.appendChild(newOne) + var domesticNode = docFragment.firstChild + var attr = domesticNode.attributes.item(0) + attr_is(attr, "Yes", "newdomestic", null, null, "newdomestic") +}, "Attributes should work in document fragments.") +test(function() { + var el = document.createElement("foo") + el.setAttribute("x", "y") + var attr = el.attributes[0] + attr.value = "Y<" + attr_is(attr, "Y<", "x", null, null, "x") + assert_equals(el.getAttribute("x"), "Y<") +}, "Attribute values should not be parsed.") +test(function() { + var el = document.getElementsByTagName("span")[0] + attr_is(el.attributes[0], "test1", "id", null, null, "id") +}, "Specified attributes should be accessible.") +test(function() { + var el = document.getElementsByTagName("span")[1] + attr_is(el.attributes[0], "&<>foo", "class", null, null, "class") +}, "Entities in attributes should have been expanded while parsing.") + +test(function() { + var el = document.createElement("div") + assert_equals(el.hasAttribute("bar"), false) + assert_equals(el.hasAttributeNS(null, "bar"), false) + assert_equals(el.hasAttributeNS("", "bar"), false) + assert_equals(el.getAttribute("bar"), null) + assert_equals(el.getAttributeNS(null, "bar"), null) + assert_equals(el.getAttributeNS("", "bar"), null) +}, "Unset attributes return null") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("ab", "attr", "t1") + el.setAttributeNS("kl", "attr", "t2") + assert_equals(el.hasAttribute("attr"), true) + assert_equals(el.hasAttributeNS("ab", "attr"), true) + assert_equals(el.hasAttributeNS("kl", "attr"), true) + assert_equals(el.getAttribute("attr"), "t1") + assert_equals(el.getAttributeNS("ab", "attr"), "t1") + assert_equals(el.getAttributeNS("kl", "attr"), "t2") + assert_equals(el.getAttributeNS(null, "attr"), null) + assert_equals(el.getAttributeNS("", "attr"), null) +}, "First set attribute is returned by getAttribute") +test(function() { + var el = document.createElement("div") + el.setAttribute("style", "color:#fff;") + assert_equals(el.hasAttribute("style"), true) + assert_equals(el.hasAttributeNS(null, "style"), true) + assert_equals(el.hasAttributeNS("", "style"), true) + assert_equals(el.getAttribute("style"), "color:#fff;") + assert_equals(el.getAttributeNS(null, "style"), "color:#fff;") + assert_equals(el.getAttributeNS("", "style"), "color:#fff;") +}, "Style attributes are not normalized") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("", "ALIGN", "left") + assert_equals(el.hasAttribute("ALIGN"), false) + assert_equals(el.hasAttribute("align"), false) + assert_equals(el.hasAttributeNS(null, "ALIGN"), true) + assert_equals(el.hasAttributeNS(null, "align"), false) + assert_equals(el.hasAttributeNS("", "ALIGN"), true) + assert_equals(el.hasAttributeNS("", "align"), false) + assert_equals(el.getAttribute("ALIGN"), null) + assert_equals(el.getAttribute("align"), null) + assert_equals(el.getAttributeNS(null, "ALIGN"), "left") + assert_equals(el.getAttributeNS("", "ALIGN"), "left") + assert_equals(el.getAttributeNS(null, "align"), null) + assert_equals(el.getAttributeNS("", "align"), null) + el.removeAttributeNS("", "ALIGN") +}, "Only lowercase attributes are returned on HTML elements (upper case attribute)") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("", "CHEEseCaKe", "tasty") + assert_equals(el.hasAttribute("CHEESECAKE"), false) + assert_equals(el.hasAttribute("CHEEseCaKe"), false) + assert_equals(el.hasAttribute("cheesecake"), false) + assert_equals(el.hasAttributeNS("", "CHEESECAKE"), false) + assert_equals(el.hasAttributeNS("", "CHEEseCaKe"), true) + assert_equals(el.hasAttributeNS("", "cheesecake"), false) + assert_equals(el.hasAttributeNS(null, "CHEESECAKE"), false) + assert_equals(el.hasAttributeNS(null, "CHEEseCaKe"), true) + assert_equals(el.hasAttributeNS(null, "cheesecake"), false) + assert_equals(el.getAttribute("CHEESECAKE"), null) + assert_equals(el.getAttribute("CHEEseCaKe"), null) + assert_equals(el.getAttribute("cheesecake"), null) + assert_equals(el.getAttributeNS(null, "CHEESECAKE"), null) + assert_equals(el.getAttributeNS("", "CHEESECAKE"), null) + assert_equals(el.getAttributeNS(null, "CHEEseCaKe"), "tasty") + assert_equals(el.getAttributeNS("", "CHEEseCaKe"), "tasty") + assert_equals(el.getAttributeNS(null, "cheesecake"), null) + assert_equals(el.getAttributeNS("", "cheesecake"), null) + el.removeAttributeNS("", "CHEEseCaKe") +}, "Only lowercase attributes are returned on HTML elements (mixed case attribute)") +test(function() { + var el = document.createElement("div") + document.body.appendChild(el) + el.setAttributeNS("", "align", "left") + el.setAttributeNS("xx", "align", "right") + el.setAttributeNS("", "foo", "left") + el.setAttributeNS("xx", "foo", "right") + assert_equals(el.hasAttribute("align"), true) + assert_equals(el.hasAttribute("foo"), true) + assert_equals(el.hasAttributeNS("xx", "align"), true) + assert_equals(el.hasAttributeNS(null, "foo"), true) + assert_equals(el.getAttribute("align"), "left") + assert_equals(el.getAttribute("foo"), "left") + assert_equals(el.getAttributeNS("xx", "align"), "right") + assert_equals(el.getAttributeNS(null, "foo"), "left") + assert_equals(el.getAttributeNS("", "foo"), "left") + el.removeAttributeNS("", "align") + el.removeAttributeNS("xx", "align") + el.removeAttributeNS("", "foo") + el.removeAttributeNS("xx", "foo") + document.body.removeChild(el) +}, "First set attribute is returned with mapped attribute set first") +test(function() { + var el = document.createElement("div") + el.setAttributeNS("xx", "align", "right") + el.setAttributeNS("", "align", "left") + el.setAttributeNS("xx", "foo", "right") + el.setAttributeNS("", "foo", "left") + assert_equals(el.hasAttribute("align"), true) + assert_equals(el.hasAttribute("foo"), true) + assert_equals(el.hasAttributeNS("xx", "align"), true) + assert_equals(el.hasAttributeNS(null, "foo"), true) + assert_equals(el.getAttribute("align"), "right") + assert_equals(el.getAttribute("foo"), "right") + assert_equals(el.getAttributeNS("xx", "align"), "right") + assert_equals(el.getAttributeNS(null, "foo"), "left") + assert_equals(el.getAttributeNS("", "foo"), "left") + el.removeAttributeNS("", "align") + el.removeAttributeNS("xx", "align") + el.removeAttributeNS("", "foo") + el.removeAttributeNS("xx", "foo") +}, "First set attribute is returned with mapped attribute set later") + +test(function() { + var el = document.createElementNS("http://www.example.com", "foo") + el.setAttribute("A", "test") + assert_equals(el.hasAttribute("A"), true, "hasAttribute()") + assert_equals(el.hasAttributeNS("", "A"), true, "el.hasAttributeNS(\"\")") + assert_equals(el.hasAttributeNS(null, "A"), true, "el.hasAttributeNS(null)") + assert_equals(el.hasAttributeNS(undefined, "A"), true, "el.hasAttributeNS(undefined)") + assert_equals(el.hasAttributeNS("foo", "A"), false, "el.hasAttributeNS(\"foo\")") + + assert_equals(el.getAttribute("A"), "test", "getAttribute()") + assert_equals(el.getAttributeNS("", "A"), "test", "el.getAttributeNS(\"\")") + assert_equals(el.getAttributeNS(null, "A"), "test", "el.getAttributeNS(null)") + assert_equals(el.getAttributeNS(undefined, "A"), "test", "el.getAttributeNS(undefined)") + assert_equals(el.getAttributeNS("foo", "A"), null, "el.getAttributeNS(\"foo\")") +}, "Non-HTML element with upper-case attribute") + +test(function() { + var el = document.createElement("div") + el.setAttribute("pre:fix", "value 1") + el.setAttribute("fix", "value 2") + + var prefixed = el.attributes[0] + assert_equals(prefixed.localName, "pre:fix", "prefixed local name") + assert_equals(prefixed.namespaceURI, null, "prefixed namespace") + + var unprefixed = el.attributes[1] + assert_equals(unprefixed.localName, "fix", "unprefixed local name") + assert_equals(unprefixed.namespaceURI, null, "unprefixed namespace") + + el.removeAttributeNS(null, "pre:fix") + assert_equals(el.attributes[0], unprefixed) +}, "Attribute with prefix in local name") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + assert_equals(attr.ownerElement, el) + el.removeAttribute("foo") + assert_equals(attr.ownerElement, null) +}, "Attribute loses its owner when removed") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attr = el.attributes[0] + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attr, attrNode); + assert_equals(attr, attrNodeNS); + el.setAttributeNS("x", "foo2", "bar2"); + var attr2 = el.attributes[1]; + var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2"); + assert_equals(attr2, attrNodeNS2); +}, "Basic functionality of getAttributeNode/getAttributeNodeNS") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var attrNodeNS = el.getAttributeNodeNS("", "foo"); + assert_equals(attrNode, attrNodeNS); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(attrNode, el2.getAttributeNode("foo")); + assert_equals(attrNode, el2.attributes[0]); + assert_equals(attrNode.ownerElement, el2); + assert_equals(attrNode.value, "bar"); + + var el3 = document.createElement("div"); + el2.removeAttribute("foo"); + el3.setAttribute("foo", "baz"); + el3.setAttributeNode(attrNode); + assert_equals(el3.getAttribute("foo"), "bar"); +}, "Basic functionality of setAttributeNode") + +test(function() { + var el = document.createElement("div"); + var attr1 = document.createAttributeNS("ns1", "p1:name"); + attr1.value = "value1"; + var attr2 = document.createAttributeNS("ns2", "p2:name"); + attr2.value = "value2"; + el.setAttributeNode(attr1); + el.setAttributeNode(attr2); + assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1"); + assert_equals(el.getAttributeNodeNS("ns2", "name").value, "value2"); +}, "setAttributeNode should distinguish attributes with same local name and different namespaces") + +test(function() { + var el = document.createElement("div"); + var attr1 = document.createAttributeNS("ns1", "p1:name"); + attr1.value = "value1"; + var attr2 = document.createAttributeNS("ns1", "p1:NAME"); + attr2.value = "VALUE2"; + el.setAttributeNode(attr1); + el.setAttributeNode(attr2); + assert_equals(el.getAttributeNodeNS("ns1", "name").value, "value1"); + assert_equals(el.getAttributeNodeNS("ns1", "NAME").value, "VALUE2"); +}, "setAttributeNode doesn't have case-insensitivity even with an HTMLElement") + +test(function() { + var el = document.createElement("div") + el.setAttributeNS("x", "foo", "bar") + var attrNode = el.getAttributeNodeNS("x", "foo"); + el.removeAttribute("foo"); + var el2 = document.createElement("div"); + el2.setAttributeNS("x", "foo", "baz"); + el2.setAttributeNodeNS(attrNode); + assert_equals(el2.getAttributeNS("x", "foo"), "bar"); +}, "Basic functionality of setAttributeNodeNS") + +test(function() { + var el = document.createElement("div"); + var other = document.createElement("div"); + var attr = document.createAttribute("foo"); + assert_equals(el.setAttributeNode(attr), null); + assert_equals(attr.ownerElement, el); + assert_throws_dom("INUSE_ATTRIBUTE_ERR", + function() { other.setAttributeNode(attr) }, + "Attribute already associated with el") +}, "If attr’s element is neither null nor element, throw an InUseAttributeError."); + +test(function() { + var el = document.createElement("div"); + var attr = document.createAttribute("foo"); + assert_equals(el.setAttributeNode(attr), null); + el.setAttribute("bar", "qux"); + assert_equals(el.setAttributeNode(attr), attr); + assert_equals(el.attributes[0], attr); +}, "Replacing an attr by itself"); + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + el.removeAttributeNode(attrNode); + var el2 = document.createElement("div"); + el2.setAttributeNode(attrNode); + assert_equals(el2.attributes[0], attrNode); + assert_equals(el.attributes.length, 0); +}, "Basic functionality of removeAttributeNode") + +test(function() { + var el = document.createElement("div") + el.setAttribute("foo", "bar") + var attrNode = el.getAttributeNode("foo"); + var el2 = document.createElement("div"); + assert_throws_dom("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)}); +}, "setAttributeNode on bound attribute should throw InUseAttributeError") + +// Have to use an async_test to see what a DOMAttrModified listener sees, +// because otherwise the event dispatch code will swallow our exceptions. And +// we want to make sure this test always happens, even when no mutation events +// run. +var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute"); + +test(function(){ + var el = document.createElement("div") + var attrNode1 = document.createAttribute("foo"); + attrNode1.value = "bar"; + el.setAttributeNode(attrNode1); + var attrNode2 = document.createAttribute("foo"); + attrNode2.value = "baz"; + + el.addEventListener("DOMAttrModified", function(e) { + // If this never gets called, that's OK, I guess. But if it gets called, it + // better represent a single modification with attrNode2 as the relatedNode. + // We have to do an inner test() call here, because otherwise the exceptions + // our asserts trigger will get swallowed by the event dispatch code. + setAttributeNode_mutation_test.step(function() { + assert_equals(e.attrName, "foo"); + assert_equals(e.attrChange, MutationEvent.MODIFICATION); + assert_equals(e.prevValue, "bar"); + assert_equals(e.newValue, "baz"); + assert_equals(e.relatedNode, attrNode2); + }); + }); + + var oldNode = el.setAttributeNode(attrNode2); + assert_equals(oldNode, attrNode1, + "Must return the old attr node from a setAttributeNode call"); +}, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)"); +setAttributeNode_mutation_test.done(); + +test(function(){ + var el = document.createElement("div") + el.setAttribute("a", "b"); + el.setAttribute("c", "d"); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["b", "d"]); + + var attrNode = document.createAttribute("a"); + attrNode.value = "e"; + el.setAttributeNode(attrNode); + + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }), + ["a", "c"]); + assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }), + ["e", "d"]); +}, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order"); + +test(function() { + var el = document.createElement("div"); + el.setAttribute("foo", "bar"); + assert_equals(el.getAttributeNames().length, 1); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[0], "foo"); + + el.removeAttribute("foo"); + assert_equals(el.getAttributeNames().length, 0); + + el.setAttribute("foo", "bar"); + el.setAttributeNS("", "FOO", "bar"); + el.setAttributeNS("dummy1", "foo", "bar"); + el.setAttributeNS("dummy2", "dummy:foo", "bar"); + assert_equals(el.getAttributeNames().length, 4); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "FOO"); + assert_equals(el.getAttributeNames()[2], "foo"); + assert_equals(el.getAttributeNames()[3], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); + assert_equals(el.getAttributeNames()[3], el.attributes[3].name); + + el.removeAttributeNS("", "FOO"); + assert_equals(el.getAttributeNames().length, 3); + assert_equals(el.getAttributeNames()[0], "foo"); + assert_equals(el.getAttributeNames()[1], "foo"); + assert_equals(el.getAttributeNames()[2], "dummy:foo"); + assert_equals(el.getAttributeNames()[0], el.attributes[0].name); + assert_equals(el.getAttributeNames()[1], el.attributes[1].name); + assert_equals(el.getAttributeNames()[2], el.attributes[2].name); +}, "getAttributeNames tests"); + +function getEnumerableOwnProps1(obj) { + var arr = []; + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { + arr.push(prop); + } + } + return arr; +} + +function getEnumerableOwnProps2(obj) { + return Object.getOwnPropertyNames(obj).filter( + function (name) { return Object.getOwnPropertyDescriptor(obj, name).enumerable; }) +} + +test(function() { + var el = document.createElement("div"); + el.setAttribute("a", ""); + el.setAttribute("b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "a", "b"]) +}, "Own property correctness with basic attributes"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("foo", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with non-namespaced attribute before same-name namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a", ""); + el.setAttribute("b", ""); + el.setAttributeNS("", "a", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a", "b"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with namespaced attribute before same-name non-namespaced one"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "a:b", ""); + el.setAttributeNS("foo", "c:d", ""); + el.setAttributeNS("bar", "a:b", ""); + assert_array_equals(getEnumerableOwnProps1(el.attributes), + ["0", "1", "2"]) + assert_array_equals(getEnumerableOwnProps2(el.attributes), + ["0", "1", "2"]) + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "a:b", "c:d"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property correctness with two namespaced attributes with the same name-with-prefix"); + +test(function() { + var el = document.createElement("div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "g:h", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document"); + +test(function() { + var el = document.createElementNS("", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for a non-HTML element in an HTML document"); + +test(function() { + var doc = document.implementation.createDocument(null, ""); + assert_equals(doc.contentType, "application/xml"); + var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div"); + el.setAttributeNS("foo", "A:B", ""); + el.setAttributeNS("bar", "c:D", ""); + el.setAttributeNS("baz", "e:F", ""); + el.setAttributeNS("qux", "g:h", ""); + el.setAttributeNS("", "I", ""); + el.setAttributeNS("", "j", ""); + assert_array_equals(Object.getOwnPropertyNames(el.attributes), + ["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"]) + for (var propName of Object.getOwnPropertyNames(el.attributes)) { + assert_true(el.attributes[propName] instanceof Attr, + "el.attributes has an Attr for property name " + propName); + } +}, "Own property names should include all qualified names for an HTML element in a non-HTML document"); +</script> diff --git a/testing/web-platform/tests/dom/nodes/attributes.js b/testing/web-platform/tests/dom/nodes/attributes.js new file mode 100644 index 0000000000..ef32bf6a67 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/attributes.js @@ -0,0 +1,18 @@ +function attr_is(attr, v, ln, ns, p, n) { + assert_equals(attr.value, v) + assert_equals(attr.nodeValue, v) + assert_equals(attr.textContent, v) + assert_equals(attr.localName, ln) + assert_equals(attr.namespaceURI, ns) + assert_equals(attr.prefix, p) + assert_equals(attr.name, n) + assert_equals(attr.nodeName, n); + assert_equals(attr.specified, true) +} + +function attributes_are(el, l) { + for (var i = 0, il = l.length; i < il; i++) { + attr_is(el.attributes[i], l[i][1], l[i][0], (l[i].length < 3) ? null : l[i][2], null, l[i][0]) + assert_equals(el.attributes[i].ownerElement, el) + } +} diff --git a/testing/web-platform/tests/dom/nodes/case.html b/testing/web-platform/tests/dom/nodes/case.html new file mode 100644 index 0000000000..c3c195141c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/case.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Tests for case-sensitivity in APIs</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelement"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-createelementns"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbytagname"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbytagnamens"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattributens"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-hasattribute"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-hasattributens"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-getelementsbytagname"> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-getelementsbytagnamens"> +<script>var is_html = true;</script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="case.js"></script> +<div id="log"></div> diff --git a/testing/web-platform/tests/dom/nodes/case.js b/testing/web-platform/tests/dom/nodes/case.js new file mode 100644 index 0000000000..8c2da4a44a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/case.js @@ -0,0 +1,186 @@ +/* + * document.createElement(NS) + * + * document.getElementsByTagName(NS) + * + * Element.setAttribute(NS) + * + * Element.getAttribute(NS) + * Element.hasAttribute(NS) + * Element.getElementsByTagName(NS) + */ + +var tests = []; +setup(function() { + var name_inputs = ["abc", "Abc", "ABC", "ä", "Ä"]; + var namespaces = ["http://www.w3.org/1999/xhtml", "http://www.w3.org/2000/svg", "http://FOO"]; + name_inputs.forEach(function(x) { + tests.push(["createElement " + x, test_create_element, [x]]); + tests.push(["setAttribute " +x, test_set_attribute, [x]]); + tests.push(["getAttribute " +x, test_get_attribute, [x]]); + tests.push(["getElementsByTagName a:" +x, test_get_elements_tag_name, + [outer_product(namespaces, ["a"], name_inputs), + x]]); + tests.push(["getElementsByTagName " +x, test_get_elements_tag_name, + [outer_product(namespaces, [null], name_inputs), + x]]); + }); + outer_product(namespaces, name_inputs, name_inputs).forEach(function(x) { + tests.push(["createElementNS " + x, test_create_element_ns, x]); + tests.push(["setAttributeNS " + x, test_set_attribute_ns, x]); + tests.push(["getAttributeNS " + x, test_get_attribute_ns, x]); + }); + outer_product([null].concat(namespaces), name_inputs).forEach(function(x) { + tests.push(["getElementsByTagNameNS " + x, test_get_elements_tag_name_ns, + outer_product(namespaces, name_inputs), x]); + }); + name_inputs.forEach(function(x) { + tests.push(["createElementNS " + x, test_create_element_ns, [null, null, x]]); + tests.push(["setAttributeNS " + x, test_set_attribute_ns, [null, null, x]]); + tests.push(["getAttributeNS " + x, test_get_attribute_ns, [null, null, x]]); + }); + + }); +function outer_product() { + var rv = []; + function compute_outer_product() { + var args = Array.prototype.slice.call(arguments); + var index = args[0]; + if (index < args.length) { + args[index].forEach(function(x) { + compute_outer_product.apply(this, [index+1].concat(args.slice(1, index), x, args.slice(index+1))); + }); + } else { + rv.push(args.slice(1)); + } + } + compute_outer_product.apply(this, [1].concat(Array.prototype.slice.call(arguments))); + return rv; +} + +function expected_case(input) { + //is_html gets set by a global on the page loading the tests + if (is_html) { + return ascii_lowercase(input); + } else { + return input; + } +} + +function ascii_lowercase(input) { + return input.replace(/[A-Z]/g, function(x) { + return x.toLowerCase(); + }); +} + +function get_qualified_name(el) { + if (el.prefix) { + return el.prefix + ":" + el.localName; + } + return el.localName; +} + +function test_create_element(name) { + var node = document.createElement(name); + assert_equals(node.localName, expected_case(name)); +} + +function test_create_element_ns(namespace, prefix, local_name) { + var qualified_name = prefix ? prefix + ":" + local_name : local_name; + var node = document.createElementNS(namespace, qualified_name); + assert_equals(node.prefix, prefix, "prefix"); + assert_equals(node.localName, local_name, "localName"); +} + +function test_set_attribute(name) { + var node = document.createElement("div"); + node.setAttribute(name, "test"); + assert_equals(node.attributes[0].localName, expected_case(name)); +} + +function test_set_attribute_ns(namespace, prefix, local_name) { + var qualified_name = prefix ? prefix + ":" + local_name : local_name; + var node = document.createElement("div"); + node.setAttributeNS(namespace, qualified_name, "test"); + var attr = node.attributes[0]; + assert_equals(attr.prefix, prefix, "prefix"); + assert_equals(attr.localName, local_name, "localName"); +} + +function test_get_attribute(name) { + var node = document.createElement("div"); + node.setAttribute(name, "test"); + var expected_name = expected_case(name); + assert_equals(node.getAttribute(expected_name), "test"); + if (expected_name != name) { + assert_equals(node.getAttribute(expected_name), "test"); + } else if (name !== ascii_lowercase(name)) { + assert_equals(node.getAttribute(ascii_lowercase(name)), null); + } +} + +function test_get_attribute_ns(namespace, prefix, local_name) { + var qualified_name = prefix ? prefix + ":" + local_name : local_name; + var node = document.createElement("div"); + node.setAttributeNS(namespace, qualified_name, "test"); + var expected_name = local_name; + assert_equals(node.getAttributeNS(namespace, expected_name), "test"); + if (local_name !== ascii_lowercase(local_name)) { + assert_equals(node.getAttributeNS(namespace, ascii_lowercase(local_name)), null); + } +} + +function test_get_elements_tag_name(elements_to_create, search_string) { + var container = document.createElement("div"); + elements_to_create.forEach(function(x) { + var qualified_name = x[1] ? x[1] + ":" + x[2] : x[2]; + var element = document.createElementNS(x[0], qualified_name); + container.appendChild(element); + }); + var expected = Array.prototype.filter.call(container.childNodes, + function(node) { + if (is_html && node.namespaceURI === "http://www.w3.org/1999/xhtml") { + return get_qualified_name(node) === expected_case(search_string); + } else { + return get_qualified_name(node) === search_string; + } + }); + document.documentElement.appendChild(container); + try { + assert_array_equals(document.getElementsByTagName(search_string), expected); + } finally { + document.documentElement.removeChild(container); + } +} + +function test_get_elements_tag_name_ns(elements_to_create, search_input) { + var search_uri = search_input[0]; + var search_name = search_input[1]; + var container = document.createElement("div"); + elements_to_create.forEach(function(x) { + var qualified_name = x[1] ? x[1] + ":" + x[2] : x[2]; + var element = document.createElementNS(x[0], qualified_name); + container.appendChild(element); + }); + var expected = Array.prototype.filter.call(container.childNodes, + function(node) { + return node.namespaceURI === search_uri; + return node.localName === search_name; + }); + document.documentElement.appendChild(container); + try { + assert_array_equals(document.getElementsByTagNameNS(search_uri, search_name), expected); + } catch(e) { + throw e; + } finally { + document.documentElement.removeChild(container); + } +} + +function test_func() { + var func = arguments[0]; + var rest = arguments[1]; + func.apply(this, rest); +} + +generate_tests(test_func, tests); diff --git a/testing/web-platform/tests/dom/nodes/characterset-helper.js b/testing/web-platform/tests/dom/nodes/characterset-helper.js new file mode 100644 index 0000000000..ecbe556ae2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/characterset-helper.js @@ -0,0 +1,62 @@ +function runCharacterSetTests(encodingMap) { + // Add spaces and mix up case + Object.keys(encodingMap).forEach(function(name) { + var lower = encodingMap[name]; + var upper = encodingMap[name].map(function(s) { return s.toUpperCase() }); + var mixed = encodingMap[name].map(function(s) { + var ret = ""; + for (var i = 0; i < s.length; i += 2) { + ret += s[i].toUpperCase(); + if (i + 1 < s.length) { + ret += s[i + 1]; + } + } + return ret; + }); + var spacey = encodingMap[name].map(function(s) { + return " \t\n\f\r" + s + " \t\n\f\r"; + }); + encodingMap[name] = []; + for (var i = 0; i < lower.length; i++) { + encodingMap[name].push(lower[i]); + /* + if (lower[i] != upper[i]) { + encodingMap[name].push(upper[i]); + } + if (lower[i] != mixed[i] && upper[i] != mixed[i]) { + encodingMap[name].push(mixed[i]); + } + encodingMap[name].push(spacey[i]); + */ + } + }); + + Object.keys(encodingMap).forEach(function(name) { + encodingMap[name].forEach(function(label) { + var iframe = document.createElement("iframe"); + var t = async_test("Name " + format_value(name) + + " has label " + format_value(label) + " (characterSet)"); + var t2 = async_test("Name " + format_value(name) + + " has label " + format_value(label) + " (inputEncoding)"); + var t3 = async_test("Name " + format_value(name) + + " has label " + format_value(label) + " (charset)"); + iframe.src = "encoding.py?label=" + label; + iframe.onload = function() { + t.step(function() { + assert_equals(iframe.contentDocument.characterSet, name); + }); + t2.step(function() { + assert_equals(iframe.contentDocument.inputEncoding, name); + }); + t3.step(function() { + assert_equals(iframe.contentDocument.charset, name); + }); + document.body.removeChild(iframe); + t.done(); + t2.done(); + t3.done(); + }; + document.body.appendChild(iframe); + }); + }); +}
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/nodes/creators.js b/testing/web-platform/tests/dom/nodes/creators.js new file mode 100644 index 0000000000..8b7415d13f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/creators.js @@ -0,0 +1,5 @@ +var creators = { + "element": "createElement", + "text": "createTextNode", + "comment": "createComment" +}; diff --git a/testing/web-platform/tests/dom/nodes/encoding.py b/testing/web-platform/tests/dom/nodes/encoding.py new file mode 100644 index 0000000000..15edff7061 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/encoding.py @@ -0,0 +1,7 @@ +from html import escape + +from wptserve.utils import isomorphic_decode + +def main(request, response): + label = request.GET.first(b'label') + return u"""<!doctype html><meta charset="%s">""" % escape(isomorphic_decode(label)) diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-01.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-01.htm new file mode 100644 index 0000000000..457d6c400f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-01.htm @@ -0,0 +1,13 @@ +<!doctype html> +<html class="a"> + <head> + <title>document.getElementsByClassName(): simple</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> test(function() {assert_array_equals(document.getElementsByClassName("\ta\n"), + [document.documentElement, document.body])}) </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-02.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-02.htm new file mode 100644 index 0000000000..d5e513fa88 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-02.htm @@ -0,0 +1,14 @@ +<!doctype html> +<html class="a +b"> + <head> + <title>document.getElementsByClassName(): also simple</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a +"> + <div id="log"></div> + <script> test(function() {assert_array_equals(document.getElementsByClassName("a\n"), [document.documentElement, document.body])}) </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-03.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-03.htm new file mode 100644 index 0000000000..a9e2d3af1a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-03.htm @@ -0,0 +1,18 @@ +<!doctype html> +<html class="a"> + <head> + <title>document.getElementsByClassName(): changing classes</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> + test(function() { + var collection = document.getElementsByClassName("a") + document.body.className = "b" + assert_array_equals(collection, [document.documentElement]) + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-04.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-04.htm new file mode 100644 index 0000000000..0c62fed2c5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-04.htm @@ -0,0 +1,18 @@ +<!doctype html> +<html class="a"> + <head> + <title>document.getElementsByClassName(): changing classes</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> + test(function() { + var collection = document.getElementsByClassName("a"); + document.body.className += "\tb"; + assert_array_equals(collection, [document.documentElement, document.body]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-05.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-05.htm new file mode 100644 index 0000000000..98245f6427 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-05.htm @@ -0,0 +1,18 @@ +<!doctype html> +<html class="a"> + <head> + <title>document.getElementsByClassName(): changing classes</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> + test(function() { + var collection = document.getElementsByClassName("a"); + document.body.removeAttribute("class"); + assert_array_equals(collection, [document.documentElement]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-06.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-06.htm new file mode 100644 index 0000000000..4975a89e09 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-06.htm @@ -0,0 +1,20 @@ +<!doctype html> +<html> + <head> + <title>document.getElementsByClassName(): adding element with class</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> + test(function() { + var collection = document.getElementsByClassName("a"); + var ele = document.createElement("foo"); + ele.setAttribute("class", "a"); + document.body.appendChild(ele); + assert_array_equals(collection, [document.body, ele]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-07.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-07.htm new file mode 100644 index 0000000000..b0102fb2e6 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-07.htm @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <title>document.getElementsByClassName(): multiple classes</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a b"> + <div id="log"></div> + <script> test(function() { + assert_array_equals(document.getElementsByClassName("b\t\f\n\na\rb"), [document.body]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-08.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-08.htm new file mode 100644 index 0000000000..a248af4929 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-08.htm @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <title>document.getElementsByClassName(): multiple classes</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script> test(function() { + document.getElementsByClassName("a\fa"), [document.body] + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-09.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-09.htm new file mode 100644 index 0000000000..9011f3068c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-09.htm @@ -0,0 +1,15 @@ +<!doctype html> +<html class="a A"> + <head> + <title>document.getElementsByClassName(): case sensitive</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a a"> + <div id="log"></div> + <script>test(function() { + assert_array_equals(document.getElementsByClassName("A a"), [document.documentElement]) + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-10.xml b/testing/web-platform/tests/dom/nodes/getElementsByClassName-10.xml new file mode 100644 index 0000000000..b3e3122cb0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-10.xml @@ -0,0 +1,19 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:g="http://www.w3.org/2000/svg"> + <head> + <title>document.getElementsByClassName(): compound</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"/> + <div id="tests"> + <x class="a"/> + <g:x class="a"/> + </div> + <script>test(function() { + assert_array_equals(document.getElementsByClassName("a"), + document.getElementById("tests").children); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-11.xml b/testing/web-platform/tests/dom/nodes/getElementsByClassName-11.xml new file mode 100644 index 0000000000..8593fa7a0e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-11.xml @@ -0,0 +1,24 @@ +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:g="http://www.w3.org/2000/svg" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:t="http://tc.labs.opera.com/#test"> + <head> + <title>document.getElementsByClassName(): "tricky" compound</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log" /> + <div id="tests"> + <x class="a"/> + <g:x class="a"/> + <x t:class="a" h:class="a" g:class="a"/> + <g:x t:class="a" h:class="a" g:class="a"/> + <t:x class="a" t:class="a" h:class="a" g:class="a"/> + </div> + <script> + test(function() { + var collection = document.getElementsByClassName("a"); + var test = document.getElementById("tests").children; + assert_array_equals(collection, [test[0], test[1], test[4]]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-12.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-12.htm new file mode 100644 index 0000000000..3b7f328b47 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-12.htm @@ -0,0 +1,15 @@ +<!doctype html> +<html class="a"> + <head> + <title>element.getElementsByClassName(): simple</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script>test(function() { + assert_array_equals(document.body.getElementsByClassName("a"), []) + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-13.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-13.htm new file mode 100644 index 0000000000..f3af106aed --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-13.htm @@ -0,0 +1,19 @@ +<!doctype html> +<html class="a"> + <head> + <title>element.getElementsByClassName(): adding an element</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a"> + <div id="log"></div> + <script>test(function() { + var collection = document.body.getElementsByClassName("a"); + var ele = document.createElement("x-y-z"); + ele.className = "a"; + document.body.appendChild(ele); + assert_array_equals(collection, [ele]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-14.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-14.htm new file mode 100644 index 0000000000..83addb7ba5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-14.htm @@ -0,0 +1,26 @@ +<!-- quirks mode --> +<html class="a A"> + <head> + <title>document.getElementsByClassName(): case-insensitive (quirks mode)</title> + <link rel="help" href="https://dom.spec.whatwg.org/#concept-getelementsbyclassname"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a a"> + <div id="log"></div> + <div class="k"></div> + <div class="K"></div> + <div class="K" id="kelvin"></div> + <script> +test(function() { + assert_array_equals(document.getElementsByClassName("A a"), + [document.documentElement, document.body]); +}) + +test(function() { + assert_array_equals(document.getElementsByClassName("\u212a"), + [document.getElementById("kelvin")]); +}, 'Unicode-case should be sensitive even in quirks mode.'); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-15.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-15.htm new file mode 100644 index 0000000000..89614de30d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-15.htm @@ -0,0 +1,18 @@ +<!doctype html> +<html class="a +b"> + <head> + <title>document.getElementsByClassName(array): "a\n"</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a +"> + <div id="log"></div> + <script>test(function () { + assert_array_equals(document.getElementsByClassName(["a\n"]), + [document.documentElement, document.body]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-16.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-16.htm new file mode 100644 index 0000000000..3f987a7ae0 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-16.htm @@ -0,0 +1,16 @@ +<!doctype html> +<html class="a +b"> + <head> + <title>document.getElementsByClassName(array): "b","a"</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="b,a"> + <div id="log"></div> + <script>test(function() { + assert_array_equals(document.getElementsByClassName(["b", "a"]), [document.body]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-17.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-17.htm new file mode 100644 index 0000000000..ae5ebda6e2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-17.htm @@ -0,0 +1,15 @@ +<!doctype html> +<html> + <head> + <title>document.getElementsByClassName(array): "b a"</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a b"> + <div id="log"></div> + <script>test(function() { + assert_array_equals(document.getElementsByClassName(["b a"]), [document.body]); + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-18.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-18.htm new file mode 100644 index 0000000000..9f6cf75a50 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-18.htm @@ -0,0 +1,17 @@ +<!doctype html> +<html class="a,b"> + <head> + <title>element.getElementsByClassName(array): "a", "b"</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body class="a,b x"> + <div id="log"></div> + <p id="r" class="a,bx"></p> + <script class="xa,b">test(function() { + assert_array_equals(document.documentElement.getElementsByClassName(["\fa","b\n"]), + [document.body]) + }) + </script> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-19.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-19.htm new file mode 100644 index 0000000000..da233c743a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-19.htm @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="get elements in document" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function () + { + var collection = document.getElementsByClassName("text"); + assert_equals(collection.length, 4); + assert_equals(collection[0].parentNode.nodeName, "DIV"); + assert_equals(collection[1].parentNode.nodeName, "DIV"); + assert_equals(collection[2].parentNode.nodeName, "TABLE"); + assert_equals(collection[3].parentNode.nodeName, "TR"); + }, "get elements in document"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-20.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-20.htm new file mode 100644 index 0000000000..6429e37bb5 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-20.htm @@ -0,0 +1,61 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="get elements in document then add element to collection" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("text"); + assert_equals(collection.length, 4); + var newDiv = document.createElement("div"); + newDiv.setAttribute("class", "text"); + newDiv.innerHTML = "text newDiv"; + document.getElementsByTagName("table")[0].tBodies[0].rows[0].cells[0].appendChild(newDiv); + + assert_equals(collection.length, 5); + assert_equals(collection[0].parentNode.nodeName, "DIV"); + assert_equals(collection[1].parentNode.nodeName, "DIV"); + assert_equals(collection[2].parentNode.nodeName, "TABLE"); + assert_equals(collection[3].parentNode.nodeName, "TD"); + assert_equals(collection[4].parentNode.nodeName, "TR"); + }, "get elements in document then add element to collection"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-21.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-21.htm new file mode 100644 index 0000000000..339ff2d3e1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-21.htm @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="delete element from collection" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("text1"); + assert_equals(collection.length, 1) + document.getElementsByTagName("table")[0].deleteRow(1); + assert_equals(collection.length, 0); + }, "delete element from collection"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-22.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-22.htm new file mode 100644 index 0000000000..c203967007 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-22.htm @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="move item in collection order" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("text"); + assert_equals(collection.length, 4); + var boldText = document.getElementsByTagName("b")[0]; + document.getElementsByTagName("table")[0].tBodies[0].rows[0].cells[0].appendChild(boldText); + + assert_equals(collection.length, 4); + assert_equals(collection[0].parentNode.nodeName, "DIV"); + assert_equals(collection[1].parentNode.nodeName, "TABLE"); + assert_equals(collection[2].parentNode.nodeName, "TD"); + assert_equals(collection[3].parentNode.nodeName, "TR"); + }, "move item in collection order"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-23.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-23.htm new file mode 100644 index 0000000000..0af8a09952 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-23.htm @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="multiple defined classes" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("te xt"); + assert_equals(collection.length, 2); + assert_equals(collection[0].parentNode.nodeName, "TR"); + assert_equals(collection[1].parentNode.nodeName, "BODY"); + }, "multiple defined classes"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-24.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-24.htm new file mode 100644 index 0000000000..838987ad0c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-24.htm @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html><head> + <meta charset='utf-8'> + <title>getElementsByClassName</title> + <meta content="handle unicode chars" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="ΔЙあ叶葉 말 link" href="#foo">ΔЙあ叶葉 말 link</a> + </div> + <b class="text">text</b> + </div> + <div class="ΔЙあ叶葉 קم">ΔЙあ叶葉 קم</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("ΔЙあ叶葉"); + assert_equals(collection.length, 2); + assert_equals(collection[0].parentNode.nodeName, "DIV"); + assert_equals(collection[1].parentNode.nodeName, "BODY"); + }, "handle unicode chars"); + </script> + +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-25.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-25.htm new file mode 100644 index 0000000000..21f2a9ff7a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-25.htm @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="verify spacing is handled correctly" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("text "); + assert_equals(collection.length, 4); + var boldText = document.getElementsByTagName("b")[0]; + document.getElementsByTagName("table")[0].tBodies[0].rows[0].cells[0].appendChild(boldText); + assert_equals(collection.length, 4); + assert_equals(collection[0].parentNode.nodeName, "DIV"); + assert_equals(collection[1].parentNode.nodeName, "TABLE"); + assert_equals(collection[2].parentNode.nodeName, "TD"); + assert_equals(collection[3].parentNode.nodeName, "TR"); + }, "verify spacing is handled correctly"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-26.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-26.htm new file mode 100644 index 0000000000..0d7ff1ba1f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-26.htm @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="multiple class attributes" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div class="te xt"> + te xt + <div class="te"> + te; xt + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <div class="xt te">xt te</div> + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("te xt"); + + assert_equals(collection.length, 2); + assert_equals(collection[0].parentNode.nodeName, "BODY"); + assert_equals(collection[1].parentNode.nodeName, "BODY"); + }, "multiple class attributes"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-27.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-27.htm new file mode 100644 index 0000000000..95fc674428 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-27.htm @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="generic element listed" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div class="te xt"> + te xt + <div class="te"> + te; xt + <a class="text link" href="#foo">test link #foo</a> + <foo class="te xt">dummy tag</foo> + </div> + <b class="text">text</b> + </div> + <div class="xt te">xt te</div> + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("te xt"); + + assert_equals(collection.length, 3); + assert_equals(collection[0].parentNode.nodeName, "BODY"); + assert_equals(collection[1].parentNode.nodeName, "DIV"); + assert_equals(collection[2].parentNode.nodeName, "BODY"); + }, "generic element listed"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-28.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-28.htm new file mode 100644 index 0000000000..1fc94d807c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-28.htm @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="generic element listed" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id="log"></div> + <div class="te xt"> + te xt + <div class="te"> + te; xt + <a class="text link" href="#foo">test link #foo</a> + <fooU00003Abar class="te xt namespace">te xt namespace + </fooU00003Abar></div> + <b class="text">text</b> + </div> + <div class="xt te">xt te</div> + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByClassName("te xt"); + assert_equals(collection.length, 3); + assert_equals(collection[0].parentNode.nodeName, "BODY"); + assert_equals(collection[1].parentNode.nodeName, "DIV"); + assert_equals(collection[2].parentNode.nodeName, "BODY"); + }, "generic element listed"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-29.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-29.htm new file mode 100644 index 0000000000..ad489752cc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-29.htm @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html><head> + <title>getElementsByClassName</title> + <meta content="get class from children of element" name="description"> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> + <body> + <div id='log'></div> + <div> + <div> + <a class="text link" href="#foo">test link #foo</a> + </div> + <b class="text">text</b> + </div> + <table> + <caption class="text caption">text caption</caption> + <thead> + <tr> + <td class="TEXT head">TEXT head</td> + </tr> + </thead> + <tbody> + <tr> + <td class="td text1">td text1</td> + </tr> + <tr> + <td class="td text">td text</td> + </tr> + <tr> + <td class="td te xt">td te xt</td> + </tr> + </tbody> + <tfoot> + <tr> + <td class="TEXT foot">TEXT foot</td> + </tr> + </tfoot> + </table> + <div class="xt te">xt te</div> + + <script type="text/javascript"> + test(function() + { + var collection = document.getElementsByTagName("table")[0].getElementsByClassName("te xt"); + assert_equals(collection.length, 1); + assert_equals(collection[0].parentNode.nodeName, "TR"); + }, "get class from children of element"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-30.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-30.htm new file mode 100644 index 0000000000..c0b4faf2d4 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-30.htm @@ -0,0 +1,190 @@ +<!DOCTYPE html> +<html><head class="foo"> + <title class="foo">getElementsByClassName</title> + <meta class="foo" content="big element listing" name="description"> + <link class="foo"> + <base class="foo"> + <script class="foo"></script> + <style class="foo"></style> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <link href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname" rel="help"> +</head> + <body class="foo"> + <div id='log'></div> + <a class="foo">a</a> + <abbr class="foo">abbr</abbr> + <acronym class="foo">acronym</acronym> + <address class="foo">address</address> + <applet class="foo">applet</applet> + <b class="foo">b</b> + <bdo class="foo">bdo</bdo> + <big class="foo">big</big> + <blockquote class="foo">blockquote</blockquote> + <br class="foo"> + <button class="foo">button</button> + <center class="foo">center</center> + <cite class="foo">cite</cite> + <code class="foo">code</code> + <del class="foo">del</del> + <dfn class="foo">dfn</dfn> + <dir class="foo">dir + <li class="foo">li</li> + </dir> + <div class="foo">div</div> + <dl class="foo"> + <dt class="foo"> + </dt><dd class="foo">dd</dd> + </dl> + <em class="foo">em</em> + <font class="foo">font</font> + <form class="foo"> + <label class="foo">label</label> + <fieldset class="foo"> + <legend class="foo">legend</legend> + </fieldset> + </form> + <h1 class="foo">h1</h1> + <hr class="foo"> + <i class="foo">i</i> + <iframe class="foo">iframe</iframe> + <img class="foo"> + <input class="foo"> + <ins class="foo">ins</ins> + <kbd class="foo">kbd</kbd> + <map class="foo"> + <area class="foo"></area> + </map> + <menu class="foo">menu</menu> + <noscript class="foo">noscript</noscript> + <object class="foo"> + <param class="foo"> + </object> + <ol class="foo">ol</ol> + <p class="foo">p</p> + <pre class="foo">pre</pre> + <q class="foo">q</q> + <s class="foo">s</s> + <samp class="foo">samp</samp> + <select class="foo"> + <optgroup class="foo">optgroup</optgroup> + <option class="foo">option</option> + </select> + <small class="foo">small</small> + <span class="foo">span</span> + <strike class="foo">strike</strike> + <strong class="foo">strong</strong> + <sub class="foo">sub</sub> + <sup class="foo">sup</sup> + colgroup<table class="foo"> + <caption class="foo">caption</caption> + <colgroup><col class="foo"> + </colgroup><colgroup class="foo"></colgroup> + <thead class="foo"> + <tr><th class="foo">th</th> + </tr></thead> + <tbody class="foo"> + <tr class="foo"> + <td class="foo">td</td> + </tr> + </tbody> + <tfoot class="foo"></tfoot> + </table> + <textarea class="foo">textarea</textarea> + <tt class="foo">tt</tt> + <u class="foo">u</u> + <ul class="foo">ul</ul> + <var class="foo">var</var> + <script type="text/javascript"> + test(function () + { + var arrElements = [ + "HEAD", + "TITLE", + "META", + "LINK", + "BASE", + "SCRIPT", + "STYLE", + "BODY", + "A", + "ABBR", + "ACRONYM", + "ADDRESS", + "APPLET", + "B", + "BDO", + "BIG", + "BLOCKQUOTE", + "BR", + "BUTTON", + "CENTER", + "CITE", + "CODE", + "DEL", + "DFN", + "DIR", + "LI", + "DIV", + "DL", + "DT", + "DD", + "EM", + "FONT", + "FORM", + "LABEL", + "FIELDSET", + "LEGEND", + "H1", + "HR", + "I", + "IFRAME", + "IMG", + "INPUT", + "INS", + "KBD", + "MAP", + "AREA", + "MENU", + "NOSCRIPT", + "OBJECT", + "PARAM", + "OL", + "P", + "PRE", + "Q", + "S", + "SAMP", + "SELECT", + "OPTGROUP", + "OPTION", + "SMALL", + "SPAN", + "STRIKE", + "STRONG", + "SUB", + "SUP", + "TABLE", + "CAPTION", + "COL", + "COLGROUP", + "THEAD", + "TH", + "TBODY", + "TR", + "TD", + "TFOOT", + "TEXTAREA", + "TT", + "U", + "UL", + "VAR"]; + + var collection = document.getElementsByClassName("foo"); + for (var x = 0; x < collection.length; x++) + { + assert_equals(collection[x].nodeName, arrElements[x]); + } +}, "big element listing"); + </script> +</body></html> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-31.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassName-31.htm new file mode 100644 index 0000000000..0e1ac014ae --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-31.htm @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html class=foo> +<meta charset=utf-8> +<title>getElementsByClassName across documents</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script class=foo> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.onload = this.step_func_done(function() { + var collection = iframe.contentDocument.getElementsByClassName("foo"); + assert_equals(collection.length, 3); + assert_equals(collection[0].localName, "html"); + assert_equals(collection[1].localName, "head"); + assert_equals(collection[2].localName, "body"); + }); + iframe.src = "getElementsByClassNameFrame.htm"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-32.html b/testing/web-platform/tests/dom/nodes/getElementsByClassName-32.html new file mode 100644 index 0000000000..29eb41353c --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-32.html @@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName tests imported from jsdom</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div class="df-article" id="1"> +</div> +<div class="df-article" id="2"> +</div> +<div class="df-article" id="3"> +</div> + +<script> +"use strict"; + +test(() => { + + const p = document.createElement("p"); + p.className = "unknown"; + document.body.appendChild(p); + + const elements = document.getElementsByClassName("first-p"); + assert_array_equals(elements, []); + +}, "cannot find the class name"); + +test(() => { + + const p = document.createElement("p"); + p.className = "first-p"; + document.body.appendChild(p); + + const elements = document.getElementsByClassName("first-p"); + assert_array_equals(elements, [p]); + +}, "finds the class name"); + + +test(() => { + + const p = document.createElement("p"); + p.className = "the-p second third"; + document.body.appendChild(p); + + const elements1 = document.getElementsByClassName("the-p"); + assert_array_equals(elements1, [p]); + + const elements2 = document.getElementsByClassName("second"); + assert_array_equals(elements2, [p]); + + const elements3 = document.getElementsByClassName("third"); + assert_array_equals(elements3, [p]); + +}, "finds the same element with multiple class names"); + +test(() => { + + const elements = document.getElementsByClassName("df-article"); + + assert_equals(elements.length, 3); + assert_array_equals(Array.prototype.map.call(elements, el => el.id), ["1", "2", "3"]); + +}, "does not get confused by numeric IDs"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-empty-set.html b/testing/web-platform/tests/dom/nodes/getElementsByClassName-empty-set.html new file mode 100644 index 0000000000..75b8d5a9f8 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-empty-set.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName with no real class names</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span class=" ">test</span> + +<script> +"use strict"; + +test(() => { + const elements = document.getElementsByClassName(""); + assert_array_equals(elements, []); +}, "Passing an empty string to getElementsByClassName should return an empty HTMLCollection"); + +test(() => { + const elements = document.getElementsByClassName(" "); + assert_array_equals(elements, []); +}, "Passing a space to getElementsByClassName should return an empty HTMLCollection"); + +test(() => { + const elements = document.getElementsByClassName(" "); + assert_array_equals(elements, []); +}, "Passing three spaces to getElementsByClassName should return an empty HTMLCollection"); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassName-whitespace-class-names.html b/testing/web-platform/tests/dom/nodes/getElementsByClassName-whitespace-class-names.html new file mode 100644 index 0000000000..59bfd2e6b1 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassName-whitespace-class-names.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName with no real class names</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span class="">LINE TABULATION</span> +<span class="…">NEXT LINE</span> +<span class=" ">NO-BREAK SPACE</span> +<span class=" ">OGHAM SPACE MARK</span> +<span class=" ">EN QUAD</span> +<span class=" ">EM QUAD</span> +<span class=" ">EN SPACE</span> +<span class=" ">EM SPACE</span> +<span class=" ">THREE-PER-EM SPACE</span> +<span class=" ">FOUR-PER-EM SPACE</span> +<span class=" ">SIX-PER-EM SPACE</span> +<span class=" ">FIGURE SPACE</span> +<span class=" ">PUNCTUATION SPACE</span> +<span class=" ">THIN SPACE</span> +<span class=" ">HAIR SPACE</span> +<span class="
">LINE SEPARATOR</span> +<span class="
">PARAGRAPH SEPARATOR</span> +<span class=" ">NARROW NO-BREAK SPACE</span> +<span class=" ">MEDIUM MATHEMATICAL SPACE</span> +<span class=" ">IDEOGRAPHIC SPACE</span> + +<span class="᠎">MONGOLIAN VOWEL SEPARATOR</span> +<span class="​">ZERO WIDTH SPACE</span> +<span class="‌">ZERO WIDTH NON-JOINER</span> +<span class="‍">ZERO WIDTH JOINER</span> +<span class="⁠">WORD JOINER</span> +<span class="">ZERO WIDTH NON-BREAKING SPACE</span> + +<script> +"use strict"; + +const spans = document.querySelectorAll("span"); + +for (const span of spans) { + test(() => { + const className = span.getAttribute("class"); + assert_equals(className.length, 1, "Sanity check: the class name was retrieved and is a single character"); + const shouldBeSpan = document.getElementsByClassName(className); + assert_array_equals(shouldBeSpan, [span]); + }, `Passing a ${span.textContent} to getElementsByClassName still finds the span`); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/getElementsByClassNameFrame.htm b/testing/web-platform/tests/dom/nodes/getElementsByClassNameFrame.htm new file mode 100644 index 0000000000..544df60a99 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/getElementsByClassNameFrame.htm @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<html class=foo> +<head class=foo> +<meta charset=utf-8> +<title>getElementsByClassName</title> +<body class=foo> diff --git a/testing/web-platform/tests/dom/nodes/insert-adjacent.html b/testing/web-platform/tests/dom/nodes/insert-adjacent.html new file mode 100644 index 0000000000..68b6f4ee66 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/insert-adjacent.html @@ -0,0 +1,79 @@ +<!doctype html> +<meta charset="utf-8"> +<title></title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +#element { + display: none; +} +</style> + +<div id="element"></div> +<div id="log"></div> + +<script> +var possiblePositions = { + 'beforebegin': 'previousSibling' + , 'afterbegin': 'firstChild' + , 'beforeend': 'lastChild' + , 'afterend': 'nextSibling' +} +var texts = { + 'beforebegin': 'raclette' + , 'afterbegin': 'tartiflette' + , 'beforeend': 'lasagne' + , 'afterend': 'gateau aux pommes' +} + +var el = document.querySelector('#element'); + +Object.keys(possiblePositions).forEach(function(position) { + var div = document.createElement('h3'); + test(function() { + div.id = texts[position]; + el.insertAdjacentElement(position, div); + assert_equals(el[possiblePositions[position]].id, texts[position]); + }, 'insertAdjacentElement(' + position + ', ' + div + ' )'); + + test(function() { + el.insertAdjacentText(position, texts[position]); + assert_equals(el[possiblePositions[position]].textContent, texts[position]); + }, 'insertAdjacentText(' + position + ', ' + texts[position] + ' )'); +}); + +test(function() { + assert_throws_js(TypeError, function() { + el.insertAdjacentElement('afterbegin', + document.implementation.createDocumentType("html")) + }) +}, 'invalid object argument insertAdjacentElement') +test(function() { + var el = document.implementation.createHTMLDocument().documentElement; + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { + el.insertAdjacentElement('beforebegin', document.createElement('banane')) + }) +}, 'invalid caller object insertAdjacentElement') +test(function() { + var el = document.implementation.createHTMLDocument().documentElement; + assert_throws_dom("HIERARCHY_REQUEST_ERR", function() { + el.insertAdjacentText('beforebegin', 'tomate farcie') + }) +}, 'invalid caller object insertAdjacentText') +test(function() { + var div = document.createElement('h3'); + assert_throws_dom("SYNTAX_ERR", function() { + el.insertAdjacentElement('heeeee', div) + }) +}, "invalid syntax for insertAdjacentElement") +test(function() { + assert_throws_dom("SYNTAX_ERR", function() { + el.insertAdjacentText('hoooo', 'magret de canard') + }) +}, "invalid syntax for insertAdjacentText") +test(function() { + var div = document.createElement('div'); + assert_equals(div.insertAdjacentElement("beforebegin", el), null); +}, 'insertAdjacentText should return null'); + +</script> diff --git a/testing/web-platform/tests/dom/nodes/mutationobservers.js b/testing/web-platform/tests/dom/nodes/mutationobservers.js new file mode 100644 index 0000000000..a95529ab39 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/mutationobservers.js @@ -0,0 +1,76 @@ +// Compares a mutation record to a predefined one +// mutationToCheck is a mutation record from the user agent +// expectedRecord is a mutation record minted by the test +// for expectedRecord, if properties are omitted, they get default ones +function checkRecords(target, mutationToCheck, expectedRecord) { + var mr1; + var mr2; + + + function checkField(property, isArray) { + var field = mr2[property]; + if (isArray === undefined) { + isArray = false; + } + if (field instanceof Function) { + field = field(); + } else if (field === undefined) { + if (isArray) { + field = new Array(); + } else { + field = null; + } + } + if (isArray) { + assert_array_equals(mr1[property], field, property + " didn't match"); + } else { + assert_equals(mr1[property], field, property + " didn't match"); + } + } + + assert_equals(mutationToCheck.length, expectedRecord.length, "mutation records must match"); + for (var item = 0; item < mutationToCheck.length; item++) { + mr1 = mutationToCheck[item]; + mr2 = expectedRecord[item]; + + if (mr2.target instanceof Function) { + assert_equals(mr1.target, mr2.target(), "target node must match"); + } else if (mr2.target !== undefined) { + assert_equals(mr1.target, mr2.target, "target node must match"); + } else { + assert_equals(mr1.target, target, "target node must match"); + } + + checkField("type"); + checkField("addedNodes", true); + checkField("removedNodes", true); + checkField("previousSibling"); + checkField("nextSibling"); + checkField("attributeName"); + checkField("attributeNamespace"); + checkField("oldValue"); + }; +} + +function runMutationTest(node, mutationObserverOptions, mutationRecordSequence, mutationFunction, description, target) { + var test = async_test(description); + + + function moc(mrl, obs) { + test.step( + function () { + if (target === undefined) target = node; + checkRecords(target, mrl, mutationRecordSequence); + test.done(); + } + ); + } + + test.step( + function () { + (new MutationObserver(moc)).observe(node, mutationObserverOptions); + mutationFunction(); + } + ); + return mutationRecordSequence.length +} diff --git a/testing/web-platform/tests/dom/nodes/node-appendchild-crash.html b/testing/web-platform/tests/dom/nodes/node-appendchild-crash.html new file mode 100644 index 0000000000..245de87f2d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/node-appendchild-crash.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" href="mailto:masonf@chromium.org"> +<link rel="help" href="https://crbug.com/1210480"> +<meta name="assert" content="The renderer should not crash."> + +<iframe id=iframe></iframe> +<select>Text Node + <option id=option></option> +</select> + +<script> + window.onload=function() { + iframe.addEventListener('DOMNodeInsertedIntoDocument',function() {}); + option.remove(); + iframe.contentDocument.body.appendChild(document.body); + } +</script> diff --git a/testing/web-platform/tests/dom/nodes/pre-insertion-validation-hierarchy.js b/testing/web-platform/tests/dom/nodes/pre-insertion-validation-hierarchy.js new file mode 100644 index 0000000000..6ef2576df2 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/pre-insertion-validation-hierarchy.js @@ -0,0 +1,86 @@ +/** + * Validations where `child` argument is irrelevant. + * @param {Function} methodName + */ +function preInsertionValidateHierarchy(methodName) { + function insert(parent, node) { + if (parent[methodName].length > 1) { + // This is for insertBefore(). We can't blindly pass `null` for all methods + // as doing so will move nodes before validation. + parent[methodName](node, null); + } else { + parent[methodName](node); + } + } + + // Step 2 + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", () => insert(doc.body, doc.body)); + assert_throws_dom("HierarchyRequestError", () => insert(doc.body, doc.documentElement)); + }, "If node is a host-including inclusive ancestor of parent, then throw a HierarchyRequestError DOMException."); + + // Step 4 + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const doc2 = document.implementation.createHTMLDocument("title2"); + assert_throws_dom("HierarchyRequestError", () => insert(doc, doc2)); + }, "If node is not a DocumentFragment, DocumentType, Element, Text, ProcessingInstruction, or Comment node, then throw a HierarchyRequestError DOMException."); + + // Step 5, in case of inserting a text node into a document + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + assert_throws_dom("HierarchyRequestError", () => insert(doc, doc.createTextNode("text"))); + }, "If node is a Text node and parent is a document, then throw a HierarchyRequestError DOMException."); + + // Step 5, in case of inserting a doctype into a non-document + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const doctype = doc.childNodes[0]; + assert_throws_dom("HierarchyRequestError", () => insert(doc.createElement("a"), doctype)); + }, "If node is a doctype and parent is not a document, then throw a HierarchyRequestError DOMException.") + + // Step 6, in case of DocumentFragment including multiple elements + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + doc.documentElement.remove(); + const df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + df.appendChild(doc.createElement("b")); + assert_throws_dom("HierarchyRequestError", () => insert(doc, df)); + }, "If node is a DocumentFragment with multiple elements and parent is a document, then throw a HierarchyRequestError DOMException."); + + // Step 6, in case of DocumentFragment has multiple elements when document already has an element + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const df = doc.createDocumentFragment(); + df.appendChild(doc.createElement("a")); + assert_throws_dom("HierarchyRequestError", () => insert(doc, df)); + }, "If node is a DocumentFragment with an element and parent is a document with another element, then throw a HierarchyRequestError DOMException."); + + // Step 6, in case of an element + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const el = doc.createElement("a"); + assert_throws_dom("HierarchyRequestError", () => insert(doc, el)); + }, "If node is an Element and parent is a document with another element, then throw a HierarchyRequestError DOMException."); + + // Step 6, in case of a doctype when document already has another doctype + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const doctype = doc.childNodes[0].cloneNode(); + doc.documentElement.remove(); + assert_throws_dom("HierarchyRequestError", () => insert(doc, doctype)); + }, "If node is a doctype and parent is a document with another doctype, then throw a HierarchyRequestError DOMException."); + + // Step 6, in case of a doctype when document has an element + if (methodName !== "prepend") { + // Skip `.prepend` as this doesn't throw if `child` is an element + test(() => { + const doc = document.implementation.createHTMLDocument("title"); + const doctype = doc.childNodes[0].cloneNode(); + doc.childNodes[0].remove(); + assert_throws_dom("HierarchyRequestError", () => insert(doc, doctype)); + }, "If node is a doctype and parent is a document with an element, then throw a HierarchyRequestError DOMException."); + } +} diff --git a/testing/web-platform/tests/dom/nodes/pre-insertion-validation-notfound.js b/testing/web-platform/tests/dom/nodes/pre-insertion-validation-notfound.js new file mode 100644 index 0000000000..705283fa23 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/pre-insertion-validation-notfound.js @@ -0,0 +1,108 @@ +function getNonParentNodes() { + return [ + document.implementation.createDocumentType("html", "", ""), + document.createTextNode("text"), + document.implementation.createDocument(null, "foo", null).createProcessingInstruction("foo", "bar"), + document.createComment("comment"), + document.implementation.createDocument(null, "foo", null).createCDATASection("data"), + ]; +} + +function getNonInsertableNodes() { + return [ + document.implementation.createHTMLDocument("title") + ]; +} + +function getNonDocumentParentNodes() { + return [ + document.createElement("div"), + document.createDocumentFragment(), + ]; +} + +// Test that the steps happen in the right order, to the extent that it's +// observable. The variable names "parent", "child", and "node" match the +// corresponding variables in the replaceChild algorithm in these tests. + +// Step 1 happens before step 3. +test(function() { + var illegalParents = getNonParentNodes(); + var child = document.createElement("div"); + var node = document.createElement("div"); + illegalParents.forEach(function (parent) { + assert_throws_dom("HierarchyRequestError", function() { + insertFunc.call(parent, node, child); + }); + }); +}, "Should check the 'parent' type before checking whether 'child' is a child of 'parent'"); + +// Step 2 happens before step 3. +test(function() { + var parent = document.createElement("div"); + var child = document.createElement("div"); + var node = document.createElement("div"); + + node.appendChild(parent); + assert_throws_dom("HierarchyRequestError", function() { + insertFunc.call(parent, node, child); + }); +}, "Should check that 'node' is not an ancestor of 'parent' before checking whether 'child' is a child of 'parent'"); + +// Step 3 happens before step 4. +test(function() { + var parent = document.createElement("div"); + var child = document.createElement("div"); + + var illegalChildren = getNonInsertableNodes(); + illegalChildren.forEach(function (node) { + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); + }); +}, "Should check whether 'child' is a child of 'parent' before checking whether 'node' is of a type that can have a parent."); + + +// Step 3 happens before step 5. +test(function() { + var child = document.createElement("div"); + + var node = document.createTextNode(""); + var parent = document.implementation.createDocument(null, "foo", null); + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); + + node = document.implementation.createDocumentType("html", "", ""); + getNonDocumentParentNodes().forEach(function (parent) { + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); + }); +}, "Should check whether 'child' is a child of 'parent' before checking whether 'node' is of a type that can have a parent of the type that 'parent' is."); + +// Step 3 happens before step 6. +test(function() { + var child = document.createElement("div"); + var parent = document.implementation.createDocument(null, null, null); + + var node = document.createDocumentFragment(); + node.appendChild(document.createElement("div")); + node.appendChild(document.createElement("div")); + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); + + node = document.createElement("div"); + parent.appendChild(document.createElement("div")); + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); + + parent.firstChild.remove(); + parent.appendChild(document.implementation.createDocumentType("html", "", "")); + node = document.implementation.createDocumentType("html", "", "") + assert_throws_dom("NotFoundError", function() { + insertFunc.call(parent, node, child); + }); +}, "Should check whether 'child' is a child of 'parent' before checking whether 'node' can be inserted into the document given the kids the document has right now."); diff --git a/testing/web-platform/tests/dom/nodes/prepend-on-Document.html b/testing/web-platform/tests/dom/nodes/prepend-on-Document.html new file mode 100644 index 0000000000..1d6d43a463 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/prepend-on-Document.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>DocumentType.prepend</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-parentnode-prepend"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +function test_prepend_on_Document() { + + var node = document.implementation.createDocument(null, null); + test(function() { + var parent = node.cloneNode(); + parent.prepend(); + assert_array_equals(parent.childNodes, []); + }, 'Document.prepend() without any argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + parent.prepend(x); + assert_array_equals(parent.childNodes, [x]); + }, 'Document.prepend() with only one element as an argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + var y = document.createElement('y'); + parent.appendChild(x); + assert_throws_dom('HierarchyRequestError', function() { parent.prepend(y); }); + assert_array_equals(parent.childNodes, [x]); + }, 'Document.append() with only one element as an argument, on a Document having one child.'); + + test(function() { + var parent = node.cloneNode(); + assert_throws_dom('HierarchyRequestError', function() { parent.prepend('text'); }); + assert_array_equals(parent.childNodes, []); + }, 'Document.prepend() with text as an argument, on a Document having no child.'); + + test(function() { + var parent = node.cloneNode(); + var x = document.createElement('x'); + var y = document.createElement('y'); + assert_throws_dom('HierarchyRequestError', function() { parent.prepend(x, y); }); + assert_array_equals(parent.childNodes, []); + }, 'Document.prepend() with two elements as the argument, on a Document having no child.'); + +} + +test_prepend_on_Document(); + +</script> +</html> diff --git a/testing/web-platform/tests/dom/nodes/productions.js b/testing/web-platform/tests/dom/nodes/productions.js new file mode 100644 index 0000000000..218797fc45 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/productions.js @@ -0,0 +1,3 @@ +var invalid_names = ["", "invalid^Name", "\\", "'", '"', "0", "0:a"] // XXX +var valid_names = ["x", "X", ":", "a:0"] +var invalid_qnames = [":a", "b:", "x:y:z"] // XXX diff --git a/testing/web-platform/tests/dom/nodes/query-target-in-load-event.html b/testing/web-platform/tests/dom/nodes/query-target-in-load-event.html new file mode 100644 index 0000000000..2835286f96 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/query-target-in-load-event.html @@ -0,0 +1,13 @@ +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe></iframe> + +<script> + let test = async_test('document.querySelector(":target") must work when called in the window.load event'); + let iframe = document.querySelector("iframe"); + window.addEventListener("message", test.step_func_done(event => { + assert_equals(event.data, "PASS"); + })); + iframe.src = "./query-target-in-load-event.part.html#target"; +</script> diff --git a/testing/web-platform/tests/dom/nodes/query-target-in-load-event.part.html b/testing/web-platform/tests/dom/nodes/query-target-in-load-event.part.html new file mode 100644 index 0000000000..7eb1baf15f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/query-target-in-load-event.part.html @@ -0,0 +1,10 @@ +<!-- Used by ./query-target-in-load-event.html --> +<script> + window.onload = function() { + let target = document.querySelector(":target"); + let expected = document.querySelector("#target"); + window.parent.postMessage(target == expected ? "PASS" : "FAIL", "*"); + }; +</script> + +<div id="target"></div> diff --git a/testing/web-platform/tests/dom/nodes/remove-and-adopt-thcrash.html b/testing/web-platform/tests/dom/nodes/remove-and-adopt-thcrash.html new file mode 100644 index 0000000000..d37015ec9f --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/remove-and-adopt-thcrash.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>Test for a Chrome crash when adopting a node into another document</title> +<link rel="help" href="https://crbug.com/981384"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="d1"></div> +<div id="d2"></div> +<script> + test(() => { + d1.appendChild(document.createElement("iframe")); + d2.remove(); + const adopted_div = d1; + const popup = window.open(); + assert_equals(adopted_div.ownerDocument, document); + popup.document.body.appendChild(document.body); + assert_equals(adopted_div.ownerDocument, popup.document); + }, "Check that removing a node and then adopting its parent into a different window/document doesn't crash."); +</script> diff --git a/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe-ref.html b/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe-ref.html new file mode 100644 index 0000000000..98de2b6883 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe-ref.html @@ -0,0 +1,4 @@ +<!doctype html> +<title>DOM Test Reference</title> +<p>You should see the word PASS below.</p> +<div>PASS</div> diff --git a/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe.html b/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe.html new file mode 100644 index 0000000000..612aed637d --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/remove-from-shadow-host-and-adopt-into-iframe.html @@ -0,0 +1,29 @@ +<!doctype html> +<html class="reftest-wait"> + <head> + <title>Adopting a shadow host child into an iframe</title> + <link rel="help" href="https://dom.spec.whatwg.org/#concept-node-adopt"> + <link rel="match" href="remove-from-shadow-host-and-adopt-into-iframe-ref.html"> + <style> + iframe { border: 0; } + </style> + <script src="/common/reftest-wait.js"></script> + <script> + onload = () => { + const root = host.attachShadow({mode:"open"}); + root.innerHTML = "<slot>"; + // force a layout + host.offsetTop; + iframe.contentWindow.document.body.style.margin = 0; + iframe.contentWindow.document.body.appendChild(adopted); + host.remove(); + takeScreenshot(); + } + </script> + </head> + <body> + <p>You should see the word PASS below.</p> + <iframe id="iframe"></iframe> + <div id="host"><span id="adopted">PASS</span></div> + </body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/remove-unscopable.html b/testing/web-platform/tests/dom/nodes/remove-unscopable.html new file mode 100644 index 0000000000..0238b0fa97 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/remove-unscopable.html @@ -0,0 +1,32 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id="testDiv" onclick="result1 = remove; result2 = this.remove;"></div> +<script> +var result1; +var result2; +var unscopables = [ + "before", + "after", + "replaceWith", + "remove", + "prepend", + "append" +]; +for (var i in unscopables) { + var name = unscopables[i]; + window[name] = "Hello there"; + result1 = result2 = undefined; + test(function () { + assert_true(Element.prototype[Symbol.unscopables][name]); + var div = document.querySelector('#testDiv'); + div.setAttribute( + "onclick", "result1 = " + name + "; result2 = this." + name + ";"); + div.dispatchEvent(new Event("click")); + assert_equals(typeof result1, "string"); + assert_equals(typeof result2, "function"); + }, name + "() should be unscopable"); +} +</script> diff --git a/testing/web-platform/tests/dom/nodes/rootNode.html b/testing/web-platform/tests/dom/nodes/rootNode.html new file mode 100644 index 0000000000..784831da0e --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/rootNode.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset=utf-8> +<title>Node.prototype.getRootNode()</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-getrootnode"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<script> + +test(function () { + var shadowHost = document.createElement('div'); + document.body.appendChild(shadowHost); + + var shadowRoot = shadowHost.attachShadow({mode: 'open'}); + shadowRoot.innerHTML = '<div class="shadowChild">content</div>'; + + var shadowChild = shadowRoot.querySelector('.shadowChild'); + assert_equals(shadowChild.getRootNode({composed: true}), document, "getRootNode() must return context object's shadow-including root if options's composed is true"); + assert_equals(shadowChild.getRootNode({composed: false}), shadowRoot, "getRootNode() must return context object's root if options's composed is false"); + assert_equals(shadowChild.getRootNode(), shadowRoot, "getRootNode() must return context object's root if options's composed is default false"); + +}, "getRootNode() must return context object's shadow-including root if options's composed is true, and context object's root otherwise"); + +test(function () { + var element = document.createElement('div'); + assert_equals(element.getRootNode(), element, 'getRootNode() on an element without a parent must return the element itself'); + + var text = document.createTextNode(''); + assert_equals(text.getRootNode(), text, 'getRootNode() on a text node without a parent must return the text node itself'); + + var processingInstruction = document.createProcessingInstruction('target', 'data'); + assert_equals(processingInstruction.getRootNode(), processingInstruction, 'getRootNode() on a processing instruction node without a parent must return the processing instruction node itself'); + + assert_equals(document.getRootNode(), document, 'getRootNode() on a document node must return the document itself'); + +}, 'getRootNode() must return the context object when it does not have any parent'); + +test(function () { + var parent = document.createElement('div'); + + var element = document.createElement('div'); + parent.appendChild(element); + assert_equals(element.getRootNode(), parent, 'getRootNode() on an element with a single ancestor must return the parent node'); + + var text = document.createTextNode(''); + parent.appendChild(text); + assert_equals(text.getRootNode(), parent, 'getRootNode() on a text node with a single ancestor must return the parent node'); + + var processingInstruction = document.createProcessingInstruction('target', 'data'); + parent.appendChild(processingInstruction) + assert_equals(processingInstruction.getRootNode(), parent, 'getRootNode() on a processing instruction node with a single ancestor must return the parent node'); + +}, 'getRootNode() must return the parent node of the context object when the context object has a single ancestor not in a document'); + +test(function () { + var parent = document.createElement('div'); + document.body.appendChild(parent); + + var element = document.createElement('div'); + parent.appendChild(element); + assert_equals(element.getRootNode(), document, 'getRootNode() on an element inside a document must return the document'); + + var text = document.createTextNode(''); + parent.appendChild(text); + assert_equals(text.getRootNode(), document, 'getRootNode() on a text node inside a document must return the document'); + + var processingInstruction = document.createProcessingInstruction('target', 'data'); + parent.appendChild(processingInstruction) + assert_equals(processingInstruction.getRootNode(), document, 'getRootNode() on a processing instruction node inside a document must return the document'); +}, 'getRootNode() must return the document when a node is in document'); + +test(function () { + var fragment = document.createDocumentFragment(); + var parent = document.createElement('div'); + fragment.appendChild(parent); + + var element = document.createElement('div'); + parent.appendChild(element); + assert_equals(element.getRootNode(), fragment, 'getRootNode() on an element inside a document fragment must return the fragment'); + + var text = document.createTextNode(''); + parent.appendChild(text); + assert_equals(text.getRootNode(), fragment, 'getRootNode() on a text node inside a document fragment must return the fragment'); + + var processingInstruction = document.createProcessingInstruction('target', 'data'); + parent.appendChild(processingInstruction) + assert_equals(processingInstruction.getRootNode(), fragment, + 'getRootNode() on a processing instruction node inside a document fragment must return the fragment'); +}, 'getRootNode() must return a document fragment when a node is in the fragment'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/nodes/selectors.js b/testing/web-platform/tests/dom/nodes/selectors.js new file mode 100644 index 0000000000..5e05547c9a --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/selectors.js @@ -0,0 +1,755 @@ +// Bit-mapped flags to indicate which tests the selector is suitable for +var TEST_QSA = 0x01; // querySelector() and querySelectorAll() tests +var TEST_FIND = 0x04; // find() and findAll() tests, may be unsuitable for querySelector[All] +var TEST_MATCH = 0x10; // matches() tests + +/* + * All of these invalid selectors should result in a SyntaxError being thrown by the APIs. + * + * name: A descriptive name of the selector being tested + * selector: The selector to test + */ +var invalidSelectors = [ + {name: "Empty String", selector: ""}, + {name: "Invalid character", selector: "["}, + {name: "Invalid character", selector: "]"}, + {name: "Invalid character", selector: "("}, + {name: "Invalid character", selector: ")"}, + {name: "Invalid character", selector: "{"}, + {name: "Invalid character", selector: "}"}, + {name: "Invalid character", selector: "<"}, + {name: "Invalid character", selector: ">"}, + {name: "Invalid ID", selector: "#"}, + {name: "Invalid group of selectors", selector: "div,"}, + {name: "Invalid class", selector: "."}, + {name: "Invalid class", selector: ".5cm"}, + {name: "Invalid class", selector: "..test"}, + {name: "Invalid class", selector: ".foo..quux"}, + {name: "Invalid class", selector: ".bar."}, + {name: "Invalid combinator", selector: "div % address, p"}, + {name: "Invalid combinator", selector: "div ++ address, p"}, + {name: "Invalid combinator", selector: "div ~~ address, p"}, + {name: "Invalid [att=value] selector", selector: "[*=test]"}, + {name: "Invalid [att=value] selector", selector: "[*|*=test]"}, + {name: "Invalid [att=value] selector", selector: "[class= space unquoted ]"}, + {name: "Unknown pseudo-class", selector: "div:example"}, + {name: "Unknown pseudo-class", selector: ":example"}, + {name: "Unknown pseudo-class", selector: "div:linkexample"}, + {name: "Unknown pseudo-element", selector: "div::example"}, + {name: "Unknown pseudo-element", selector: "::example"}, + {name: "Invalid pseudo-element", selector: ":::before"}, + {name: "Invalid pseudo-element", selector: ":: before"}, + {name: "Undeclared namespace", selector: "ns|div"}, + {name: "Undeclared namespace", selector: ":not(ns|div)"}, + {name: "Invalid namespace", selector: "^|div"}, + {name: "Invalid namespace", selector: "$|div"}, + {name: "Relative selector", selector: ">*"}, +]; + +/* + * All of these should be valid selectors, expected to match zero or more elements in the document. + * None should throw any errors. + * + * name: A descriptive name of the selector being tested + * selector: The selector to test + * expect: A list of IDs of the elements expected to be matched. List must be given in tree order. + * exclude: An array of contexts to exclude from testing. The valid values are: + * ["document", "element", "fragment", "detached", "html", "xhtml"] + * The "html" and "xhtml" values represent the type of document being queried. These are useful + * for tests that are affected by differences between HTML and XML, such as case sensitivity. + * level: An integer indicating the CSS or Selectors level in which the selector being tested was introduced. + * testType: A bit-mapped flag indicating the type of test. + * + * Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite. + */ +var validSelectors = [ + // Type Selector + {name: "Type selector, matching html element", selector: "html", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Type selector, matching html element", selector: "html", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA}, + {name: "Type selector, matching body element", selector: "body", expect: ["body"], exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Type selector, matching body element", selector: "body", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA}, + + // Universal Selector + {name: "Universal selector, matching all elements", selector: "*", expect: ["universal", "universal-p1", "universal-code1", "universal-hr1", "universal-pre1", "universal-span1", "universal-p2", "universal-a1", "universal-address1", "universal-code2", "universal-a2"], level: 2, testType: TEST_MATCH}, + {name: "Universal selector, matching all children of element with specified ID", selector: "#universal>*", expect: ["universal-p1", "universal-hr1", "universal-pre1", "universal-p2", "universal-address1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Universal selector, matching all grandchildren of element with specified ID", selector: "#universal>*>*", expect: ["universal-code1", "universal-span1", "universal-a1", "universal-code2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Universal selector, matching all children of empty element with specified ID", selector: "#empty>*", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Universal selector, matching all descendants of element with specified ID", selector: "#universal *", expect: ["universal-p1", "universal-code1", "universal-hr1", "universal-pre1", "universal-span1", "universal-p2", "universal-a1", "universal-address1", "universal-code2", "universal-a2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // Attribute Selectors + // - presence [att] + {name: "Attribute presence selector, matching align attribute with value", selector: ".attr-presence-div1[align]", expect: ["attr-presence-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, matching align attribute with empty value", selector: ".attr-presence-div2[align]", expect: ["attr-presence-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, matching title attribute, case insensitivity", selector: "#attr-presence [*|TiTlE]", expect: ["attr-presence-a1", "attr-presence-span1", "attr-presence-i1"], exclude: ["xhtml"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, not matching title attribute, case sensitivity", selector: "#attr-presence [*|TiTlE]", expect: [], exclude: ["html"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, matching custom data-* attribute", selector: "[data-attr-presence]", expect: ["attr-presence-pre1", "attr-presence-blockquote1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, not matching attribute with similar name", selector: ".attr-presence-div3[align], .attr-presence-div4[align]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Attribute presence selector, matching attribute with non-ASCII characters", selector: "ul[data-中文]", expect: ["attr-presence-ul1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, not matching default option without selected attribute", selector: "#attr-presence-select1 option[selected]", expect: [] /* no matches */, level: 2, testType: TEST_QSA}, + {name: "Attribute presence selector, matching option with selected attribute", selector: "#attr-presence-select2 option[selected]", expect: ["attr-presence-select2-option4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute presence selector, matching multiple options with selected attributes", selector: "#attr-presence-select3 option[selected]", expect: ["attr-presence-select3-option2", "attr-presence-select3-option3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - value [att=val] + {name: "Attribute value selector, matching align attribute with value", selector: "#attr-value [align=\"center\"]", expect: ["attr-value-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector, matching align attribute with value, unclosed bracket", selector: "#attr-value [align=\"center\"", expect: ["attr-value-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector, matching align attribute with empty value", selector: "#attr-value [align=\"\"]", expect: ["attr-value-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector, not matching align attribute with partial value", selector: "#attr-value [align=\"c\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Attribute value selector, not matching align attribute with incorrect value", selector: "#attr-value [align=\"centera\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Attribute value selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-value=\"\\e9\"]", expect: ["attr-value-div3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector, matching custom data-* attribute with escaped character", selector: "[data-attr-value\_foo=\"\\e9\"]", expect: ["attr-value-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector with single-quoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type='hidden'],#attr-value input[type='radio']", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector with double-quoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type=\"hidden\"],#attr-value input[type='radio']", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector with unquoted value, matching multiple inputs with type attributes", selector: "#attr-value input[type=hidden],#attr-value input[type=radio]", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute value selector, matching attribute with value using non-ASCII characters", selector: "[data-attr-value=中文]", expect: ["attr-value-div5"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - whitespace-separated list [att~=val] + {name: "Attribute whitespace-separated list selector, matching class attribute with value", selector: "#attr-whitespace [class~=\"div1\"]", expect: ["attr-whitespace-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector, not matching class attribute with empty value", selector: "#attr-whitespace [class~=\"\"]", expect: [] /*no matches*/ , level: 2, testType: TEST_QSA}, + {name: "Attribute whitespace-separated list selector, not matching class attribute with partial value", selector: "[data-attr-whitespace~=\"div\"]", expect: [] /*no matches*/ , level: 2, testType: TEST_QSA}, + {name: "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-whitespace~=\"\\0000e9\"]", expect: ["attr-whitespace-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character", selector: "[data-attr-whitespace\_foo~=\"\\e9\"]", expect: ["attr-whitespace-div5"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes", selector: "#attr-whitespace a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with double-quoted value, not matching value with space", selector: "#attr-whitespace a[rel~=\"book mark\"]", expect: [] /* no matches */, level: 2, testType: TEST_QSA}, + {name: "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters", selector: "#attr-whitespace [title~=中文]", expect: ["attr-whitespace-p1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - hyphen-separated list [att|=val] + {name: "Attribute hyphen-separated list selector, not matching unspecified lang attribute", selector: "#attr-hyphen-div1[lang|=\"en\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Attribute hyphen-separated list selector, matching lang attribute with exact value", selector: "#attr-hyphen-div2[lang|=\"fr\"]", expect: ["attr-hyphen-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute hyphen-separated list selector, matching lang attribute with partial value", selector: "#attr-hyphen-div3[lang|=\"en\"]", expect: ["attr-hyphen-div3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute hyphen-separated list selector, not matching incorrect value", selector: "#attr-hyphen-div4[lang|=\"es-AR\"]", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + + // - substring begins-with [att^=val] (Level 3) + {name: "Attribute begins with selector, matching href attributes beginning with specified substring", selector: "#attr-begins a[href^=\"http://www\"]", expect: ["attr-begins-a1", "attr-begins-a3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute begins with selector, matching lang attributes beginning with specified substring, ", selector: "#attr-begins [lang^=\"en-\"]", expect: ["attr-begins-div2", "attr-begins-div4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute begins with selector, not matching class attribute with empty value", selector: "#attr-begins [class^=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "Attribute begins with selector, not matching class attribute not beginning with specified substring", selector: "#attr-begins [class^=apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring", selector: "#attr-begins [class^=' apple']", expect: ["attr-begins-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring", selector: "#attr-begins [class^=\" apple\"]", expect: ["attr-begins-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring", selector: "#attr-begins [class^= apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - substring ends-with [att$=val] (Level 3) + {name: "Attribute ends with selector, matching href attributes ending with specified substring", selector: "#attr-ends a[href$=\".org\"]", expect: ["attr-ends-a1", "attr-ends-a3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute ends with selector, matching lang attributes ending with specified substring, ", selector: "#attr-ends [lang$=\"-CH\"]", expect: ["attr-ends-div2", "attr-ends-div4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute ends with selector, not matching class attribute with empty value", selector: "#attr-ends [class$=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "Attribute ends with selector, not matching class attribute not ending with specified substring", selector: "#attr-ends [class$=apple]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring", selector: "#attr-ends [class$='apple ']", expect: ["attr-ends-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring", selector: "#attr-ends [class$=\"apple \"]", expect: ["attr-ends-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring", selector: "#attr-ends [class$=apple ]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - substring contains [att*=val] (Level 3) + {name: "Attribute contains selector, matching href attributes beginning with specified substring", selector: "#attr-contains a[href*=\"http://www\"]", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector, matching href attributes ending with specified substring", selector: "#attr-contains a[href*=\".org\"]", expect: ["attr-contains-a1", "attr-contains-a2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector, matching href attributes containing specified substring", selector: "#attr-contains a[href*=\".example.\"]", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector, matching lang attributes beginning with specified substring, ", selector: "#attr-contains [lang*=\"en-\"]", expect: ["attr-contains-div2", "attr-contains-div6"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector, matching lang attributes ending with specified substring, ", selector: "#attr-contains [lang*=\"-CH\"]", expect: ["attr-contains-div3", "attr-contains-div5"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector, not matching class attribute with empty value", selector: "#attr-contains [class*=\"\"]", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*=' apple']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*='orange ']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with single-quoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*='ple banana ora']", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*=\" apple\"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*=\"orange \"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*=\"ple banana ora\"]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring", selector: "#attr-contains [class*= apple]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute ending with specified substring", selector: "#attr-contains [class*=orange ]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute containing specified substring", selector: "#attr-contains [class*= banana ]", expect: ["attr-contains-p1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // Pseudo-classes + // - :root (Level 3) + {name: ":root pseudo-class selector, matching document root element", selector: ":root", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":root pseudo-class selector, not matching document root element", selector: ":root", expect: [] /*no matches*/, exclude: ["document"], level: 3, testType: TEST_QSA}, + + // - :nth-child(n) (Level 3) + // XXX write descriptions + {name: ":nth-child selector, matching the third child element", selector: "#pseudo-nth-table1 :nth-child(3)", expect: ["pseudo-nth-td3", "pseudo-nth-td9", "pseudo-nth-tr3", "pseudo-nth-td15"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-child selector, matching every third child element", selector: "#pseudo-nth li:nth-child(3n)", expect: ["pseudo-nth-li3", "pseudo-nth-li6", "pseudo-nth-li9", "pseudo-nth-li12"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-child selector, matching every second child element, starting from the fourth", selector: "#pseudo-nth li:nth-child(2n+4)", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-child selector, matching every fourth child element, starting from the third", selector: "#pseudo-nth-p1 :nth-child(4n-1)", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :nth-last-child (Level 3) + {name: ":nth-last-child selector, matching the third last child element", selector: "#pseudo-nth-table1 :nth-last-child(3)", expect: ["pseudo-nth-tr1", "pseudo-nth-td4", "pseudo-nth-td10", "pseudo-nth-td16"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-last-child selector, matching every third child element from the end", selector: "#pseudo-nth li:nth-last-child(3n)", expect: ["pseudo-nth-li1", "pseudo-nth-li4", "pseudo-nth-li7", "pseudo-nth-li10"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-last-child selector, matching every second child element from the end, starting from the fourth last", selector: "#pseudo-nth li:nth-last-child(2n+4)", expect: ["pseudo-nth-li1", "pseudo-nth-li3", "pseudo-nth-li5", "pseudo-nth-li7", "pseudo-nth-li9"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-last-child selector, matching every fourth element from the end, starting from the third last", selector: "#pseudo-nth-p1 :nth-last-child(4n-1)", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :nth-of-type(n) (Level 3) + {name: ":nth-of-type selector, matching the third em element", selector: "#pseudo-nth-p1 em:nth-of-type(3)", expect: ["pseudo-nth-em3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-of-type selector, matching every second element of their type", selector: "#pseudo-nth-p1 :nth-of-type(2n)", expect: ["pseudo-nth-em2", "pseudo-nth-span2", "pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-of-type selector, matching every second elemetn of their type, starting from the first", selector: "#pseudo-nth-p1 span:nth-of-type(2n-1)", expect: ["pseudo-nth-span1", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :nth-last-of-type(n) (Level 3) + {name: ":nth-last-of-type selector, matching the third last em element", selector: "#pseudo-nth-p1 em:nth-last-of-type(3)", expect: ["pseudo-nth-em2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-last-of-type selector, matching every second last element of their type", selector: "#pseudo-nth-p1 :nth-last-of-type(2n)", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1", "pseudo-nth-em3", "pseudo-nth-span3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":nth-last-of-type selector, matching every second last element of their type, starting from the last", selector: "#pseudo-nth-p1 span:nth-last-of-type(2n-1)", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :first-of-type (Level 3) + {name: ":first-of-type selector, matching the first em element", selector: "#pseudo-nth-p1 em:first-of-type", expect: ["pseudo-nth-em1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":first-of-type selector, matching the first of every type of element", selector: "#pseudo-nth-p1 :first-of-type", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":first-of-type selector, matching the first td element in each table row", selector: "#pseudo-nth-table1 tr :first-of-type", expect: ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :last-of-type (Level 3) + {name: ":last-of-type selector, matching the last em elemnet", selector: "#pseudo-nth-p1 em:last-of-type", expect: ["pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":last-of-type selector, matching the last of every type of element", selector: "#pseudo-nth-p1 :last-of-type", expect: ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":last-of-type selector, matching the last td element in each table row", selector: "#pseudo-nth-table1 tr :last-of-type", expect: ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :first-child + {name: ":first-child pseudo-class selector, matching first child div element", selector: "#pseudo-first-child div:first-child", expect: ["pseudo-first-child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: ":first-child pseudo-class selector, doesn't match non-first-child elements", selector: ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: ":first-child pseudo-class selector, matching first-child of multiple elements", selector: "#pseudo-first-child span:first-child", expect: ["pseudo-first-child-span1", "pseudo-first-child-span3", "pseudo-first-child-span5"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - :last-child (Level 3) + {name: ":last-child pseudo-class selector, matching last child div element", selector: "#pseudo-last-child div:last-child", expect: ["pseudo-last-child-div3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":last-child pseudo-class selector, doesn't match non-last-child elements", selector: ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: ":last-child pseudo-class selector, matching first-child of multiple elements", selector: "#pseudo-last-child span:last-child", expect: ["pseudo-last-child-span2", "pseudo-last-child-span4", "pseudo-last-child-span6"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :only-child (Level 3) + {name: ":pseudo-only-child pseudo-class selector, matching all only-child elements", selector: "#pseudo-only :only-child", expect: ["pseudo-only-span1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":pseudo-only-child pseudo-class selector, matching only-child em elements", selector: "#pseudo-only em:only-child", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - :only-of-type (Level 3) + {name: ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type", selector: "#pseudo-only :only-of-type", expect: ["pseudo-only-span1", "pseudo-only-em1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type", selector: "#pseudo-only em:only-of-type", expect: ["pseudo-only-em1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :empty (Level 3) + {name: ":empty pseudo-class selector, matching empty p elements", selector: "#pseudo-empty p:empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":empty pseudo-class selector, matching all empty elements", selector: "#pseudo-empty :empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :link and :visited + // Implementations may treat all visited links as unvisited, so these cannot be tested separately. + // The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets. + {name: ":link and :visited pseudo-class selectors, matching a and area elements with href attributes", selector: "#pseudo-link :link, #pseudo-link :visited", expect: ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: ":link and :visited pseudo-class selectors, matching no elements", selector: "#head :link, #head :visited", expect: [] /*no matches*/, exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: ":link and :visited pseudo-class selectors, not matching link elements with href attributes", selector: "#head :link, #head :visited", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA}, + {name: ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing", selector: ":link:visited", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_QSA}, + + // - :target (Level 3) + {name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", expect: [] /*no matches*/, exclude: ["document", "element"], level: 3, testType: TEST_QSA}, + {name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", expect: ["target"], exclude: ["fragment", "detached"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :lang() + {name: ":lang pseudo-class selector, matching inherited language", selector: "#pseudo-lang-div1:lang(en)", expect: ["pseudo-lang-div1"], exclude: ["detached", "fragment"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: ":lang pseudo-class selector, not matching element with no inherited language", selector: "#pseudo-lang-div1:lang(en)", expect: [] /*no matches*/, exclude: ["document", "element"], level: 2, testType: TEST_QSA}, + {name: ":lang pseudo-class selector, matching specified language with exact value", selector: "#pseudo-lang-div2:lang(fr)", expect: ["pseudo-lang-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: ":lang pseudo-class selector, matching specified language with partial value", selector: "#pseudo-lang-div3:lang(en)", expect: ["pseudo-lang-div3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: ":lang pseudo-class selector, not matching incorrect language", selector: "#pseudo-lang-div4:lang(es-AR)", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + + // - :enabled (Level 3) + {name: ":enabled pseudo-class selector, matching all enabled form controls", selector: "#pseudo-ui :enabled", expect: ["pseudo-ui-input1", "pseudo-ui-input2", "pseudo-ui-input3", "pseudo-ui-input4", "pseudo-ui-input5", "pseudo-ui-input6", + "pseudo-ui-input7", "pseudo-ui-input8", "pseudo-ui-input9", "pseudo-ui-textarea1", "pseudo-ui-button1"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":enabled pseudo-class selector, not matching link elements", selector: "#pseudo-link :enabled", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :disabled (Level 3) + {name: ":disabled pseudo-class selector, matching all disabled form controls", selector: "#pseudo-ui :disabled", expect: ["pseudo-ui-input10", "pseudo-ui-input11", "pseudo-ui-input12", "pseudo-ui-input13", "pseudo-ui-input14", "pseudo-ui-input15", + "pseudo-ui-input16", "pseudo-ui-input17", "pseudo-ui-input18", "pseudo-ui-textarea2", "pseudo-ui-button2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":disabled pseudo-class selector, not matching link elements", selector: "#pseudo-link :disabled", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :checked (Level 3) + {name: ":checked pseudo-class selector, matching checked radio buttons and checkboxes", selector: "#pseudo-ui :checked", expect: ["pseudo-ui-input4", "pseudo-ui-input6", "pseudo-ui-input13", "pseudo-ui-input15"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :not(s) (Level 3) + {name: ":not pseudo-class selector, matching ", selector: "#not>:not(div)", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":not pseudo-class selector, matching ", selector: "#not * :not(:first-child)", expect: ["not-em1", "not-em2", "not-em3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: ":not pseudo-class selector, matching nothing", selector: ":not(*)", expect: [] /* no matches */, level: 3, testType: TEST_QSA}, + {name: ":not pseudo-class selector, matching nothing", selector: ":not(*|*)", expect: [] /* no matches */, level: 3, testType: TEST_QSA}, + {name: ":not pseudo-class selector argument surrounded by spaces, matching ", selector: "#not>:not( div )", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // Pseudo-elements + // - ::first-line + {name: ":first-line pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-line", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "::first-line pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-line", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - ::first-letter + {name: ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-letter", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-letter", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - ::before + {name: ":before pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:before", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "::before pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::before", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // - ::after + {name: ":after pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:after", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "::after pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::after", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + + // Class Selectors + {name: "Class selector, matching element with specified class", selector: ".class-p", expect: ["class-p1","class-p2", "class-p3"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, chained, matching only elements with all specified classes", selector: "#class .apple.orange.banana", expect: ["class-div1", "class-div2", "class-p4", "class-div3", "class-p6", "class-div4"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class Selector, chained, with type selector", selector: "div.apple.banana.orange", expect: ["class-div1", "class-div2", "class-div3", "class-div4"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, matching element with class value using non-ASCII characters (1)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci", expect: ["class-span1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, matching multiple elements with class value using non-ASCII characters", selector: ".\u53F0\u5317", expect: ["class-span1","class-span2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, chained, matching element with multiple class values using non-ASCII characters (1)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci.\u53F0\u5317", expect: ["class-span1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, matching element with class with escaped character", selector: ".foo\\:bar", expect: ["class-span3"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Class selector, matching element with class with escaped character", selector: ".test\\.foo\\[5\\]bar", expect: ["class-span4"], level: 1, testType: TEST_QSA | TEST_MATCH}, + + // ID Selectors + {name: "ID selector, matching element with specified id", selector: "#id #id-div1", expect: ["id-div1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID selector, chained, matching element with specified id", selector: "#id-div1, #id-div1", expect: ["id-div1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID selector, chained, matching element with specified id", selector: "#id-div1, #id-div2", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID Selector, chained, with type selector", selector: "div#id-div1, div#id-div2", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID selector, not matching non-existent descendant", selector: "#id #none", expect: [] /*no matches*/, level: 1, testType: TEST_QSA}, + {name: "ID selector, not matching non-existent ancestor", selector: "#none #id-div1", expect: [] /*no matches*/, level: 1, testType: TEST_QSA}, + {name: "ID selector, matching multiple elements with duplicate id", selector: "#id-li-duplicate", expect: ["id-li-duplicate", "id-li-duplicate", "id-li-duplicate", "id-li-duplicate"], level: 1, testType: TEST_QSA | TEST_MATCH}, + + {name: "ID selector, matching id value using non-ASCII characters (1)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID selector, matching id value using non-ASCII characters (2)", selector: "#\u53F0\u5317", expect: ["\u53F0\u5317"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "ID selector, matching id values using non-ASCII characters (1)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci, #\u53F0\u5317", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci", "\u53F0\u5317"], level: 1, testType: TEST_QSA | TEST_MATCH}, + + // XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values + {name: "ID selector, matching element with id with escaped character", selector: "#\\#foo\\:bar", expect: ["#foo:bar"], level: 1, testType: TEST_QSA}, + {name: "ID selector, matching element with id with escaped character", selector: "#test\\.foo\\[5\\]bar", expect: ["test.foo[5]bar"], level: 1, testType: TEST_QSA}, + + // Namespaces + // XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id + {name: "Namespace selector, matching element with any namespace", selector: "#any-namespace *|div", expect: ["any-namespace-div1", "any-namespace-div2", "any-namespace-div3", "any-namespace-div4"], level: 3, testType: TEST_QSA}, + {name: "Namespace selector, matching div elements in no namespace only", selector: "#no-namespace |div", expect: ["no-namespace-div3"], level: 3, testType: TEST_QSA}, + {name: "Namespace selector, matching any elements in no namespace only", selector: "#no-namespace |*", expect: ["no-namespace-div3"], level: 3, testType: TEST_QSA}, + + // Combinators + // - Descendant combinator ' ' + {name: "Descendant combinator, matching element that is a descendant of an element with id", selector: "#descendant div", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element", selector: "body #descendant-div1", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element", selector: "div #descendant-div1", expect: ["descendant-div1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element with id", selector: "#descendant #descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, matching element with class that is a descendant of an element with id", selector: "#descendant .descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, matching element with class that is a descendant of an element with class", selector: ".descendant-div1 .descendant-div3", expect: ["descendant-div3"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Descendant combinator, not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1 #descendant-div4", expect: [] /*no matches*/, level: 1, testType: TEST_QSA}, + {name: "Descendant combinator, whitespace characters", selector: "#descendant\t\r\n#descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + + /* The future of this combinator is uncertain, see + * https://github.com/w3c/csswg-drafts/issues/641 + * These tests are commented out until a final decision is made on whether to + * keep the feature in the spec. + */ + + // // - Descendant combinator '>>' + // {name: "Descendant combinator '>>', matching element that is a descendant of an element with id", selector: "#descendant>>div", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element", selector: "body>>#descendant-div1", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element", selector: "div>>#descendant-div1", expect: ["descendant-div1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element with id", selector: "#descendant>>#descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with id", selector: "#descendant>>.descendant-div2", expect: ["descendant-div2"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with class", selector: ".descendant-div1>>.descendant-div3", expect: ["descendant-div3"], level: 1, testType: TEST_QSA | TEST_MATCH}, + // {name: "Descendant combinator '>>', not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1>>#descendant-div4", expect: [] /*no matches*/, level: 1, testType: TEST_QSA}, + + // - Child combinator '>' + {name: "Child combinator, matching element that is a child of an element with id", selector: "#child>div", expect: ["child-div1", "child-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element", selector: "div>#child-div1", expect: ["child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element with id", selector: "#child>#child-div1", expect: ["child-div1"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element with class", selector: "#child-div1>.child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, matching element with class that is a child of an element with class", selector: ".child-div1>.child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, not matching element with id that is not a child of an element with id", selector: "#child>#child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Child combinator, not matching element with id that is not a child of an element with class", selector: "#child-div1>.child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Child combinator, not matching element with class that is not a child of an element with class", selector: ".child-div1>.child-div3", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Child combinator, surrounded by whitespace", selector: "#child-div1\t\r\n>\t\r\n#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, whitespace after", selector: "#child-div1>\t\r\n#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, whitespace before", selector: "#child-div1\t\r\n>#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Child combinator, no whitespace", selector: "#child-div1>#child-div2", expect: ["child-div2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - Adjacent sibling combinator '+' + {name: "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id", selector: "#adjacent-div2+div", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element", selector: "div+#adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id", selector: "#adjacent-div2+.adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class", selector: ".adjacent-div2+.adjacent-div4", expect: ["adjacent-div4"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element", selector: "#adjacent div+p", expect: ["adjacent-p2"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1", expect: [] /*no matches*/, level: 2, testType: TEST_QSA}, + {name: "Adjacent sibling combinator, surrounded by whitespace", selector: "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, whitespace after", selector: "#adjacent-p2+\t\r\n#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, whitespace before", selector: "#adjacent-p2\t\r\n+#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + {name: "Adjacent sibling combinator, no whitespace", selector: "#adjacent-p2+#adjacent-p3", expect: ["adjacent-p3"], level: 2, testType: TEST_QSA | TEST_MATCH}, + + // - General sibling combinator ~ (Level 3) + {name: "General sibling combinator, matching element that is a sibling of an element with id", selector: "#sibling-div2~div", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, matching element with id that is a sibling of an element", selector: "div~#sibling-div4", expect: ["sibling-div4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, matching element with id that is a sibling of an element with id", selector: "#sibling-div2~#sibling-div4", expect: ["sibling-div4"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, matching element with class that is a sibling of an element with id", selector: "#sibling-div2~.sibling-div", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, matching p element that is a sibling of a div element", selector: "#sibling div~p", expect: ["sibling-p2", "sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, not matching element with id that is not a sibling after a p element", selector: "#sibling>p~div", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "General sibling combinator, not matching element with id that is not a sibling after an element with id", selector: "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1", expect: [] /*no matches*/, level: 3, testType: TEST_QSA}, + {name: "General sibling combinator, surrounded by whitespace", selector: "#sibling-p2\t\r\n~\t\r\n#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, whitespace after", selector: "#sibling-p2~\t\r\n#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, whitespace before", selector: "#sibling-p2\t\r\n~#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + {name: "General sibling combinator, no whitespace", selector: "#sibling-p2~#sibling-p3", expect: ["sibling-p3"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // Group of selectors (comma) + {name: "Syntax, group of selectors separator, surrounded by whitespace", selector: "#group em\t\r \n,\t\r \n#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Syntax, group of selectors separator, whitespace after", selector: "#group em,\t\r\n#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Syntax, group of selectors separator, whitespace before", selector: "#group em\t\r\n,#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + {name: "Syntax, group of selectors separator, no whitespace", selector: "#group em,#group strong", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_QSA | TEST_MATCH}, + + // ::slotted (shouldn't match anything, but is a valid selector) + {name: "Slotted selector", selector: "::slotted(foo)", expect: [], level: 3, testType: TEST_QSA}, + {name: "Slotted selector (no matching closing paren)", selector: "::slotted(foo", expect: [], level: 3, testType: TEST_QSA}, +]; + + +/* + * These selectors are intended to be used with the find(), findAll() and matches() methods. Expected results + * should be determined under the assumption that :scope will be prepended to the selector where appropriate, + * in accordance with the specification. + * + * All of these should be valid relative selectors, expected to match zero or more elements in the document. + * None should throw any errors. + * + * name: A descriptive name of the selector being tested + * + * selector: The selector to test + * + * ctx: A selector to obtain the context object to use for tests invoking context.find(), + * and to use as a single reference node for tests invoking document.find(). + * Note: context = root.querySelector(ctx); + * + * ref: A selector to obtain the reference nodes to be used for the selector. + * Note: If root is the document or an in-document element: + * refNodes = document.querySelectorAll(ref); + * Otherwise, if root is a fragment or detached element: + * refNodes = root.querySelectorAll(ref); + * + * expect: A list of IDs of the elements expected to be matched. List must be given in tree order. + * + * unexpected: A list of IDs of some elements that are not expected to match the given selector. + * This is used to verify that unexpected.matches(selector, refNode) does not match. + * + * exclude: An array of contexts to exclude from testing. The valid values are: + * ["document", "element", "fragment", "detached", "html", "xhtml"] + * The "html" and "xhtml" values represent the type of document being queried. These are useful + * for tests that are affected by differences between HTML and XML, such as case sensitivity. + * + * level: An integer indicating the CSS or Selectors level in which the selector being tested was introduced. + * + * testType: A bit-mapped flag indicating the type of test. + * + * The test function for these tests accepts a specified root node, on which the methods will be invoked during the tests. + * + * Based on whether either 'context' or 'refNodes', or both, are specified the tests will execute the following methods: + * + * Where testType is TEST_FIND: + * + * context.findAll(selector, refNodes) + * context.findAll(selector) // Only if refNodes is not specified + * root.findAll(selector, context) // Only if refNodes is not specified + * root.findAll(selector, refNodes) // Only if context is not specified + * root.findAll(selector) // Only if neither context nor refNodes is specified + * + * Where testType is TEST_QSA + * + * context.querySelectorAll(selector) + * root.querySelectorAll(selector) // Only if neither context nor refNodes is specified + * + * Equivalent tests will be run for .find() as well. + * Note: Do not specify a testType of TEST_QSA where either implied :scope or explicit refNodes + * are required. + * + * Where testType is TEST_MATCH: + * For each expected result given, within the specified root: + * + * expect.matches(selector, context) // Only where refNodes is not specified + * expect.matches(selector, refNodes) + * expect.matches(selector) // Only if neither context nor refNodes is specified + * + * The tests involving refNodes for both find(), findAll() and matches() will each be run by passing the + * collection as a NodeList, an Array and, if there is only a single element, an Element node. + * + * Note: Interactive pseudo-classes (:active :hover and :focus) have not been tested in this test suite. + */ + +var scopedSelectors = [ + //{name: "", selector: "", ctx: "", ref: "", expect: [], level: 1, testType: TEST_FIND | TEST_MATCH}, + + // Attribute Selectors + // - presence [att] + {name: "Attribute presence selector, matching align attribute with value", selector: ".attr-presence-div1[align]", ctx: "#attr-presence", expect: ["attr-presence-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, matching align attribute with empty value", selector: ".attr-presence-div2[align]", ctx: "#attr-presence", expect: ["attr-presence-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, matching title attribute, case insensitivity", selector: "[TiTlE]", ctx: "#attr-presence", expect: ["attr-presence-a1", "attr-presence-span1"], exclude: ["xhtml"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, not matching title attribute, case sensitivity", selector: "[TiTlE]", ctx: "#attr-presence", expect: [], exclude: ["html"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, matching custom data-* attribute", selector: "[data-attr-presence]", ctx: "#attr-presence", expect: ["attr-presence-pre1", "attr-presence-blockquote1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, not matching attribute with similar name", selector: ".attr-presence-div3[align], .attr-presence-div4[align]", ctx: "#attr-presence", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Attribute presence selector, matching attribute with non-ASCII characters", selector: "ul[data-中文]", ctx: "#attr-presence", expect: ["attr-presence-ul1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, not matching default option without selected attribute", selector: "#attr-presence-select1 option[selected]", ctx: "#attr-presence", expect: [] /* no matches */, level: 2, testType: TEST_FIND}, + {name: "Attribute presence selector, matching option with selected attribute", selector: "#attr-presence-select2 option[selected]", ctx: "#attr-presence", expect: ["attr-presence-select2-option4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute presence selector, matching multiple options with selected attributes", selector: "#attr-presence-select3 option[selected]", ctx: "#attr-presence", expect: ["attr-presence-select3-option2", "attr-presence-select3-option3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - value [att=val] + {name: "Attribute value selector, matching align attribute with value", selector: "[align=\"center\"]", ctx: "#attr-value", expect: ["attr-value-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector, matching align attribute with empty value", selector: "[align=\"\"]", ctx: "#attr-value", expect: ["attr-value-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector, not matching align attribute with partial value", selector: "[align=\"c\"]", ctx: "#attr-value", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Attribute value selector, not matching align attribute with incorrect value", selector: "[align=\"centera\"]", ctx: "#attr-value", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Attribute value selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-value=\"\\e9\"]", ctx: "#attr-value", expect: ["attr-value-div3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector, matching custom data-* attribute with escaped character", selector: "[data-attr-value\_foo=\"\\e9\"]", ctx: "#attr-value", expect: ["attr-value-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector with single-quoted value, matching multiple inputs with type attributes", selector: "input[type='hidden'],#attr-value input[type='radio']", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector with double-quoted value, matching multiple inputs with type attributes", selector: "input[type=\"hidden\"],#attr-value input[type='radio']", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector with unquoted value, matching multiple inputs with type attributes", selector: "input[type=hidden],#attr-value input[type=radio]", ctx: "#attr-value", expect: ["attr-value-input3", "attr-value-input4", "attr-value-input6", "attr-value-input8", "attr-value-input9"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute value selector, matching attribute with value using non-ASCII characters", selector: "[data-attr-value=中文]", ctx: "#attr-value", expect: ["attr-value-div5"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - whitespace-separated list [att~=val] + {name: "Attribute whitespace-separated list selector, matching class attribute with value", selector: "[class~=\"div1\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector, not matching class attribute with empty value", selector: "[class~=\"\"]", ctx: "#attr-whitespace", expect: [] /*no matches*/ , level: 2, testType: TEST_FIND}, + {name: "Attribute whitespace-separated list selector, not matching class attribute with partial value", selector: "[data-attr-whitespace~=\"div\"]", ctx: "#attr-whitespace", expect: [] /*no matches*/ , level: 2, testType: TEST_FIND}, + {name: "Attribute whitespace-separated list selector, matching custom data-* attribute with unicode escaped value", selector: "[data-attr-whitespace~=\"\\0000e9\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector, matching custom data-* attribute with escaped character", selector: "[data-attr-whitespace\_foo~=\"\\e9\"]", ctx: "#attr-whitespace", expect: ["attr-whitespace-div5"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with single-quoted value, matching multiple links with rel attributes", selector: "a[rel~='bookmark'], #attr-whitespace a[rel~='nofollow']", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with double-quoted value, matching multiple links with rel attributes", selector: "a[rel~=\"bookmark\"],#attr-whitespace a[rel~='nofollow']", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with unquoted value, matching multiple links with rel attributes", selector: "a[rel~=bookmark], #attr-whitespace a[rel~=nofollow]", ctx: "#attr-whitespace", expect: ["attr-whitespace-a1", "attr-whitespace-a2", "attr-whitespace-a3", "attr-whitespace-a5", "attr-whitespace-a7"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute whitespace-separated list selector with double-quoted value, not matching value with space", selector: "a[rel~=\"book mark\"]", ctx: "#attr-whitespace", expect: [] /* no matches */, level: 2, testType: TEST_FIND}, + {name: "Attribute whitespace-separated list selector, matching title attribute with value using non-ASCII characters", selector: "[title~=中文]", ctx: "#attr-whitespace", expect: ["attr-whitespace-p1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - hyphen-separated list [att|=val] + {name: "Attribute hyphen-separated list selector, not matching unspecified lang attribute", selector: "#attr-hyphen-div1[lang|=\"en\"]", ctx: "#attr-hyphen", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Attribute hyphen-separated list selector, matching lang attribute with exact value", selector: "#attr-hyphen-div2[lang|=\"fr\"]", ctx: "#attr-hyphen", expect: ["attr-hyphen-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute hyphen-separated list selector, matching lang attribute with partial value", selector: "#attr-hyphen-div3[lang|=\"en\"]", ctx: "#attr-hyphen", expect: ["attr-hyphen-div3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute hyphen-separated list selector, not matching incorrect value", selector: "#attr-hyphen-div4[lang|=\"es-AR\"]", ctx: "#attr-hyphen", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + + // - substring begins-with [att^=val] (Level 3) + {name: "Attribute begins with selector, matching href attributes beginning with specified substring", selector: "a[href^=\"http://www\"]", ctx: "#attr-begins", expect: ["attr-begins-a1", "attr-begins-a3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute begins with selector, matching lang attributes beginning with specified substring, ", selector: "[lang^=\"en-\"]", ctx: "#attr-begins", expect: ["attr-begins-div2", "attr-begins-div4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute begins with selector, not matching class attribute with empty value", selector: "[class^=\"\"]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "Attribute begins with selector, not matching class attribute not beginning with specified substring", selector: "[class^=apple]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "Attribute begins with selector with single-quoted value, matching class attribute beginning with specified substring", selector: "[class^=' apple']", ctx: "#attr-begins", expect: ["attr-begins-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute begins with selector with double-quoted value, matching class attribute beginning with specified substring", selector: "[class^=\" apple\"]", ctx: "#attr-begins", expect: ["attr-begins-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute begins with selector with unquoted value, not matching class attribute not beginning with specified substring", selector: "[class^= apple]", ctx: "#attr-begins", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - substring ends-with [att$=val] (Level 3) + {name: "Attribute ends with selector, matching href attributes ending with specified substring", selector: "a[href$=\".org\"]", ctx: "#attr-ends", expect: ["attr-ends-a1", "attr-ends-a3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute ends with selector, matching lang attributes ending with specified substring, ", selector: "[lang$=\"-CH\"]", ctx: "#attr-ends", expect: ["attr-ends-div2", "attr-ends-div4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute ends with selector, not matching class attribute with empty value", selector: "[class$=\"\"]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "Attribute ends with selector, not matching class attribute not ending with specified substring", selector: "[class$=apple]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "Attribute ends with selector with single-quoted value, matching class attribute ending with specified substring", selector: "[class$='apple ']", ctx: "#attr-ends", expect: ["attr-ends-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute ends with selector with double-quoted value, matching class attribute ending with specified substring", selector: "[class$=\"apple \"]", ctx: "#attr-ends", expect: ["attr-ends-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute ends with selector with unquoted value, not matching class attribute not ending with specified substring", selector: "[class$=apple ]", ctx: "#attr-ends", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - substring contains [att*=val] (Level 3) + {name: "Attribute contains selector, matching href attributes beginning with specified substring", selector: "a[href*=\"http://www\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector, matching href attributes ending with specified substring", selector: "a[href*=\".org\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a2"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector, matching href attributes containing specified substring", selector: "a[href*=\".example.\"]", ctx: "#attr-contains", expect: ["attr-contains-a1", "attr-contains-a3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector, matching lang attributes beginning with specified substring, ", selector: "[lang*=\"en-\"]", ctx: "#attr-contains", expect: ["attr-contains-div2", "attr-contains-div6"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector, matching lang attributes ending with specified substring, ", selector: "[lang*=\"-CH\"]", ctx: "#attr-contains", expect: ["attr-contains-div3", "attr-contains-div5"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector, not matching class attribute with empty value", selector: "[class*=\"\"]", ctx: "#attr-contains", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "Attribute contains selector with single-quoted value, matching class attribute beginning with specified substring", selector: "[class*=' apple']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with single-quoted value, matching class attribute ending with specified substring", selector: "[class*='orange ']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with single-quoted value, matching class attribute containing specified substring", selector: "[class*='ple banana ora']", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute beginning with specified substring", selector: "[class*=\" apple\"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute ending with specified substring", selector: "[class*=\"orange \"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with double-quoted value, matching class attribute containing specified substring", selector: "[class*=\"ple banana ora\"]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute beginning with specified substring", selector: "[class*= apple]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute ending with specified substring", selector: "[class*=orange ]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "Attribute contains selector with unquoted value, matching class attribute containing specified substring", selector: "[class*= banana ]", ctx: "#attr-contains", expect: ["attr-contains-p1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // Pseudo-classes + // - :root (Level 3) + {name: ":root pseudo-class selector, matching document root element", selector: ":root", expect: ["html"], exclude: ["element", "fragment", "detached"], level: 3, testType: TEST_FIND}, + {name: ":root pseudo-class selector, not matching document root element", selector: ":root", expect: [] /*no matches*/, exclude: ["document"], level: 3, testType: TEST_FIND}, + {name: ":root pseudo-class selector, not matching document root element", selector: ":root", ctx: "#html", expect: [] /*no matches*/, exclude: ["fragment", "detached"], level: 3, testType: TEST_FIND}, + + // - :nth-child(n) (Level 3) + {name: ":nth-child selector, matching the third child element", selector: ":nth-child(3)", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td3", "pseudo-nth-td9", "pseudo-nth-tr3", "pseudo-nth-td15"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector, matching every third child element", selector: "li:nth-child(3n)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li3", "pseudo-nth-li6", "pseudo-nth-li9", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector, matching every second child element, starting from the fourth", selector: "li:nth-child(2n+4)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector, matching every second child element, starting from the fourth, with whitespace", selector: "li:nth-child(2n \t\r\n+ \t\r\n4)", ctx: "#pseudo-nth", expect: ["pseudo-nth-li4", "pseudo-nth-li6", "pseudo-nth-li8", "pseudo-nth-li10", "pseudo-nth-li12"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector, matching every fourth child element, starting from the third", selector: ":nth-child(4n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector, matching every fourth child element, starting from the third, with whitespace", selector: ":nth-child(4n \t\r\n- \t\r\n1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-child selector used twice, matching ", selector: ":nth-child(1) :nth-child(1)", ctx: "#pseudo-nth", expect: ["pseudo-nth-table1", "pseudo-nth-tr1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :nth-last-child (Level 3) + {name: ":nth-last-child selector, matching the third last child element", selector: ":nth-last-child(3)", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-tr1", "pseudo-nth-td4", "pseudo-nth-td10", "pseudo-nth-td16"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-last-child selector, matching every third child element from the end", selector: "li:nth-last-child(3n)", ctx: "pseudo-nth", expect: ["pseudo-nth-li1", "pseudo-nth-li4", "pseudo-nth-li7", "pseudo-nth-li10"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-last-child selector, matching every second child element from the end, starting from the fourth last", selector: "li:nth-last-child(2n+4)", ctx: "pseudo-nth", expect: ["pseudo-nth-li1", "pseudo-nth-li3", "pseudo-nth-li5", "pseudo-nth-li7", "pseudo-nth-li9"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-last-child selector, matching every fourth element from the end, starting from the third last", selector: ":nth-last-child(4n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :nth-of-type(n) (Level 3) + {name: ":nth-of-type selector, matching the third em element", selector: "em:nth-of-type(3)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-of-type selector, matching every second element of their type", selector: ":nth-of-type(2n)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2", "pseudo-nth-span2", "pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-of-type selector, matching every second elemetn of their type, starting from the first", selector: "span:nth-of-type(2n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :nth-last-of-type(n) (Level 3) + {name: ":nth-last-of-type selector, matching the third last em element", selector: "em:nth-last-of-type(3)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em2"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-last-of-type selector, matching every second last element of their type", selector: ":nth-last-of-type(2n)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1", "pseudo-nth-em3", "pseudo-nth-span3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":nth-last-of-type selector, matching every second last element of their type, starting from the last", selector: "span:nth-last-of-type(2n-1)", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span2", "pseudo-nth-span4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :first-of-type (Level 3) + {name: ":first-of-type selector, matching the first em element", selector: "em:first-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":first-of-type selector, matching the first of every type of element", selector: ":first-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span1", "pseudo-nth-em1", "pseudo-nth-strong1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":first-of-type selector, matching the first td element in each table row", selector: "tr :first-of-type", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td1", "pseudo-nth-td7", "pseudo-nth-td13"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :last-of-type (Level 3) + {name: ":last-of-type selector, matching the last em elemnet", selector: "em:last-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":last-of-type selector, matching the last of every type of element", selector: ":last-of-type", ctx: "#pseudo-nth-p1", expect: ["pseudo-nth-span4", "pseudo-nth-strong2", "pseudo-nth-em4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":last-of-type selector, matching the last td element in each table row", selector: "tr :last-of-type", ctx: "#pseudo-nth-table1", expect: ["pseudo-nth-td6", "pseudo-nth-td12", "pseudo-nth-td18"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :first-child + {name: ":first-child pseudo-class selector, matching first child div element", selector: "div:first-child", ctx: "#pseudo-first-child", expect: ["pseudo-first-child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: ":first-child pseudo-class selector, doesn't match non-first-child elements", selector: ".pseudo-first-child-div2:first-child, .pseudo-first-child-div3:first-child", ctx: "#pseudo-first-child", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: ":first-child pseudo-class selector, matching first-child of multiple elements", selector: "span:first-child", ctx: "#pseudo-first-child", expect: ["pseudo-first-child-span1", "pseudo-first-child-span3", "pseudo-first-child-span5"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - :last-child (Level 3) + {name: ":last-child pseudo-class selector, matching last child div element", selector: "div:last-child", ctx: "#pseudo-last-child", expect: ["pseudo-last-child-div3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":last-child pseudo-class selector, doesn't match non-last-child elements", selector: ".pseudo-last-child-div1:last-child, .pseudo-last-child-div2:first-child", ctx: "#pseudo-last-child", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: ":last-child pseudo-class selector, matching first-child of multiple elements", selector: "span:last-child", ctx: "#pseudo-last-child", expect: ["pseudo-last-child-span2", "pseudo-last-child-span4", "pseudo-last-child-span6"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :only-child (Level 3) + {name: ":pseudo-only-child pseudo-class selector, matching all only-child elements", selector: ":only-child", ctx: "#pseudo-only", expect: ["pseudo-only-span1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":pseudo-only-child pseudo-class selector, matching only-child em elements", selector: "em:only-child", ctx: "#pseudo-only", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - :only-of-type (Level 3) + {name: ":pseudo-only-of-type pseudo-class selector, matching all elements with no siblings of the same type", selector: " :only-of-type", ctx: "#pseudo-only", expect: ["pseudo-only-span1", "pseudo-only-em1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":pseudo-only-of-type pseudo-class selector, matching em elements with no siblings of the same type", selector: " em:only-of-type", ctx: "#pseudo-only", expect: ["pseudo-only-em1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :empty (Level 3) + {name: ":empty pseudo-class selector, matching empty p elements", selector: "p:empty", ctx: "#pseudo-empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":empty pseudo-class selector, matching all empty elements", selector: ":empty", ctx: "#pseudo-empty", expect: ["pseudo-empty-p1", "pseudo-empty-p2", "pseudo-empty-span1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :link and :visited + // Implementations may treat all visited links as unvisited, so these cannot be tested separately. + // The only guarantee is that ":link,:visited" matches the set of all visited and unvisited links and that they are individually mutually exclusive sets. + {name: ":link and :visited pseudo-class selectors, matching a and area elements with href attributes", selector: " :link, #pseudo-link :visited", ctx: "#pseudo-link", expect: ["pseudo-link-a1", "pseudo-link-a2", "pseudo-link-area1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: ":link and :visited pseudo-class selectors, matching no elements", selector: " :link, #head :visited", ctx: "#head", expect: [] /*no matches*/, exclude: ["element", "fragment", "detached"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: ":link and :visited pseudo-class selectors, not matching link elements with href attributes", selector: " :link, #head :visited", ctx: "#head", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_FIND}, + {name: ":link and :visited pseudo-class selectors, chained, mutually exclusive pseudo-classes match nothing", selector: ":link:visited", ctx: "#html", expect: [] /*no matches*/, exclude: ["document"], level: 1, testType: TEST_FIND}, + +// XXX Figure out context or refNodes for this + // - :target (Level 3) + {name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", ctx: "", expect: [] /*no matches*/, exclude: ["document", "element"], level: 3, testType: TEST_FIND}, + {name: ":target pseudo-class selector, matching the element referenced by the URL fragment identifier", selector: ":target", ctx: "", expect: ["target"], exclude: ["fragment", "detached"], level: 3, testType: TEST_FIND}, + +// XXX Fix ctx in tests below + + // - :lang() + {name: ":lang pseudo-class selector, matching inherited language (1)", selector: "#pseudo-lang-div1:lang(en)", ctx: "", expect: ["pseudo-lang-div1"], exclude: ["detached", "fragment"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: ":lang pseudo-class selector, not matching element with no inherited language", selector: "#pseudo-lang-div1:lang(en)", ctx: "", expect: [] /*no matches*/, exclude: ["document", "element"], level: 2, testType: TEST_FIND}, + {name: ":lang pseudo-class selector, matching specified language with exact value (1)", selector: "#pseudo-lang-div2:lang(fr)", ctx: "", expect: ["pseudo-lang-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: ":lang pseudo-class selector, matching specified language with partial value (1)", selector: "#pseudo-lang-div3:lang(en)", ctx: "", expect: ["pseudo-lang-div3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: ":lang pseudo-class selector, not matching incorrect language", selector: "#pseudo-lang-div4:lang(es-AR)", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + + // - :enabled (Level 3) + {name: ":enabled pseudo-class selector, matching all enabled form controls (1)", selector: "#pseudo-ui :enabled", ctx: "", expect: ["pseudo-ui-input1", "pseudo-ui-input2", "pseudo-ui-input3", "pseudo-ui-input4", "pseudo-ui-input5", "pseudo-ui-input6", + "pseudo-ui-input7", "pseudo-ui-input8", "pseudo-ui-input9", "pseudo-ui-textarea1", "pseudo-ui-button1"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":enabled pseudo-class selector, not matching link elements (1)", selector: "#pseudo-link :enabled", ctx: "", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :disabled (Level 3) + {name: ":disabled pseudo-class selector, matching all disabled form controls (1)", selector: "#pseudo-ui :disabled", ctx: "", expect: ["pseudo-ui-input10", "pseudo-ui-input11", "pseudo-ui-input12", "pseudo-ui-input13", "pseudo-ui-input14", "pseudo-ui-input15", + "pseudo-ui-input16", "pseudo-ui-input17", "pseudo-ui-input18", "pseudo-ui-textarea2", "pseudo-ui-button2"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":disabled pseudo-class selector, not matching link elements (1)", selector: "#pseudo-link :disabled", ctx: "", expect: [] /*no matches*/, unexpected: ["pseudo-link-a1","pseudo-link-a2","pseudo-link-a3","pseudo-link-map1","pseudo-link-area1","pseudo-link-area2"], level: 3, testType: TEST_QSA | TEST_MATCH}, + + // - :checked (Level 3) + {name: ":checked pseudo-class selector, matching checked radio buttons and checkboxes (1)", selector: "#pseudo-ui :checked", ctx: "", expect: ["pseudo-ui-input4", "pseudo-ui-input6", "pseudo-ui-input13", "pseudo-ui-input15"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // - :not(s) (Level 3) + {name: ":not pseudo-class selector, matching (1)", selector: "#not>:not(div)", ctx: "", expect: ["not-p1", "not-p2", "not-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":not pseudo-class selector, matching (1)", selector: "#not * :not(:first-child)", ctx: "", expect: ["not-em1", "not-em2", "not-em3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: ":not pseudo-class selector, matching nothing", selector: ":not(*)", ctx: "", expect: [] /* no matches */, level: 3, testType: TEST_FIND}, + {name: ":not pseudo-class selector, matching nothing", selector: ":not(*|*)", ctx: "", expect: [] /* no matches */, level: 3, testType: TEST_FIND}, + + // Pseudo-elements + // - ::first-line + {name: ":first-line pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-line", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "::first-line pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-line", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - ::first-letter + {name: ":first-letter pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:first-letter", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "::first-letter pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::first-letter", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - ::before + {name: ":before pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:before", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "::before pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::before", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // - ::after + {name: ":after pseudo-element (one-colon syntax) selector, not matching any elements", selector: "#pseudo-element:after", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "::after pseudo-element (two-colon syntax) selector, not matching any elements", selector: "#pseudo-element::after", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + + // Class Selectors + {name: "Class selector, matching element with specified class (1)", selector: ".class-p", ctx: "", expect: ["class-p1","class-p2", "class-p3"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, chained, matching only elements with all specified classes (1)", selector: "#class .apple.orange.banana", ctx: "", expect: ["class-div1", "class-div2", "class-p4", "class-div3", "class-p6", "class-div4"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class Selector, chained, with type selector (1)", selector: "div.apple.banana.orange", ctx: "", expect: ["class-div1", "class-div2", "class-div3", "class-div4"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, matching element with class value using non-ASCII characters (2)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci", ctx: "", expect: ["class-span1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, matching multiple elements with class value using non-ASCII characters (1)", selector: ".\u53F0\u5317", ctx: "", expect: ["class-span1","class-span2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, chained, matching element with multiple class values using non-ASCII characters (2)", selector: ".\u53F0\u5317Ta\u0301ibe\u030Ci.\u53F0\u5317", ctx: "", expect: ["class-span1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, matching element with class with escaped character (1)", selector: ".foo\\:bar", ctx: "", expect: ["class-span3"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Class selector, matching element with class with escaped character (1)", selector: ".test\\.foo\\[5\\]bar", ctx: "", expect: ["class-span4"], level: 1, testType: TEST_FIND | TEST_MATCH}, + + // ID Selectors + {name: "ID selector, matching element with specified id (1)", selector: "#id #id-div1", ctx: "", expect: ["id-div1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID selector, chained, matching element with specified id (1)", selector: "#id-div1, #id-div1", ctx: "", expect: ["id-div1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID selector, chained, matching element with specified id (1)", selector: "#id-div1, #id-div2", ctx: "", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID Selector, chained, with type selector (1)", selector: "div#id-div1, div#id-div2", ctx: "", expect: ["id-div1", "id-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID selector, not matching non-existent descendant", selector: "#id #none", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND}, + {name: "ID selector, not matching non-existent ancestor", selector: "#none #id-div1", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND}, + {name: "ID selector, matching multiple elements with duplicate id (1)", selector: "#id-li-duplicate", ctx: "", expect: ["id-li-duplicate", "id-li-duplicate", "id-li-duplicate", "id-li-duplicate"], level: 1, testType: TEST_FIND | TEST_MATCH}, + + {name: "ID selector, matching id value using non-ASCII characters (3)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci", ctx: "", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID selector, matching id value using non-ASCII characters (4)", selector: "#\u53F0\u5317", ctx: "", expect: ["\u53F0\u5317"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "ID selector, matching id values using non-ASCII characters (2)", selector: "#\u53F0\u5317Ta\u0301ibe\u030Ci, #\u53F0\u5317", ctx: "", expect: ["\u53F0\u5317Ta\u0301ibe\u030Ci", "\u53F0\u5317"], level: 1, testType: TEST_FIND | TEST_MATCH}, + + // XXX runMatchesTest() in level2-lib.js can't handle this because obtaining the expected nodes requires escaping characters when generating the selector from 'expect' values + {name: "ID selector, matching element with id with escaped character", selector: "#\\#foo\\:bar", ctx: "", expect: ["#foo:bar"], level: 1, testType: TEST_FIND}, + {name: "ID selector, matching element with id with escaped character", selector: "#test\\.foo\\[5\\]bar", ctx: "", expect: ["test.foo[5]bar"], level: 1, testType: TEST_FIND}, + + // Namespaces + // XXX runMatchesTest() in level2-lib.js can't handle these because non-HTML elements don't have a recognised id + {name: "Namespace selector, matching element with any namespace", selector: "#any-namespace *|div", ctx: "", expect: ["any-namespace-div1", "any-namespace-div2", "any-namespace-div3", "any-namespace-div4"], level: 3, testType: TEST_FIND}, + {name: "Namespace selector, matching div elements in no namespace only", selector: "#no-namespace |div", ctx: "", expect: ["no-namespace-div3"], level: 3, testType: TEST_FIND}, + {name: "Namespace selector, matching any elements in no namespace only", selector: "#no-namespace |*", ctx: "", expect: ["no-namespace-div3"], level: 3, testType: TEST_FIND}, + + // Combinators + // - Descendant combinator ' ' + {name: "Descendant combinator, matching element that is a descendant of an element with id (1)", selector: "#descendant div", ctx: "", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element (1)", selector: "body #descendant-div1", ctx: "", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element (1)", selector: "div #descendant-div1", ctx: "", expect: ["descendant-div1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, matching element with id that is a descendant of an element with id (1)", selector: "#descendant #descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, matching element with class that is a descendant of an element with id (1)", selector: "#descendant .descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, matching element with class that is a descendant of an element with class (1)", selector: ".descendant-div1 .descendant-div3", ctx: "", expect: ["descendant-div3"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Descendant combinator, not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1 #descendant-div4", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND}, + {name: "Descendant combinator, whitespace characters (1)", selector: "#descendant\t\r\n#descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + + // // - Descendant combinator '>>' + // {name: "Descendant combinator '>>', matching element that is a descendant of an element with id (1)", selector: "#descendant>>div", ctx: "", expect: ["descendant-div1", "descendant-div2", "descendant-div3", "descendant-div4"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element (1)", selector: "body>>#descendant-div1", ctx: "", expect: ["descendant-div1"], exclude: ["detached", "fragment"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element (1)", selector: "div>>#descendant-div1", ctx: "", expect: ["descendant-div1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with id that is a descendant of an element with id (1)", selector: "#descendant>>#descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator '>>', matching element with class that is a descendant of an element with id (1)", selector: "#descendant>>.descendant-div2", ctx: "", expect: ["descendant-div2"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator, '>>', matching element with class that is a descendant of an element with class (1)", selector: ".descendant-div1>>.descendant-div3", ctx: "", expect: ["descendant-div3"], level: 1, testType: TEST_FIND | TEST_MATCH}, + // {name: "Descendant combinator '>>', not matching element with id that is not a descendant of an element with id", selector: "#descendant-div1>>#descendant-div4", ctx: "", expect: [] /*no matches*/, level: 1, testType: TEST_FIND}, + + // - Child combinator '>' + {name: "Child combinator, matching element that is a child of an element with id (1)", selector: "#child>div", ctx: "", expect: ["child-div1", "child-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element (1)", selector: "div>#child-div1", ctx: "", expect: ["child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element with id (1)", selector: "#child>#child-div1", ctx: "", expect: ["child-div1"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, matching element with id that is a child of an element with class (1)", selector: "#child-div1>.child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, matching element with class that is a child of an element with class (1)", selector: ".child-div1>.child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, not matching element with id that is not a child of an element with id", selector: "#child>#child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Child combinator, not matching element with id that is not a child of an element with class", selector: "#child-div1>.child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Child combinator, not matching element with class that is not a child of an element with class", selector: ".child-div1>.child-div3", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Child combinator, surrounded by whitespace (1)", selector: "#child-div1\t\r\n>\t\r\n#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, whitespace after (1)", selector: "#child-div1>\t\r\n#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, whitespace before (1)", selector: "#child-div1\t\r\n>#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Child combinator, no whitespace (1)", selector: "#child-div1>#child-div2", ctx: "", expect: ["child-div2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - Adjacent sibling combinator '+' + {name: "Adjacent sibling combinator, matching element that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+div", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element (1)", selector: "div+#adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with id that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+#adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with id (1)", selector: "#adjacent-div2+.adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching element with class that is an adjacent sibling of an element with class (1)", selector: ".adjacent-div2+.adjacent-div4", ctx: "", expect: ["adjacent-div4"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, matching p element that is an adjacent sibling of a div element (1)", selector: "#adjacent div+p", ctx: "", expect: ["adjacent-p2"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, not matching element with id that is not an adjacent sibling of an element with id", selector: "#adjacent-div2+#adjacent-p2, #adjacent-div2+#adjacent-div1", ctx: "", expect: [] /*no matches*/, level: 2, testType: TEST_FIND}, + {name: "Adjacent sibling combinator, surrounded by whitespace (1)", selector: "#adjacent-p2\t\r\n+\t\r\n#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, whitespace after (1)", selector: "#adjacent-p2+\t\r\n#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, whitespace before (1)", selector: "#adjacent-p2\t\r\n+#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + {name: "Adjacent sibling combinator, no whitespace (1)", selector: "#adjacent-p2+#adjacent-p3", ctx: "", expect: ["adjacent-p3"], level: 2, testType: TEST_FIND | TEST_MATCH}, + + // - General sibling combinator ~ (Level 3) + {name: "General sibling combinator, matching element that is a sibling of an element with id (1)", selector: "#sibling-div2~div", ctx: "", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, matching element with id that is a sibling of an element (1)", selector: "div~#sibling-div4", ctx: "", expect: ["sibling-div4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, matching element with id that is a sibling of an element with id (1)", selector: "#sibling-div2~#sibling-div4", ctx: "", expect: ["sibling-div4"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, matching element with class that is a sibling of an element with id (1)", selector: "#sibling-div2~.sibling-div", ctx: "", expect: ["sibling-div4", "sibling-div6"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, matching p element that is a sibling of a div element (1)", selector: "#sibling div~p", ctx: "", expect: ["sibling-p2", "sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, not matching element with id that is not a sibling after a p element (1)", selector: "#sibling>p~div", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "General sibling combinator, not matching element with id that is not a sibling after an element with id", selector: "#sibling-div2~#sibling-div3, #sibling-div2~#sibling-div1", ctx: "", expect: [] /*no matches*/, level: 3, testType: TEST_FIND}, + {name: "General sibling combinator, surrounded by whitespace (1)", selector: "#sibling-p2\t\r\n~\t\r\n#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, whitespace after (1)", selector: "#sibling-p2~\t\r\n#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, whitespace before (1)", selector: "#sibling-p2\t\r\n~#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + {name: "General sibling combinator, no whitespace (1)", selector: "#sibling-p2~#sibling-p3", ctx: "", expect: ["sibling-p3"], level: 3, testType: TEST_FIND | TEST_MATCH}, + + // Group of selectors (comma) + {name: "Syntax, group of selectors separator, surrounded by whitespace (1)", selector: "#group em\t\r \n,\t\r \n#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Syntax, group of selectors separator, whitespace after (1)", selector: "#group em,\t\r\n#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Syntax, group of selectors separator, whitespace before (1)", selector: "#group em\t\r\n,#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH}, + {name: "Syntax, group of selectors separator, no whitespace (1)", selector: "#group em,#group strong", ctx: "", expect: ["group-em1", "group-strong1"], level: 1, testType: TEST_FIND | TEST_MATCH}, +]; diff --git a/testing/web-platform/tests/dom/nodes/support/NodeList-static-length-tampered.js b/testing/web-platform/tests/dom/nodes/support/NodeList-static-length-tampered.js new file mode 100644 index 0000000000..51167e2ddc --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/support/NodeList-static-length-tampered.js @@ -0,0 +1,46 @@ +"use strict"; + +function makeStaticNodeList(length) { + const fooRoot = document.createElement("div"); + + for (var i = 0; i < length; i++) { + const el = document.createElement("span"); + el.className = "foo"; + fooRoot.append(el); + } + + document.body.append(fooRoot); + return fooRoot.querySelectorAll(".foo"); +} + +const indexOfNodeList = new Function("nodeList", ` + const __cacheBust = ${Math.random()}; + + const el = nodeList[50]; + + let index = -1; + + for (var i = 0; i < 1e5 / 2; i++) { + for (var j = 0; j < nodeList.length; j++) { + if (nodeList[j] === el) { + index = j; + break; + } + } + } + + return index; +`); + +const arrayIndexOfNodeList = new Function("nodeList", ` + const __cacheBust = ${Math.random()}; + + const el = nodeList[50]; + const {indexOf} = Array.prototype; + + for (var i = 0; i < 1e5; i++) { + var index = indexOf.call(nodeList, el); + } + + return index; +`); diff --git a/testing/web-platform/tests/dom/nodes/svg-template-querySelector.html b/testing/web-platform/tests/dom/nodes/svg-template-querySelector.html new file mode 100644 index 0000000000..5d2f634143 --- /dev/null +++ b/testing/web-platform/tests/dom/nodes/svg-template-querySelector.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector on template fragments with SVG elements</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<template id="template1"><div></div></template> +<template id="template2"><svg></svg></template> +<template id="template3"><div><svg></svg></div></template> + +<script> +"use strict"; + +test(() => { + const fragment = document.querySelector("#template1").content; + assert_not_equals(fragment.querySelector("div"), null); +}, "querySelector works on template contents fragments with HTML elements (sanity check)"); + +test(() => { + const fragment = document.querySelector("#template2").content; + assert_not_equals(fragment.querySelector("svg"), null); +}, "querySelector works on template contents fragments with SVG elements"); + +test(() => { + const fragment = document.querySelector("#template3").content; + assert_not_equals(fragment.firstChild.querySelector("svg"), null); +}, "querySelector works on template contents fragments with nested SVG elements"); +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-adopt-test.html b/testing/web-platform/tests/dom/ranges/Range-adopt-test.html new file mode 100644 index 0000000000..3735fc38fd --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-adopt-test.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script> +function createRangeWithUnparentedContainerOfSingleElement() { + const range = document.createRange(); + const container = document.createElement("container"); + const element = document.createElement("element"); + container.appendChild(element); + range.selectNode(element); + return range; +} +function nestRangeInOuterContainer(range) { + range.startContainer.ownerDocument.createElement("outer").appendChild(range.startContainer); +} +function moveNodeToNewlyCreatedDocumentWithAppendChild(node) { + document.implementation.createDocument(null, null).appendChild(node); +} + +//Tests removing only element +test(()=>{ + const range = createRangeWithUnparentedContainerOfSingleElement(); + range.startContainer.removeChild(range.startContainer.firstChild); + assert_equals(range.endOffset, 0); +}, "Range in document: Removing the only element in the range must collapse the range"); + + +//Tests removing only element after parented container moved to another document +test(()=>{ + const range = createRangeWithUnparentedContainerOfSingleElement(); + nestRangeInOuterContainer(range); + moveNodeToNewlyCreatedDocumentWithAppendChild(range.startContainer); + assert_equals(range.endOffset, 0); +}, "Parented range container moved to another document with appendChild: Moving the element to the other document must collapse the range"); + +//Tests removing only element after parentless container moved oo another document +test(()=>{ + const range = createRangeWithUnparentedContainerOfSingleElement(); + moveNodeToNewlyCreatedDocumentWithAppendChild(range.startContainer); + range.startContainer.removeChild(range.startContainer.firstChild); + assert_equals(range.endOffset, 0); +}, "Parentless range container moved to another document with appendChild: Removing the only element in the range must collapse the range"); + +//Tests removing only element after parentless container of container moved to another document +test(()=>{ + const range = createRangeWithUnparentedContainerOfSingleElement(); + nestRangeInOuterContainer(range); + moveNodeToNewlyCreatedDocumentWithAppendChild(range.startContainer.parentNode); + range.startContainer.removeChild(range.startContainer.firstChild); + assert_equals(range.endOffset, 0); +}, "Range container's parentless container moved to another document with appendChild: Removing the only element in the range must collapse the range"); +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-attributes.html b/testing/web-platform/tests/dom/ranges/Range-attributes.html new file mode 100644 index 0000000000..ced47edc50 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-attributes.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<title>Range attributes</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var r = document.createRange(); + assert_equals(r.startContainer, document) + assert_equals(r.endContainer, document) + assert_equals(r.startOffset, 0) + assert_equals(r.endOffset, 0) + assert_true(r.collapsed) + r.detach() + assert_equals(r.startContainer, document) + assert_equals(r.endContainer, document) + assert_equals(r.startOffset, 0) + assert_equals(r.endOffset, 0) + assert_true(r.collapsed) +}) +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-cloneContents.html b/testing/web-platform/tests/dom/ranges/Range-cloneContents.html new file mode 100644 index 0000000000..6064151f62 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-cloneContents.html @@ -0,0 +1,461 @@ +<!doctype html> +<title>Range.cloneContents() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<p>To debug test failures, add a query parameter "subtest" with the test id (like +"?subtest=5"). Only that test will be run. Then you can look at the resulting +iframe in the DOM. +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testDiv.parentNode.removeChild(testDiv); + +var actualIframe = document.createElement("iframe"); +actualIframe.style.display = "none"; +document.body.appendChild(actualIframe); + +var expectedIframe = document.createElement("iframe"); +expectedIframe.style.display = "none"; +document.body.appendChild(expectedIframe); + +function myCloneContents(range) { + // "Let frag be a new DocumentFragment whose ownerDocument is the same as + // the ownerDocument of the context object's start node." + var ownerDoc = range.startContainer.nodeType == Node.DOCUMENT_NODE + ? range.startContainer + : range.startContainer.ownerDocument; + var frag = ownerDoc.createDocumentFragment(); + + // "If the context object's start and end are the same, abort this method, + // returning frag." + if (range.startContainer == range.endContainer + && range.startOffset == range.endOffset) { + return frag; + } + + // "Let original start node, original start offset, original end node, and + // original end offset be the context object's start and end nodes and + // offsets, respectively." + var originalStartNode = range.startContainer; + var originalStartOffset = range.startOffset; + var originalEndNode = range.endContainer; + var originalEndOffset = range.endOffset; + + // "If original start node and original end node are the same, and they are + // a Text, ProcessingInstruction, or Comment node:" + if (range.startContainer == range.endContainer + && (range.startContainer.nodeType == Node.TEXT_NODE + || range.startContainer.nodeType == Node.COMMENT_NODE + || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // start node." + var clone = originalStartNode.cloneNode(false); + + // "Set the data of clone to the result of calling + // substringData(original start offset, original end offset − original + // start offset) on original start node." + clone.data = originalStartNode.substringData(originalStartOffset, + originalEndOffset - originalStartOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Abort this method, returning frag." + return frag; + } + + // "Let common ancestor equal original start node." + var commonAncestor = originalStartNode; + + // "While common ancestor is not an ancestor container of original end + // node, set common ancestor to its own parent." + while (!isAncestorContainer(commonAncestor, originalEndNode)) { + commonAncestor = commonAncestor.parentNode; + } + + // "If original start node is an ancestor container of original end node, + // let first partially contained child be null." + var firstPartiallyContainedChild; + if (isAncestorContainer(originalStartNode, originalEndNode)) { + firstPartiallyContainedChild = null; + // "Otherwise, let first partially contained child be the first child of + // common ancestor that is partially contained in the context object." + } else { + for (var i = 0; i < commonAncestor.childNodes.length; i++) { + if (isPartiallyContained(commonAncestor.childNodes[i], range)) { + firstPartiallyContainedChild = commonAncestor.childNodes[i]; + break; + } + } + if (!firstPartiallyContainedChild) { + throw "Spec bug: no first partially contained child!"; + } + } + + // "If original end node is an ancestor container of original start node, + // let last partially contained child be null." + var lastPartiallyContainedChild; + if (isAncestorContainer(originalEndNode, originalStartNode)) { + lastPartiallyContainedChild = null; + // "Otherwise, let last partially contained child be the last child of + // common ancestor that is partially contained in the context object." + } else { + for (var i = commonAncestor.childNodes.length - 1; i >= 0; i--) { + if (isPartiallyContained(commonAncestor.childNodes[i], range)) { + lastPartiallyContainedChild = commonAncestor.childNodes[i]; + break; + } + } + if (!lastPartiallyContainedChild) { + throw "Spec bug: no last partially contained child!"; + } + } + + // "Let contained children be a list of all children of common ancestor + // that are contained in the context object, in tree order." + // + // "If any member of contained children is a DocumentType, raise a + // HIERARCHY_REQUEST_ERR exception and abort these steps." + var containedChildren = []; + for (var i = 0; i < commonAncestor.childNodes.length; i++) { + if (isContained(commonAncestor.childNodes[i], range)) { + if (commonAncestor.childNodes[i].nodeType + == Node.DOCUMENT_TYPE_NODE) { + return "HIERARCHY_REQUEST_ERR"; + } + containedChildren.push(commonAncestor.childNodes[i]); + } + } + + // "If first partially contained child is a Text, ProcessingInstruction, or Comment node:" + if (firstPartiallyContainedChild + && (firstPartiallyContainedChild.nodeType == Node.TEXT_NODE + || firstPartiallyContainedChild.nodeType == Node.COMMENT_NODE + || firstPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // start node." + var clone = originalStartNode.cloneNode(false); + + // "Set the data of clone to the result of calling substringData() on + // original start node, with original start offset as the first + // argument and (length of original start node − original start offset) + // as the second." + clone.data = originalStartNode.substringData(originalStartOffset, + nodeLength(originalStartNode) - originalStartOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + // "Otherwise, if first partially contained child is not null:" + } else if (firstPartiallyContainedChild) { + // "Let clone be the result of calling cloneNode(false) on first + // partially contained child." + var clone = firstPartiallyContainedChild.cloneNode(false); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Let subrange be a new Range whose start is (original start node, + // original start offset) and whose end is (first partially contained + // child, length of first partially contained child)." + var subrange = ownerDoc.createRange(); + subrange.setStart(originalStartNode, originalStartOffset); + subrange.setEnd(firstPartiallyContainedChild, + nodeLength(firstPartiallyContainedChild)); + + // "Let subfrag be the result of calling cloneContents() on + // subrange." + var subfrag = myCloneContents(subrange); + + // "For each child of subfrag, in order, append that child to clone as + // its last child." + for (var i = 0; i < subfrag.childNodes.length; i++) { + clone.appendChild(subfrag.childNodes[i]); + } + } + + // "For each contained child in contained children:" + for (var i = 0; i < containedChildren.length; i++) { + // "Let clone be the result of calling cloneNode(true) of contained + // child." + var clone = containedChildren[i].cloneNode(true); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + } + + // "If last partially contained child is a Text, ProcessingInstruction, or Comment node:" + if (lastPartiallyContainedChild + && (lastPartiallyContainedChild.nodeType == Node.TEXT_NODE + || lastPartiallyContainedChild.nodeType == Node.COMMENT_NODE + || lastPartiallyContainedChild.nodeType == Node.PROCESSING_INSTRUCTION_NODE)) { + // "Let clone be the result of calling cloneNode(false) on original + // end node." + var clone = originalEndNode.cloneNode(false); + + // "Set the data of clone to the result of calling substringData(0, + // original end offset) on original end node." + clone.data = originalEndNode.substringData(0, originalEndOffset); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + // "Otherwise, if last partially contained child is not null:" + } else if (lastPartiallyContainedChild) { + // "Let clone be the result of calling cloneNode(false) on last + // partially contained child." + var clone = lastPartiallyContainedChild.cloneNode(false); + + // "Append clone as the last child of frag." + frag.appendChild(clone); + + // "Let subrange be a new Range whose start is (last partially + // contained child, 0) and whose end is (original end node, original + // end offset)." + var subrange = ownerDoc.createRange(); + subrange.setStart(lastPartiallyContainedChild, 0); + subrange.setEnd(originalEndNode, originalEndOffset); + + // "Let subfrag be the result of calling cloneContents() on + // subrange." + var subfrag = myCloneContents(subrange); + + // "For each child of subfrag, in order, append that child to clone as + // its last child." + for (var i = 0; i < subfrag.childNodes.length; i++) { + clone.appendChild(subfrag.childNodes[i]); + } + } + + // "Return frag." + return frag; +} + +function restoreIframe(iframe, i) { + // Most of this function is designed to work around the fact that Opera + // doesn't let you add a doctype to a document that no longer has one, in + // any way I can figure out. I eventually compromised on something that + // will still let Opera pass most tests that don't actually involve + // doctypes. + while (iframe.contentDocument.firstChild + && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); + } + + while (iframe.contentDocument.lastChild + && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); + } + + if (!iframe.contentDocument.firstChild) { + // This will throw an exception in Opera if we reach here, which is why + // I try to avoid it. It will never happen in a browser that obeys the + // spec, so it's really just insurance. I don't think it actually gets + // hit by anything. + iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", "")); + } + iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true)); + iframe.contentWindow.setupRangeTests(); + iframe.contentWindow.testRangeInput = testRanges[i]; + iframe.contentWindow.run(); +} + +function testCloneContents(i) { + restoreIframe(actualIframe, i); + restoreIframe(expectedIframe, i); + + var actualRange = actualIframe.contentWindow.testRange; + var expectedRange = expectedIframe.contentWindow.testRange; + var actualFrag, expectedFrag; + var actualRoots, expectedRoots; + + domTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual cloneContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated cloneContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + // NOTE: We could just assume that cloneContents() doesn't change + // anything. That would simplify these tests, taken in isolation. But + // once we've already set up the whole apparatus for extractContents() + // and deleteContents(), we just reuse it here, on the theory of "why + // not test some more stuff if it's easy to do". + // + // Just to be pedantic, we'll test not only that the tree we're + // modifying is the same in expected vs. actual, but also that all the + // nodes originally in it were the same. Typically some nodes will + // become detached when the algorithm is run, but they still exist and + // references can still be kept to them, so they should also remain the + // same. + // + // We initialize the list to all nodes, and later on remove all the + // ones which still have parents, since the parents will presumably be + // tested for isEqualNode() and checking the children would be + // redundant. + var actualAllNodes = []; + var node = furthestAncestor(actualRange.startContainer); + do { + actualAllNodes.push(node); + } while (node = nextNode(node)); + + var expectedAllNodes = []; + var node = furthestAncestor(expectedRange.startContainer); + do { + expectedAllNodes.push(node); + } while (node = nextNode(node)); + + expectedFrag = myCloneContents(expectedRange); + if (typeof expectedFrag == "string") { + assert_throws_dom( + expectedFrag, + actualIframe.contentWindow.DOMException, + function() { + actualRange.cloneContents(); + } + ); + } else { + actualFrag = actualRange.cloneContents(); + } + + actualRoots = []; + for (var j = 0; j < actualAllNodes.length; j++) { + if (!actualAllNodes[j].parentNode) { + actualRoots.push(actualAllNodes[j]); + } + } + + expectedRoots = []; + for (var j = 0; j < expectedAllNodes.length; j++) { + if (!expectedAllNodes[j].parentNode) { + expectedRoots.push(expectedAllNodes[j]); + } + } + + for (var j = 0; j < actualRoots.length; j++) { + assertNodesEqual(actualRoots[j], expectedRoots[j], j ? "detached node #" + j : "tree root"); + + if (j == 0) { + // Clearly something is wrong if the node lists are different + // lengths. We want to report this only after we've already + // checked the main tree for equality, though, so it doesn't + // mask more interesting errors. + assert_equals(actualRoots.length, expectedRoots.length, + "Actual and expected DOMs were broken up into a different number of pieces by cloneContents() (this probably means you created or detached nodes when you weren't supposed to)"); + } + } + }); + domTests[i].done(); + + positionTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual cloneContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated cloneContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + assert_true(actualRoots[0].isEqualNode(expectedRoots[0]), + "The resulting DOMs were not equal, so comparing positions makes no sense"); + + if (typeof expectedFrag == "string") { + // It's no longer true that, e.g., startContainer and endContainer + // must always be the same + return; + } + + assert_equals(actualRange.startOffset, expectedRange.startOffset, + "Unexpected startOffset after cloneContents()"); + // How do we decide that the two nodes are equal, since they're in + // different trees? Since the DOMs are the same, it's enough to check + // that the index in the parent is the same all the way up the tree. + // But we can first cheat by just checking they're actually equal. + assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer), + "Unexpected startContainer after cloneContents(), expected " + + expectedRange.startContainer.nodeName.toLowerCase() + " but got " + + actualRange.startContainer.nodeName.toLowerCase()); + var currentActual = actualRange.startContainer; + var currentExpected = expectedRange.startContainer; + var actual = ""; + var expected = ""; + while (currentActual && currentExpected) { + actual = indexOf(currentActual) + "-" + actual; + expected = indexOf(currentExpected) + "-" + expected; + + currentActual = currentActual.parentNode; + currentExpected = currentExpected.parentNode; + } + actual = actual.substr(0, actual.length - 1); + expected = expected.substr(0, expected.length - 1); + assert_equals(actual, expected, + "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened"); + }); + positionTests[i].done(); + + fragTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual cloneContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated cloneContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + if (typeof expectedFrag == "string") { + // Comparing makes no sense + return; + } + assertNodesEqual(actualFrag, expectedFrag, + "returned fragment"); + }); + fragTests[i].done(); +} + +// First test a Range that has the no-op detach() called on it, synchronously +test(function() { + var range = document.createRange(); + range.detach(); + assert_array_equals(range.cloneContents().childNodes, []); +}, "Range.detach()"); + +var iStart = 0; +var iStop = testRanges.length; + +if (/subtest=[0-9]+/.test(location.search)) { + var matches = /subtest=([0-9]+)/.exec(location.search); + iStart = Number(matches[1]); + iStop = Number(matches[1]) + 1; +} + +var domTests = []; +var positionTests = []; +var fragTests = []; + +for (var i = iStart; i < iStop; i++) { + domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i]); + positionTests[i] = async_test("Resulting cursor position for range " + i + " " + testRanges[i]); + fragTests[i] = async_test("Returned fragment for range " + i + " " + testRanges[i]); +} + +var referenceDoc = document.implementation.createHTMLDocument(""); +referenceDoc.removeChild(referenceDoc.documentElement); + +actualIframe.onload = function() { + expectedIframe.onload = function() { + for (var i = iStart; i < iStop; i++) { + testCloneContents(i); + } + } + expectedIframe.src = "Range-test-iframe.html"; + referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true)); +} +actualIframe.src = "Range-test-iframe.html"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-cloneRange.html b/testing/web-platform/tests/dom/ranges/Range-cloneRange.html new file mode 100644 index 0000000000..6c736df29f --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-cloneRange.html @@ -0,0 +1,112 @@ +<!doctype html> +<title>Range.cloneRange() and document.createRange() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +function testCloneRange(rangeEndpoints) { + var range; + if (rangeEndpoints == "detached") { + range = document.createRange(); + range.detach(); + var clonedRange = range.cloneRange(); + assert_equals(clonedRange.startContainer, range.startContainer, + "startContainers must be equal after cloneRange()"); + assert_equals(clonedRange.startOffset, range.startOffset, + "startOffsets must be equal after cloneRange()"); + assert_equals(clonedRange.endContainer, range.endContainer, + "endContainers must be equal after cloneRange()"); + assert_equals(clonedRange.endOffset, range.endOffset, + "endOffsets must be equal after cloneRange()"); + return; + } + + // Have to account for Ranges involving Documents! We could just create + // the Range from the current document unconditionally, but some browsers + // (WebKit) don't implement setStart() and setEnd() per spec and will throw + // spurious exceptions at the time of this writing. No need to mask other + // bugs. + var ownerDoc = rangeEndpoints[0].nodeType == Node.DOCUMENT_NODE + ? rangeEndpoints[0] + : rangeEndpoints[0].ownerDocument; + range = ownerDoc.createRange(); + // Here we throw in some createRange() tests, because why not. Have to + // test it someplace. + assert_equals(range.startContainer, ownerDoc, + "doc.createRange() must create Range whose startContainer is doc"); + assert_equals(range.endContainer, ownerDoc, + "doc.createRange() must create Range whose endContainer is doc"); + assert_equals(range.startOffset, 0, + "doc.createRange() must create Range whose startOffset is 0"); + assert_equals(range.endOffset, 0, + "doc.createRange() must create Range whose endOffset is 0"); + + range.setStart(rangeEndpoints[0], rangeEndpoints[1]); + range.setEnd(rangeEndpoints[2], rangeEndpoints[3]); + + // Make sure we bail out now if setStart or setEnd are buggy, so it doesn't + // create misleading failures later. + assert_equals(range.startContainer, rangeEndpoints[0], + "Sanity check on setStart()"); + assert_equals(range.startOffset, rangeEndpoints[1], + "Sanity check on setStart()"); + assert_equals(range.endContainer, rangeEndpoints[2], + "Sanity check on setEnd()"); + assert_equals(range.endOffset, rangeEndpoints[3], + "Sanity check on setEnd()"); + + var clonedRange = range.cloneRange(); + + assert_equals(clonedRange.startContainer, range.startContainer, + "startContainers must be equal after cloneRange()"); + assert_equals(clonedRange.startOffset, range.startOffset, + "startOffsets must be equal after cloneRange()"); + assert_equals(clonedRange.endContainer, range.endContainer, + "endContainers must be equal after cloneRange()"); + assert_equals(clonedRange.endOffset, range.endOffset, + "endOffsets must be equal after cloneRange()"); + + // Make sure that modifying one doesn't affect the other. + var testNode1 = ownerDoc.createTextNode("testing"); + var testNode2 = ownerDoc.createTextNode("testing with different length"); + + range.setStart(testNode1, 1); + range.setEnd(testNode1, 2); + assert_equals(clonedRange.startContainer, rangeEndpoints[0], + "Modifying a Range must not modify its clone's startContainer"); + assert_equals(clonedRange.startOffset, rangeEndpoints[1], + "Modifying a Range must not modify its clone's startOffset"); + assert_equals(clonedRange.endContainer, rangeEndpoints[2], + "Modifying a Range must not modify its clone's endContainer"); + assert_equals(clonedRange.endOffset, rangeEndpoints[3], + "Modifying a Range must not modify its clone's endOffset"); + + clonedRange.setStart(testNode2, 3); + clonedRange.setStart(testNode2, 4); + + assert_equals(range.startContainer, testNode1, + "Modifying a clone must not modify the original Range's startContainer"); + assert_equals(range.startOffset, 1, + "Modifying a clone must not modify the original Range's startOffset"); + assert_equals(range.endContainer, testNode1, + "Modifying a clone must not modify the original Range's endContainer"); + assert_equals(range.endOffset, 2, + "Modifying a clone must not modify the original Range's endOffset"); +} + +var tests = []; +for (var i = 0; i < testRanges.length; i++) { + tests.push([ + "Range " + i + " " + testRanges[i], + eval(testRanges[i]) + ]); +} +generate_tests(testCloneRange, tests); + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-collapse.html b/testing/web-platform/tests/dom/ranges/Range-collapse.html new file mode 100644 index 0000000000..141dbdf610 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-collapse.html @@ -0,0 +1,67 @@ +<!doctype html> +<title>Range.collapse() and .collapsed tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +function testCollapse(rangeEndpoints, toStart) { + // Have to account for Ranges involving Documents! + var ownerDoc = rangeEndpoints[0].nodeType == Node.DOCUMENT_NODE + ? rangeEndpoints[0] + : rangeEndpoints[0].ownerDocument; + var range = ownerDoc.createRange(); + range.setStart(rangeEndpoints[0], rangeEndpoints[1]); + range.setEnd(rangeEndpoints[2], rangeEndpoints[3]); + + var expectedContainer = toStart ? range.startContainer : range.endContainer; + var expectedOffset = toStart ? range.startOffset : range.endOffset; + + assert_equals(range.collapsed, range.startContainer == range.endContainer + && range.startOffset == range.endOffset, + "collapsed must be true if and only if the start and end are equal"); + + if (toStart === undefined) { + range.collapse(); + } else { + range.collapse(toStart); + } + + assert_equals(range.startContainer, expectedContainer, + "Wrong startContainer"); + assert_equals(range.endContainer, expectedContainer, + "Wrong endContainer"); + assert_equals(range.startOffset, expectedOffset, + "Wrong startOffset"); + assert_equals(range.endOffset, expectedOffset, + "Wrong endOffset"); + assert_true(range.collapsed, + ".collapsed must be set after .collapsed()"); +} + +var tests = []; +for (var i = 0; i < testRanges.length; i++) { + tests.push([ + "Range " + i + " " + testRanges[i] + ", toStart true", + eval(testRanges[i]), + true + ]); + tests.push([ + "Range " + i + " " + testRanges[i] + ", toStart false", + eval(testRanges[i]), + false + ]); + tests.push([ + "Range " + i + " " + testRanges[i] + ", toStart omitted", + eval(testRanges[i]), + undefined + ]); +} +generate_tests(testCollapse, tests); + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer-2.html b/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer-2.html new file mode 100644 index 0000000000..f0a3e451cd --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer-2.html @@ -0,0 +1,33 @@ +<!doctype html> +<title>Range.commonAncestorContainer</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var range = document.createRange(); + range.detach(); + assert_equals(range.commonAncestorContainer, document); +}, "Detached Range") +test(function() { + var df = document.createDocumentFragment(); + var foo = df.appendChild(document.createElement("foo")); + foo.appendChild(document.createTextNode("Foo")); + var bar = df.appendChild(document.createElement("bar")); + bar.appendChild(document.createComment("Bar")); + [ + // start node, start offset, end node, end offset, expected cAC + [foo, 0, bar, 0, df], + [foo, 0, foo.firstChild, 3, foo], + [foo.firstChild, 0, bar, 0, df], + [foo.firstChild, 3, bar.firstChild, 2, df] + ].forEach(function(t) { + test(function() { + var range = document.createRange(); + range.setStart(t[0], t[1]); + range.setEnd(t[2], t[3]); + assert_equals(range.commonAncestorContainer, t[4]); + }) + }); +}, "Normal Ranges") +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer.html b/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer.html new file mode 100644 index 0000000000..7882ccc31f --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-commonAncestorContainer.html @@ -0,0 +1,40 @@ +<!doctype html> +<title>Range.commonAncestorContainer tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testRanges.unshift("[detached]"); + +for (var i = 0; i < testRanges.length; i++) { + test(function() { + var range; + if (i == 0) { + range = document.createRange(); + range.detach(); + } else { + range = rangeFromEndpoints(eval(testRanges[i])); + } + + // "Let container be start node." + var container = range.startContainer; + + // "While container is not an inclusive ancestor of end node, let + // container be container's parent." + while (container != range.endContainer + && !isAncestor(container, range.endContainer)) { + container = container.parentNode; + } + + // "Return container." + assert_equals(range.commonAncestorContainer, container); + }, i + ": range " + testRanges[i]); +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-compareBoundaryPoints.html b/testing/web-platform/tests/dom/ranges/Range-compareBoundaryPoints.html new file mode 100644 index 0000000000..9d150ae0ab --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-compareBoundaryPoints.html @@ -0,0 +1,182 @@ +<!doctype html> +<title>Range.compareBoundaryPoints() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +var testRangesCached = []; +testRangesCached.push(document.createRange()); +testRangesCached[0].detach(); +for (var i = 0; i < testRangesShort.length; i++) { + try { + testRangesCached.push(rangeFromEndpoints(eval(testRangesShort[i]))); + } catch(e) { + testRangesCached.push(null); + } +} + +var testRangesCachedClones = []; +testRangesCachedClones.push(document.createRange()); +testRangesCachedClones[0].detach(); +for (var i = 1; i < testRangesCached.length; i++) { + if (testRangesCached[i]) { + testRangesCachedClones.push(testRangesCached[i].cloneRange()); + } else { + testRangesCachedClones.push(null); + } +} + +// We want to run a whole bunch of extra tests with invalid "how" values (not +// 0-3), but it's excessive to run them for every single pair of ranges -- +// there are too many of them. So just run them for a handful of the tests. +var extraTests = [0, // detached + 1 + testRanges.indexOf("[paras[0].firstChild, 2, paras[0].firstChild, 8]"), + 1 + testRanges.indexOf("[paras[0].firstChild, 3, paras[3], 1]"), + 1 + testRanges.indexOf("[testDiv, 0, comment, 5]"), + 1 + testRanges.indexOf("[foreignDoc.documentElement, 0, foreignDoc.documentElement, 1]")]; + +for (var i = 0; i < testRangesCached.length; i++) { + var range1 = testRangesCached[i]; + var range1Desc = i + " " + (i == 0 ? "[detached]" : testRanges[i - 1]); + for (var j = 0; j <= testRangesCachedClones.length; j++) { + var range2; + var range2Desc; + if (j == testRangesCachedClones.length) { + range2 = range1; + range2Desc = "same as first range"; + } else { + range2 = testRangesCachedClones[j]; + range2Desc = j + " " + (j == 0 ? "[detached]" : testRanges[j - 1]); + } + + var hows = [Range.START_TO_START, Range.START_TO_END, Range.END_TO_END, + Range.END_TO_START]; + if (extraTests.indexOf(i) != -1 && extraTests.indexOf(j) != -1) { + // TODO: Make some type of reusable utility function to do this + // work. + hows.push(-1, 4, 5, NaN, -0, +Infinity, -Infinity); + [65536, -65536, 65536*65536, 0.5, -0.5, -72.5].forEach(function(addend) { + hows.push(-1 + addend, 0 + addend, 1 + addend, + 2 + addend, 3 + addend, 4 + addend); + }); + hows.forEach(function(how) { hows.push(String(how)) }); + hows.push("6.5536e4", null, undefined, true, false, "", "quasit"); + } + + for (var k = 0; k < hows.length; k++) { + var how = hows[k]; + test(function() { + assert_not_equals(range1, null, + "Creating context range threw an exception"); + assert_not_equals(range2, null, + "Creating argument range threw an exception"); + + // Convert how per WebIDL. TODO: Make some type of reusable + // utility function to do this work. + // "Let number be the result of calling ToNumber on the input + // argument." + var convertedHow = Number(how); + + // "If number is NaN, +0, −0, +∞, or −∞, return +0." + if (isNaN(convertedHow) + || convertedHow == 0 + || convertedHow == Infinity + || convertedHow == -Infinity) { + convertedHow = 0; + } else { + // "Let posInt be sign(number) * floor(abs(number))." + var posInt = (convertedHow < 0 ? -1 : 1) * Math.floor(Math.abs(convertedHow)); + + // "Let int16bit be posInt modulo 2^16; that is, a finite + // integer value k of Number type with positive sign and + // less than 2^16 in magnitude such that the mathematical + // difference of posInt and k is mathematically an integer + // multiple of 2^16." + // + // "Return int16bit." + convertedHow = posInt % 65536; + if (convertedHow < 0) { + convertedHow += 65536; + } + } + + // Now to the actual algorithm. + // "If how is not one of + // START_TO_START, + // START_TO_END, + // END_TO_END, and + // END_TO_START, + // throw a "NotSupportedError" exception and terminate these + // steps." + if (convertedHow != Range.START_TO_START + && convertedHow != Range.START_TO_END + && convertedHow != Range.END_TO_END + && convertedHow != Range.END_TO_START) { + assert_throws_dom("NOT_SUPPORTED_ERR", function() { + range1.compareBoundaryPoints(how, range2); + }, "NotSupportedError required if first parameter doesn't convert to 0-3 per WebIDL"); + return; + } + + // "If context object's root is not the same as sourceRange's + // root, throw a "WrongDocumentError" exception and terminate + // these steps." + if (furthestAncestor(range1.startContainer) != furthestAncestor(range2.startContainer)) { + assert_throws_dom("WRONG_DOCUMENT_ERR", function() { + range1.compareBoundaryPoints(how, range2); + }, "WrongDocumentError required if the ranges don't share a root"); + return; + } + + // "If how is: + // START_TO_START: + // Let this point be the context object's start. + // Let other point be sourceRange's start. + // START_TO_END: + // Let this point be the context object's end. + // Let other point be sourceRange's start. + // END_TO_END: + // Let this point be the context object's end. + // Let other point be sourceRange's end. + // END_TO_START: + // Let this point be the context object's start. + // Let other point be sourceRange's end." + var thisPoint = convertedHow == Range.START_TO_START || convertedHow == Range.END_TO_START + ? [range1.startContainer, range1.startOffset] + : [range1.endContainer, range1.endOffset]; + var otherPoint = convertedHow == Range.START_TO_START || convertedHow == Range.START_TO_END + ? [range2.startContainer, range2.startOffset] + : [range2.endContainer, range2.endOffset]; + + // "If the position of this point relative to other point is + // before + // Return −1. + // equal + // Return 0. + // after + // Return 1." + var position = getPosition(thisPoint[0], thisPoint[1], otherPoint[0], otherPoint[1]); + var expected; + if (position == "before") { + expected = -1; + } else if (position == "equal") { + expected = 0; + } else if (position == "after") { + expected = 1; + } + + assert_equals(range1.compareBoundaryPoints(how, range2), expected, + "Wrong return value"); + }, i + "," + j + "," + k + ": context range " + range1Desc + ", argument range " + range2Desc + ", how " + format_value(how)); + } + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-comparePoint-2.html b/testing/web-platform/tests/dom/ranges/Range-comparePoint-2.html new file mode 100644 index 0000000000..30a6c57ad9 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-comparePoint-2.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<title>Range.comparePoint</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var r = document.createRange(); + r.detach() + assert_equals(r.comparePoint(document.body, 0), 1) +}) +test(function() { + var r = document.createRange(); + assert_throws_js(TypeError, function() { r.comparePoint(null, 0) }) +}) +test(function() { + var doc = document.implementation.createHTMLDocument("tralala") + var r = document.createRange(); + assert_throws_dom("WRONG_DOCUMENT_ERR", function() { r.comparePoint(doc.body, 0) }) +}) +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-comparePoint.html b/testing/web-platform/tests/dom/ranges/Range-comparePoint.html new file mode 100644 index 0000000000..e18ac95c4c --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-comparePoint.html @@ -0,0 +1,92 @@ +<!doctype html> +<title>Range.comparePoint() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +// Will be filled in on the first run for that range +var testRangesCached = []; + +for (var i = 0; i < testPoints.length; i++) { + var node = eval(testPoints[i])[0]; + var offset = eval(testPoints[i])[1]; + + // comparePoint is an unsigned long, so per WebIDL, we need to treat it as + // though it wrapped to an unsigned 32-bit integer. + var normalizedOffset = offset % Math.pow(2, 32); + if (normalizedOffset < 0) { + normalizedOffset += Math.pow(2, 32); + } + + for (var j = 0; j < testRanges.length; j++) { + test(function() { + if (testRangesCached[j] === undefined) { + try { + testRangesCached[j] = rangeFromEndpoints(eval(testRanges[i])); + } catch(e) { + testRangesCached[j] = null; + } + } + assert_not_equals(testRangesCached[j], null, + "Setting up the range failed"); + + var range = testRangesCached[j].cloneRange(); + + // "If node's root is different from the context object's root, + // throw a "WrongDocumentError" exception and terminate these + // steps." + if (furthestAncestor(node) !== furthestAncestor(range.startContainer)) { + assert_throws_dom("WRONG_DOCUMENT_ERR", function() { + range.comparePoint(node, offset); + }, "Must throw WrongDocumentError if node and range have different roots"); + return; + } + + // "If node is a doctype, throw an "InvalidNodeTypeError" exception + // and terminate these steps." + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { + range.comparePoint(node, offset); + }, "Must throw InvalidNodeTypeError if node is a doctype"); + return; + } + + // "If offset is greater than node's length, throw an + // "IndexSizeError" exception and terminate these steps." + if (normalizedOffset > nodeLength(node)) { + assert_throws_dom("INDEX_SIZE_ERR", function() { + range.comparePoint(node, offset); + }, "Must throw IndexSizeError if offset is greater than length"); + return; + } + + // "If (node, offset) is before start, return −1 and terminate + // these steps." + if (getPosition(node, normalizedOffset, range.startContainer, range.startOffset) === "before") { + assert_equals(range.comparePoint(node, offset), -1, + "Must return -1 if point is before start"); + return; + } + + // "If (node, offset) is after end, return 1 and terminate these + // steps." + if (getPosition(node, normalizedOffset, range.endContainer, range.endOffset) === "after") { + assert_equals(range.comparePoint(node, offset), 1, + "Must return 1 if point is after end"); + return; + } + + // "Return 0." + assert_equals(range.comparePoint(node, offset), 0, + "Must return 0 if point is neither before start nor after end"); + }, "Point " + i + " " + testPoints[i] + ", range " + j + " " + testRanges[j]); + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-constructor.html b/testing/web-platform/tests/dom/ranges/Range-constructor.html new file mode 100644 index 0000000000..e8cfbef753 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-constructor.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>Range constructor test</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; + +test(function() { + var range = new Range(); + assert_equals(range.startContainer, document, "startContainer"); + assert_equals(range.endContainer, document, "endContainer"); + assert_equals(range.startOffset, 0, "startOffset"); + assert_equals(range.endOffset, 0, "endOffset"); + assert_true(range.collapsed, "collapsed"); + assert_equals(range.commonAncestorContainer, document, + "commonAncestorContainer"); +}); +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-deleteContents.html b/testing/web-platform/tests/dom/ranges/Range-deleteContents.html new file mode 100644 index 0000000000..40dc400125 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-deleteContents.html @@ -0,0 +1,337 @@ +<!doctype html> +<title>Range.deleteContents() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<p>To debug test failures, add a query parameter "subtest" with the test id (like +"?subtest=5"). Only that test will be run. Then you can look at the resulting +iframe in the DOM. +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testDiv.parentNode.removeChild(testDiv); + +var actualIframe = document.createElement("iframe"); +actualIframe.style.display = "none"; +document.body.appendChild(actualIframe); + +var expectedIframe = document.createElement("iframe"); +expectedIframe.style.display = "none"; +document.body.appendChild(expectedIframe); + +function restoreIframe(iframe, i) { + // Most of this function is designed to work around the fact that Opera + // doesn't let you add a doctype to a document that no longer has one, in + // any way I can figure out. I eventually compromised on something that + // will still let Opera pass most tests that don't actually involve + // doctypes. + while (iframe.contentDocument.firstChild + && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); + } + + while (iframe.contentDocument.lastChild + && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); + } + + if (!iframe.contentDocument.firstChild) { + // This will throw an exception in Opera if we reach here, which is why + // I try to avoid it. It will never happen in a browser that obeys the + // spec, so it's really just insurance. I don't think it actually gets + // hit by anything. + iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", "")); + } + iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true)); + iframe.contentWindow.setupRangeTests(); + iframe.contentWindow.testRangeInput = testRanges[i]; + iframe.contentWindow.run(); +} + +function myDeleteContents(range) { + // "If the context object's start and end are the same, abort this method." + if (range.startContainer == range.endContainer + && range.startOffset == range.endOffset) { + return; + } + + // "Let original start node, original start offset, original end node, and + // original end offset be the context object's start and end nodes and + // offsets, respectively." + var originalStartNode = range.startContainer; + var originalStartOffset = range.startOffset; + var originalEndNode = range.endContainer; + var originalEndOffset = range.endOffset; + + // "If original start node and original end node are the same, and they are + // a Text, ProcessingInstruction, or Comment node, replace data with node + // original start node, offset original start offset, count original end + // offset minus original start offset, and data the empty string, and then + // terminate these steps" + if (originalStartNode == originalEndNode + && (range.startContainer.nodeType == Node.TEXT_NODE + || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || range.startContainer.nodeType == Node.COMMENT_NODE)) { + originalStartNode.deleteData(originalStartOffset, originalEndOffset - originalStartOffset); + return; + } + + // "Let nodes to remove be a list of all the Nodes that are contained in + // the context object, in tree order, omitting any Node whose parent is + // also contained in the context object." + // + // We rely on the fact that the contained nodes must lie in tree order + // between the start node, and the end node's last descendant (inclusive). + var nodesToRemove = []; + var stop = nextNodeDescendants(range.endContainer); + for (var node = range.startContainer; node != stop; node = nextNode(node)) { + if (isContained(node, range) + && !(node.parentNode && isContained(node.parentNode, range))) { + nodesToRemove.push(node); + } + } + + // "If original start node is an ancestor container of original end node, + // set new node to original start node and new offset to original start + // offset." + var newNode; + var newOffset; + if (originalStartNode == originalEndNode + || originalEndNode.compareDocumentPosition(originalStartNode) & Node.DOCUMENT_POSITION_CONTAINS) { + newNode = originalStartNode; + newOffset = originalStartOffset; + // "Otherwise:" + } else { + // "Let reference node equal original start node." + var referenceNode = originalStartNode; + + // "While reference node's parent is not null and is not an ancestor + // container of original end node, set reference node to its parent." + while (referenceNode.parentNode + && referenceNode.parentNode != originalEndNode + && !(originalEndNode.compareDocumentPosition(referenceNode.parentNode) & Node.DOCUMENT_POSITION_CONTAINS)) { + referenceNode = referenceNode.parentNode; + } + + // "Set new node to the parent of reference node, and new offset to one + // plus the index of reference node." + newNode = referenceNode.parentNode; + newOffset = 1 + indexOf(referenceNode); + } + + // "If original start node is a Text, ProcessingInstruction, or Comment node, + // replace data with node original start node, offset original start offset, + // count original start node's length minus original start offset, data the + // empty start" + if (originalStartNode.nodeType == Node.TEXT_NODE + || originalStartNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || originalStartNode.nodeType == Node.COMMENT_NODE) { + originalStartNode.deleteData(originalStartOffset, nodeLength(originalStartNode) - originalStartOffset); + } + + // "For each node in nodes to remove, in order, remove node from its + // parent." + for (var i = 0; i < nodesToRemove.length; i++) { + nodesToRemove[i].parentNode.removeChild(nodesToRemove[i]); + } + + // "If original end node is a Text, ProcessingInstruction, or Comment node, + // replace data with node original end node, offset 0, count original end + // offset, and data the empty string." + if (originalEndNode.nodeType == Node.TEXT_NODE + || originalEndNode.nodeType == Node.PROCESSING_INSTRUCTION_NODE + || originalEndNode.nodeType == Node.COMMENT_NODE) { + originalEndNode.deleteData(0, originalEndOffset); + } + + // "Set the context object's start and end to (new node, new offset)." + range.setStart(newNode, newOffset); + range.setEnd(newNode, newOffset); +} + +function testDeleteContents(i) { + restoreIframe(actualIframe, i); + restoreIframe(expectedIframe, i); + + var actualRange = actualIframe.contentWindow.testRange; + var expectedRange = expectedIframe.contentWindow.testRange; + var actualRoots, expectedRoots; + + domTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual deleteContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated deleteContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + // Just to be pedantic, we'll test not only that the tree we're + // modifying is the same in expected vs. actual, but also that all the + // nodes originally in it were the same. Typically some nodes will + // become detached when the algorithm is run, but they still exist and + // references can still be kept to them, so they should also remain the + // same. + // + // We initialize the list to all nodes, and later on remove all the + // ones which still have parents, since the parents will presumably be + // tested for isEqualNode() and checking the children would be + // redundant. + var actualAllNodes = []; + var node = furthestAncestor(actualRange.startContainer); + do { + actualAllNodes.push(node); + } while (node = nextNode(node)); + + var expectedAllNodes = []; + var node = furthestAncestor(expectedRange.startContainer); + do { + expectedAllNodes.push(node); + } while (node = nextNode(node)); + + actualRange.deleteContents(); + myDeleteContents(expectedRange); + + actualRoots = []; + for (var j = 0; j < actualAllNodes.length; j++) { + if (!actualAllNodes[j].parentNode) { + actualRoots.push(actualAllNodes[j]); + } + } + + expectedRoots = []; + for (var j = 0; j < expectedAllNodes.length; j++) { + if (!expectedAllNodes[j].parentNode) { + expectedRoots.push(expectedAllNodes[j]); + } + } + + for (var j = 0; j < actualRoots.length; j++) { + if (!actualRoots[j].isEqualNode(expectedRoots[j])) { + var msg = j ? "detached node #" + j : "tree root"; + msg = "Actual and expected mismatch for " + msg + ". "; + + // Find the specific error + var actual = actualRoots[j]; + var expected = expectedRoots[j]; + + while (actual && expected) { + assert_equals(actual.nodeType, expected.nodeType, + msg + "First difference: differing nodeType"); + assert_equals(actual.nodeName, expected.nodeName, + msg + "First difference: differing nodeName"); + assert_equals(actual.nodeValue, expected.nodeValue, + msg + 'First difference: differing nodeValue (nodeName = "' + actual.nodeName + '")'); + assert_equals(actual.childNodes.length, expected.childNodes.length, + msg + 'First difference: differing number of children (nodeName = "' + actual.nodeName + '")'); + actual = nextNode(actual); + expected = nextNode(expected); + } + + assert_unreached("DOMs were not equal but we couldn't figure out why"); + } + + if (j == 0) { + // Clearly something is wrong if the node lists are different + // lengths. We want to report this only after we've already + // checked the main tree for equality, though, so it doesn't + // mask more interesting errors. + assert_equals(actualRoots.length, expectedRoots.length, + "Actual and expected DOMs were broken up into a different number of pieces by deleteContents() (this probably means you created or detached nodes when you weren't supposed to)"); + } + } + }); + domTests[i].done(); + + positionTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual deleteContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated deleteContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + assert_true(actualRoots[0].isEqualNode(expectedRoots[0]), + "The resulting DOMs were not equal, so comparing positions makes no sense"); + + assert_equals(actualRange.startContainer, actualRange.endContainer, + "startContainer and endContainer must always be the same after deleteContents()"); + assert_equals(actualRange.startOffset, actualRange.endOffset, + "startOffset and endOffset must always be the same after deleteContents()"); + assert_equals(expectedRange.startContainer, expectedRange.endContainer, + "Test bug! Expected startContainer and endContainer must always be the same after deleteContents()"); + assert_equals(expectedRange.startOffset, expectedRange.endOffset, + "Test bug! Expected startOffset and endOffset must always be the same after deleteContents()"); + + assert_equals(actualRange.startOffset, expectedRange.startOffset, + "Unexpected startOffset after deleteContents()"); + // How do we decide that the two nodes are equal, since they're in + // different trees? Since the DOMs are the same, it's enough to check + // that the index in the parent is the same all the way up the tree. + // But we can first cheat by just checking they're actually equal. + assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer), + "Unexpected startContainer after deleteContents(), expected " + + expectedRange.startContainer.nodeName.toLowerCase() + " but got " + + actualRange.startContainer.nodeName.toLowerCase()); + var currentActual = actualRange.startContainer; + var currentExpected = expectedRange.startContainer; + var actual = ""; + var expected = ""; + while (currentActual && currentExpected) { + actual = indexOf(currentActual) + "-" + actual; + expected = indexOf(currentExpected) + "-" + expected; + + currentActual = currentActual.parentNode; + currentExpected = currentExpected.parentNode; + } + actual = actual.substr(0, actual.length - 1); + expected = expected.substr(0, expected.length - 1); + assert_equals(actual, expected, + "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened"); + }); + positionTests[i].done(); +} + +// First test a detached Range, synchronously +test(function() { + var range = document.createRange(); + range.detach(); + range.deleteContents(); +}, "Detached Range"); + +var iStart = 0; +var iStop = testRanges.length; + +if (/subtest=[0-9]+/.test(location.search)) { + var matches = /subtest=([0-9]+)/.exec(location.search); + iStart = Number(matches[1]); + iStop = Number(matches[1]) + 1; +} + +var domTests = []; +var positionTests = []; + +for (var i = iStart; i < iStop; i++) { + domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i]); + positionTests[i] = async_test("Resulting cursor position for range " + i + " " + testRanges[i]); +} + +var referenceDoc = document.implementation.createHTMLDocument(""); +referenceDoc.removeChild(referenceDoc.documentElement); + +actualIframe.onload = function() { + expectedIframe.onload = function() { + for (var i = iStart; i < iStop; i++) { + testDeleteContents(i); + } + } + expectedIframe.src = "Range-test-iframe.html"; + referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true)); +} +actualIframe.src = "Range-test-iframe.html"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-detach.html b/testing/web-platform/tests/dom/ranges/Range-detach.html new file mode 100644 index 0000000000..ac35d71369 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-detach.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<title>Range.detach</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var r = document.createRange(); + r.detach() + r.detach() +}) +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-extractContents.html b/testing/web-platform/tests/dom/ranges/Range-extractContents.html new file mode 100644 index 0000000000..88f8fa55f8 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-extractContents.html @@ -0,0 +1,252 @@ +<!doctype html> +<title>Range.extractContents() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<p>To debug test failures, add a query parameter "subtest" with the test id (like +"?subtest=5"). Only that test will be run. Then you can look at the resulting +iframe in the DOM. +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testDiv.parentNode.removeChild(testDiv); + +var actualIframe = document.createElement("iframe"); +actualIframe.style.display = "none"; +document.body.appendChild(actualIframe); + +var expectedIframe = document.createElement("iframe"); +expectedIframe.style.display = "none"; +document.body.appendChild(expectedIframe); + +function restoreIframe(iframe, i) { + // Most of this function is designed to work around the fact that Opera + // doesn't let you add a doctype to a document that no longer has one, in + // any way I can figure out. I eventually compromised on something that + // will still let Opera pass most tests that don't actually involve + // doctypes. + while (iframe.contentDocument.firstChild + && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); + } + + while (iframe.contentDocument.lastChild + && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); + } + + if (!iframe.contentDocument.firstChild) { + // This will throw an exception in Opera if we reach here, which is why + // I try to avoid it. It will never happen in a browser that obeys the + // spec, so it's really just insurance. I don't think it actually gets + // hit by anything. + iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", "")); + } + iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true)); + iframe.contentWindow.setupRangeTests(); + iframe.contentWindow.testRangeInput = testRanges[i]; + iframe.contentWindow.run(); +} + +function testExtractContents(i) { + restoreIframe(actualIframe, i); + restoreIframe(expectedIframe, i); + + var actualRange = actualIframe.contentWindow.testRange; + var expectedRange = expectedIframe.contentWindow.testRange; + var actualFrag, expectedFrag; + var actualRoots, expectedRoots; + + domTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual extractContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated extractContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + // Just to be pedantic, we'll test not only that the tree we're + // modifying is the same in expected vs. actual, but also that all the + // nodes originally in it were the same. Typically some nodes will + // become detached when the algorithm is run, but they still exist and + // references can still be kept to them, so they should also remain the + // same. + // + // We initialize the list to all nodes, and later on remove all the + // ones which still have parents, since the parents will presumably be + // tested for isEqualNode() and checking the children would be + // redundant. + var actualAllNodes = []; + var node = furthestAncestor(actualRange.startContainer); + do { + actualAllNodes.push(node); + } while (node = nextNode(node)); + + var expectedAllNodes = []; + var node = furthestAncestor(expectedRange.startContainer); + do { + expectedAllNodes.push(node); + } while (node = nextNode(node)); + + expectedFrag = myExtractContents(expectedRange); + if (typeof expectedFrag == "string") { + assert_throws_dom( + expectedFrag, + actualIframe.contentWindow.DOMException, + function() { + actualRange.extractContents(); + } + ); + } else { + actualFrag = actualRange.extractContents(); + } + + actualRoots = []; + for (var j = 0; j < actualAllNodes.length; j++) { + if (!actualAllNodes[j].parentNode) { + actualRoots.push(actualAllNodes[j]); + } + } + + expectedRoots = []; + for (var j = 0; j < expectedAllNodes.length; j++) { + if (!expectedAllNodes[j].parentNode) { + expectedRoots.push(expectedAllNodes[j]); + } + } + + for (var j = 0; j < actualRoots.length; j++) { + assertNodesEqual(actualRoots[j], expectedRoots[j], j ? "detached node #" + j : "tree root"); + + if (j == 0) { + // Clearly something is wrong if the node lists are different + // lengths. We want to report this only after we've already + // checked the main tree for equality, though, so it doesn't + // mask more interesting errors. + assert_equals(actualRoots.length, expectedRoots.length, + "Actual and expected DOMs were broken up into a different number of pieces by extractContents() (this probably means you created or detached nodes when you weren't supposed to)"); + } + } + }); + domTests[i].done(); + + positionTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual extractContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated extractContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + assert_true(actualRoots[0].isEqualNode(expectedRoots[0]), + "The resulting DOMs were not equal, so comparing positions makes no sense"); + + if (typeof expectedFrag == "string") { + // It's no longer true that, e.g., startContainer and endContainer + // must always be the same + return; + } + assert_equals(actualRange.startContainer, actualRange.endContainer, + "startContainer and endContainer must always be the same after extractContents()"); + assert_equals(actualRange.startOffset, actualRange.endOffset, + "startOffset and endOffset must always be the same after extractContents()"); + assert_equals(expectedRange.startContainer, expectedRange.endContainer, + "Test bug! Expected startContainer and endContainer must always be the same after extractContents()"); + assert_equals(expectedRange.startOffset, expectedRange.endOffset, + "Test bug! Expected startOffset and endOffset must always be the same after extractContents()"); + + assert_equals(actualRange.startOffset, expectedRange.startOffset, + "Unexpected startOffset after extractContents()"); + // How do we decide that the two nodes are equal, since they're in + // different trees? Since the DOMs are the same, it's enough to check + // that the index in the parent is the same all the way up the tree. + // But we can first cheat by just checking they're actually equal. + assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer), + "Unexpected startContainer after extractContents(), expected " + + expectedRange.startContainer.nodeName.toLowerCase() + " but got " + + actualRange.startContainer.nodeName.toLowerCase()); + var currentActual = actualRange.startContainer; + var currentExpected = expectedRange.startContainer; + var actual = ""; + var expected = ""; + while (currentActual && currentExpected) { + actual = indexOf(currentActual) + "-" + actual; + expected = indexOf(currentExpected) + "-" + expected; + + currentActual = currentActual.parentNode; + currentExpected = currentExpected.parentNode; + } + actual = actual.substr(0, actual.length - 1); + expected = expected.substr(0, expected.length - 1); + assert_equals(actual, expected, + "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened"); + }); + positionTests[i].done(); + + fragTests[i].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual extractContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated extractContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + + if (typeof expectedFrag == "string") { + // Comparing makes no sense + return; + } + assertNodesEqual(actualFrag, expectedFrag, + "returned fragment"); + }); + fragTests[i].done(); +} + +// First test a detached Range, synchronously +test(function() { + var range = document.createRange(); + range.detach(); + assert_array_equals(range.extractContents().childNodes, []); +}, "Detached Range"); + +var iStart = 0; +var iStop = testRanges.length; + +if (/subtest=[0-9]+/.test(location.search)) { + var matches = /subtest=([0-9]+)/.exec(location.search); + iStart = Number(matches[1]); + iStop = Number(matches[1]) + 1; +} + +var domTests = []; +var positionTests = []; +var fragTests = []; + +for (var i = iStart; i < iStop; i++) { + domTests[i] = async_test("Resulting DOM for range " + i + " " + testRanges[i]); + positionTests[i] = async_test("Resulting cursor position for range " + i + " " + testRanges[i]); + fragTests[i] = async_test("Returned fragment for range " + i + " " + testRanges[i]); +} + +var referenceDoc = document.implementation.createHTMLDocument(""); +referenceDoc.removeChild(referenceDoc.documentElement); + +actualIframe.onload = function() { + expectedIframe.onload = function() { + for (var i = iStart; i < iStop; i++) { + testExtractContents(i); + } + } + expectedIframe.src = "Range-test-iframe.html"; + referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true)); +} +actualIframe.src = "Range-test-iframe.html"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-insertNode.html b/testing/web-platform/tests/dom/ranges/Range-insertNode.html new file mode 100644 index 0000000000..b0a9d43f98 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-insertNode.html @@ -0,0 +1,286 @@ +<!doctype html> +<title>Range.insertNode() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<p>To debug test failures, add a query parameter "subtest" with the test id (like +"?subtest=5,16"). Only that test will be run. Then you can look at the resulting +iframes in the DOM. +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testDiv.parentNode.removeChild(testDiv); + +function restoreIframe(iframe, i, j) { + // Most of this function is designed to work around the fact that Opera + // doesn't let you add a doctype to a document that no longer has one, in + // any way I can figure out. I eventually compromised on something that + // will still let Opera pass most tests that don't actually involve + // doctypes. + while (iframe.contentDocument.firstChild + && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); + } + + while (iframe.contentDocument.lastChild + && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); + } + + if (!iframe.contentDocument.firstChild) { + // This will throw an exception in Opera if we reach here, which is why + // I try to avoid it. It will never happen in a browser that obeys the + // spec, so it's really just insurance. I don't think it actually gets + // hit by anything. + iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", "")); + } + iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true)); + iframe.contentWindow.setupRangeTests(); + iframe.contentWindow.testRangeInput = testRangesShort[i]; + iframe.contentWindow.testNodeInput = testNodesShort[j]; + iframe.contentWindow.run(); +} + +function testInsertNode(i, j) { + var actualRange; + var expectedRange; + var actualNode; + var expectedNode; + var actualRoots = []; + var expectedRoots = []; + + var detached = false; + + domTests[i][j].step(function() { + restoreIframe(actualIframe, i, j); + restoreIframe(expectedIframe, i, j); + + actualRange = actualIframe.contentWindow.testRange; + expectedRange = expectedIframe.contentWindow.testRange; + actualNode = actualIframe.contentWindow.testNode; + expectedNode = expectedIframe.contentWindow.testNode; + + try { + actualRange.collapsed; + } catch (e) { + detached = true; + } + + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual insertNode()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated insertNode()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_not_equals(actualRange, null, + "Range produced in actual iframe was null"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + assert_not_equals(expectedRange, null, + "Range produced in expected iframe was null"); + assert_equals(typeof actualNode, "object", + "typeof Node produced in actual iframe"); + assert_not_equals(actualNode, null, + "Node produced in actual iframe was null"); + assert_equals(typeof expectedNode, "object", + "typeof Node produced in expected iframe"); + assert_not_equals(expectedNode, null, + "Node produced in expected iframe was null"); + + // We want to test that the trees containing the ranges are equal, and + // also the trees containing the moved nodes. These might not be the + // same, if we're inserting a node from a detached tree or a different + // document. + // + // Detached ranges are always in the contentDocument. + if (detached) { + actualRoots.push(actualIframe.contentDocument); + expectedRoots.push(expectedIframe.contentDocument); + } else { + actualRoots.push(furthestAncestor(actualRange.startContainer)); + expectedRoots.push(furthestAncestor(expectedRange.startContainer)); + } + + if (furthestAncestor(actualNode) != actualRoots[0]) { + actualRoots.push(furthestAncestor(actualNode)); + } + if (furthestAncestor(expectedNode) != expectedRoots[0]) { + expectedRoots.push(furthestAncestor(expectedNode)); + } + + assert_equals(actualRoots.length, expectedRoots.length, + "Either the actual node and actual range are in the same tree but the expected are in different trees, or vice versa"); + + // This doctype stuff is to work around the fact that Opera 11.00 will + // move around doctypes within a document, even to totally invalid + // positions, but it won't allow a new doctype to be added to a + // document in any way I can figure out. So if we try moving a doctype + // to some invalid place, in Opera it will actually succeed, and then + // restoreIframe() will remove the doctype along with the root element, + // and then nothing can re-add the doctype. So instead, we catch it + // during the test itself and move it back to the right place while we + // still can. + // + // I spent *way* too much time debugging and working around this bug. + var actualDoctype = actualIframe.contentDocument.doctype; + var expectedDoctype = expectedIframe.contentDocument.doctype; + + var result; + try { + result = myInsertNode(expectedRange, expectedNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + throw e; + } + if (typeof result == "string") { + assert_throws_dom(result, actualIframe.contentWindow.DOMException, function() { + try { + actualRange.insertNode(actualNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + if (actualDoctype != actualIframe.contentDocument.firstChild) { + actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild); + } + throw e; + } + }, "A " + result + " DOMException must be thrown in this case"); + // Don't return, we still need to test DOM equality + } else { + try { + actualRange.insertNode(actualNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + if (actualDoctype != actualIframe.contentDocument.firstChild) { + actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild); + } + throw e; + } + } + + for (var k = 0; k < actualRoots.length; k++) { + assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root"); + } + }); + domTests[i][j].done(); + + positionTests[i][j].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual insertNode()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated insertNode()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_not_equals(actualRange, null, + "Range produced in actual iframe was null"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + assert_not_equals(expectedRange, null, + "Range produced in expected iframe was null"); + assert_equals(typeof actualNode, "object", + "typeof Node produced in actual iframe"); + assert_not_equals(actualNode, null, + "Node produced in actual iframe was null"); + assert_equals(typeof expectedNode, "object", + "typeof Node produced in expected iframe"); + assert_not_equals(expectedNode, null, + "Node produced in expected iframe was null"); + + for (var k = 0; k < actualRoots.length; k++) { + assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root"); + } + + if (detached) { + // No further tests we can do + return; + } + + assert_equals(actualRange.startOffset, expectedRange.startOffset, + "Unexpected startOffset after insertNode()"); + assert_equals(actualRange.endOffset, expectedRange.endOffset, + "Unexpected endOffset after insertNode()"); + // How do we decide that the two nodes are equal, since they're in + // different trees? Since the DOMs are the same, it's enough to check + // that the index in the parent is the same all the way up the tree. + // But we can first cheat by just checking they're actually equal. + assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer), + "Unexpected startContainer after insertNode(), expected " + + expectedRange.startContainer.nodeName.toLowerCase() + " but got " + + actualRange.startContainer.nodeName.toLowerCase()); + var currentActual = actualRange.startContainer; + var currentExpected = expectedRange.startContainer; + var actual = ""; + var expected = ""; + while (currentActual && currentExpected) { + actual = indexOf(currentActual) + "-" + actual; + expected = indexOf(currentExpected) + "-" + expected; + + currentActual = currentActual.parentNode; + currentExpected = currentExpected.parentNode; + } + actual = actual.substr(0, actual.length - 1); + expected = expected.substr(0, expected.length - 1); + assert_equals(actual, expected, + "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened"); + }); + positionTests[i][j].done(); +} + +testRanges.unshift('"detached"'); + +var iStart = 0; +var iStop = testRangesShort.length; +var jStart = 0; +var jStop = testNodesShort.length; + +if (/subtest=[0-9]+,[0-9]+/.test(location.search)) { + var matches = /subtest=([0-9]+),([0-9]+)/.exec(location.search); + iStart = Number(matches[1]); + iStop = Number(matches[1]) + 1; + jStart = Number(matches[2]) + 0; + jStop = Number(matches[2]) + 1; +} + +var domTests = []; +var positionTests = []; +for (var i = iStart; i < iStop; i++) { + domTests[i] = []; + positionTests[i] = []; + for (var j = jStart; j < jStop; j++) { + domTests[i][j] = async_test(i + "," + j + ": resulting DOM for range " + testRangesShort[i] + ", node " + testNodesShort[j]); + positionTests[i][j] = async_test(i + "," + j + ": resulting range position for range " + testRangesShort[i] + ", node " + testNodesShort[j]); + } +} + +var actualIframe = document.createElement("iframe"); +actualIframe.style.display = "none"; +document.body.appendChild(actualIframe); + +var expectedIframe = document.createElement("iframe"); +expectedIframe.style.display = "none"; +document.body.appendChild(expectedIframe); + +var referenceDoc = document.implementation.createHTMLDocument(""); +referenceDoc.removeChild(referenceDoc.documentElement); + +actualIframe.onload = function() { + expectedIframe.onload = function() { + for (var i = iStart; i < iStop; i++) { + for (var j = jStart; j < jStop; j++) { + testInsertNode(i, j); + } + } + } + expectedIframe.src = "Range-test-iframe.html"; + referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true)); +} +actualIframe.src = "Range-test-iframe.html"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-intersectsNode-2.html b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-2.html new file mode 100644 index 0000000000..48072d98af --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-2.html @@ -0,0 +1,36 @@ +<!doctype htlml> +<title>Range.intersectsNode</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="div"><span id="s0">s0</span><span id="s1">s1</span><span id="s2">s2</span></div> +<script> +// Taken from Chromium bug: http://crbug.com/822510 +test(() => { + const range = new Range(); + const div = document.getElementById('div'); + const s0 = document.getElementById('s0'); + const s1 = document.getElementById('s1'); + const s2 = document.getElementById('s2'); + + // Range encloses s0 + range.setStart(div, 0); + range.setEnd(div, 1); + assert_true(range.intersectsNode(s0), '[s0] range.intersectsNode(s0)'); + assert_false(range.intersectsNode(s1), '[s0] range.intersectsNode(s1)'); + assert_false(range.intersectsNode(s2), '[s0] range.intersectsNode(s2)'); + + // Range encloses s1 + range.setStart(div, 1); + range.setEnd(div, 2); + assert_false(range.intersectsNode(s0), '[s1] range.intersectsNode(s0)'); + assert_true(range.intersectsNode(s1), '[s1] range.intersectsNode(s1)'); + assert_false(range.intersectsNode(s2), '[s1] range.intersectsNode(s2)'); + + // Range encloses s2 + range.setStart(div, 2); + range.setEnd(div, 3); + assert_false(range.intersectsNode(s0), '[s2] range.intersectsNode(s0)'); + assert_false(range.intersectsNode(s1), '[s2] range.intersectsNode(s1)'); + assert_true(range.intersectsNode(s2), '[s2] range.intersectsNode(s2)'); +}, 'Range.intersectsNode() simple cases'); +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-intersectsNode-binding.html b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-binding.html new file mode 100644 index 0000000000..57d159b030 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-binding.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>Range.intersectsNode</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<meta name=timeout content=long> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var r = document.createRange(); + assert_throws_js(TypeError, function() { r.intersectsNode(); }); + assert_throws_js(TypeError, function() { r.intersectsNode(null); }); + assert_throws_js(TypeError, function() { r.intersectsNode(undefined); }); + assert_throws_js(TypeError, function() { r.intersectsNode(42); }); + assert_throws_js(TypeError, function() { r.intersectsNode("foo"); }); + assert_throws_js(TypeError, function() { r.intersectsNode({}); }); + r.detach(); + assert_throws_js(TypeError, function() { r.intersectsNode(); }); + assert_throws_js(TypeError, function() { r.intersectsNode(null); }); + assert_throws_js(TypeError, function() { r.intersectsNode(undefined); }); + assert_throws_js(TypeError, function() { r.intersectsNode(42); }); + assert_throws_js(TypeError, function() { r.intersectsNode("foo"); }); + assert_throws_js(TypeError, function() { r.intersectsNode({}); }); +}, "Calling intersectsNode without an argument or with an invalid argument should throw a TypeError.") +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-intersectsNode-shadow.html b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-shadow.html new file mode 100644 index 0000000000..8219ba8285 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-intersectsNode-shadow.html @@ -0,0 +1,19 @@ +<!doctype html> +<title>Range.intersectsNode with Shadow DOM</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="host"></div> +<script> +test(() => { + const host = document.getElementById("host"); + host.attachShadow({ mode: "open" }).innerHTML = `<span>ABC</span>`; + + const range = document.createRange(); + range.selectNode(document.body); + + assert_true(range.intersectsNode(host), "Should intersect host"); + assert_false(range.intersectsNode(host.shadowRoot), "Should not intersect shadow root"); + assert_false(range.intersectsNode(host.shadowRoot.firstElementChild), "Should not intersect shadow span"); +}, "Range.intersectsNode() doesn't return true for shadow children in other trees"); +</script> + diff --git a/testing/web-platform/tests/dom/ranges/Range-intersectsNode.html b/testing/web-platform/tests/dom/ranges/Range-intersectsNode.html new file mode 100644 index 0000000000..97e10f6f0d --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-intersectsNode.html @@ -0,0 +1,70 @@ +<!doctype html> +<title>Range.intersectsNode() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +// Will be filled in on the first run for that range +var testRangesCached = []; + +for (var i = 0; i < testNodes.length; i++) { + var node = eval(testNodes[i]); + + for (var j = 0; j < testRanges.length; j++) { + test(function() { + if (testRangesCached[j] === undefined) { + try { + testRangesCached[j] = rangeFromEndpoints(eval(testRanges[i])); + } catch(e) { + testRangesCached[j] = null; + } + } + assert_not_equals(testRangesCached[j], null, + "Setting up the range failed"); + + var range = testRangesCached[j].cloneRange(); + + // "If node's root is different from the context object's root, + // return false and terminate these steps." + if (furthestAncestor(node) !== furthestAncestor(range.startContainer)) { + assert_equals(range.intersectsNode(node), false, + "Must return false if node and range have different roots"); + return; + } + + // "Let parent be node's parent." + var parent_ = node.parentNode; + + // "If parent is null, return true and terminate these steps." + if (!parent_) { + assert_equals(range.intersectsNode(node), true, + "Must return true if node's parent is null"); + return; + } + + // "Let offset be node's index." + var offset = indexOf(node); + + // "If (parent, offset) is before end and (parent, offset + 1) is + // after start, return true and terminate these steps." + if (getPosition(parent_, offset, range.endContainer, range.endOffset) === "before" + && getPosition(parent_, offset + 1, range.startContainer, range.startOffset) === "after") { + assert_equals(range.intersectsNode(node), true, + "Must return true if (parent, offset) is before range end and (parent, offset + 1) is after range start"); + return; + } + + // "Return false." + assert_equals(range.intersectsNode(node), false, + "Must return false if (parent, offset) is not before range end or (parent, offset + 1) is not after range start"); + }, "Node " + i + " " + testNodes[i] + ", range " + j + " " + testRanges[j]); + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-isPointInRange.html b/testing/web-platform/tests/dom/ranges/Range-isPointInRange.html new file mode 100644 index 0000000000..80db97e844 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-isPointInRange.html @@ -0,0 +1,83 @@ +<!doctype html> +<title>Range.isPointInRange() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +var testRangesCached = []; +test(function() { + for (var j = 0; j < testRanges.length; j++) { + test(function() { + testRangesCached[j] = rangeFromEndpoints(eval(testRanges[j])); + }, "Set up for range " + j + " " + testRanges[j]); + } + var detachedRange = document.createRange(); + detachedRange.detach(); + testRanges.push("detached"); + testRangesCached.push(detachedRange); +}, "Setup"); + +for (var i = 0; i < testPoints.length; i++) { + var node = eval(testPoints[i])[0]; + var offset = eval(testPoints[i])[1]; + + // isPointInRange is an unsigned long, so per WebIDL, we need to treat it + // as though it wrapped to an unsigned 32-bit integer. + var normalizedOffset = offset % Math.pow(2, 32); + if (normalizedOffset < 0) { + normalizedOffset += Math.pow(2, 32); + } + + for (var j = 0; j < testRanges.length; j++) { + test(function() { + var range = testRangesCached[j].cloneRange(); + + // "If node's root is different from the context object's root, + // return false and terminate these steps." + if (furthestAncestor(node) !== furthestAncestor(range.startContainer)) { + assert_false(range.isPointInRange(node, offset), + "Must return false if node has a different root from the context object"); + return; + } + + // "If node is a doctype, throw an "InvalidNodeTypeError" exception + // and terminate these steps." + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { + range.isPointInRange(node, offset); + }, "Must throw InvalidNodeTypeError if node is a doctype"); + return; + } + + // "If offset is greater than node's length, throw an + // "IndexSizeError" exception and terminate these steps." + if (normalizedOffset > nodeLength(node)) { + assert_throws_dom("INDEX_SIZE_ERR", function() { + range.isPointInRange(node, offset); + }, "Must throw IndexSizeError if offset is greater than length"); + return; + } + + // "If (node, offset) is before start or after end, return false + // and terminate these steps." + if (getPosition(node, normalizedOffset, range.startContainer, range.startOffset) === "before" + || getPosition(node, normalizedOffset, range.endContainer, range.endOffset) === "after") { + assert_false(range.isPointInRange(node, offset), + "Must return false if point is before start or after end"); + return; + } + + // "Return true." + assert_true(range.isPointInRange(node, offset), + "Must return true if point is not before start, after end, or in different tree"); + }, "Point " + i + " " + testPoints[i] + ", range " + j + " " + testRanges[j]); + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-appendChild.html b/testing/web-platform/tests/dom/ranges/Range-mutations-appendChild.html new file mode 100644 index 0000000000..5b5b5a55df --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-appendChild.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<title>Range mutation tests - appendChild</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(appendChildTests, function(params) { return params[0] + ".appendChild(" + params[1] + ")" }, testAppendChild); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-appendData.html b/testing/web-platform/tests/dom/ranges/Range-mutations-appendData.html new file mode 100644 index 0000000000..1d4879d57c --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-appendData.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - appendData</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(appendDataTests, function(params) { return params[0] + ".appendData(" + params[1] + ")" }, testAppendData); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-dataChange.html b/testing/web-platform/tests/dom/ranges/Range-mutations-dataChange.html new file mode 100644 index 0000000000..3683e8bb9b --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-dataChange.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - update data by IDL attributes</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(dataChangeTests, function(params) { return params[0] + "." + eval(params[1]) + " " + eval(params[2]) + ' ' + params[3] }, testDataChange); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-deleteData.html b/testing/web-platform/tests/dom/ranges/Range-mutations-deleteData.html new file mode 100644 index 0000000000..5f2b852f5b --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-deleteData.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - deleteData</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(deleteDataTests, function(params) { return params[0] + ".deleteData(" + params[1] + ", " + params[2] + ")" }, testDeleteData); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-insertBefore.html b/testing/web-platform/tests/dom/ranges/Range-mutations-insertBefore.html new file mode 100644 index 0000000000..c71b239547 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-insertBefore.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - insertBefore</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(insertBeforeTests, function(params) { return params[0] + ".insertBefore(" + params[1] + ", " + params[2] + ")" }, testInsertBefore); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-insertData.html b/testing/web-platform/tests/dom/ranges/Range-mutations-insertData.html new file mode 100644 index 0000000000..fca533d503 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-insertData.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - insertData</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(insertDataTests, function(params) { return params[0] + ".insertData(" + params[1] + ", " + params[2] + ")" }, testInsertData); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-removeChild.html b/testing/web-platform/tests/dom/ranges/Range-mutations-removeChild.html new file mode 100644 index 0000000000..a8d2381253 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-removeChild.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - removeChild</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(removeChildTests, function(params) { return params[0] + ".parentNode.removeChild(" + params[0] + ")" }, testRemoveChild); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-replaceChild.html b/testing/web-platform/tests/dom/ranges/Range-mutations-replaceChild.html new file mode 100644 index 0000000000..a4ef0c365e --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-replaceChild.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - replaceChild</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(replaceChildTests, function(params) { return params[0] + ".replaceChild(" + params[1] + ", " + params[2] + ")" }, testReplaceChild); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-replaceData.html b/testing/web-platform/tests/dom/ranges/Range-mutations-replaceData.html new file mode 100644 index 0000000000..55ddb146ea --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-replaceData.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - replaceData</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(replaceDataTests, function(params) { return params[0] + ".replaceData(" + params[1] + ", " + params[2] + ", " + params[3] + ")" }, testReplaceData); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations-splitText.html b/testing/web-platform/tests/dom/ranges/Range-mutations-splitText.html new file mode 100644 index 0000000000..fbb4c8d9b6 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations-splitText.html @@ -0,0 +1,14 @@ +<!doctype html> +<title>Range mutation tests - splitText</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../common.js"></script> +<script src="Range-mutations.js"></script> +<script> +doTests(splitTextTests, function(params) { return params[0] + ".splitText(" + params[1] + ")" }, testSplitText); +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-mutations.js b/testing/web-platform/tests/dom/ranges/Range-mutations.js new file mode 100644 index 0000000000..23c013ac6a --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-mutations.js @@ -0,0 +1,921 @@ +"use strict"; + +// These tests probably use too much abstraction and too little copy-paste. +// Reader beware. +// +// TODO: +// +// * Lots and lots and lots more different types of ranges +// * insertBefore() with DocumentFragments +// * Fill out other insert/remove tests +// * normalize() (https://www.w3.org/Bugs/Public/show_bug.cgi?id=13843) + +// Give a textual description of the range we're testing, for the test names. +function describeRange(startContainer, startOffset, endContainer, endOffset) { + if (startContainer == endContainer && startOffset == endOffset) { + return "range collapsed at (" + startContainer + ", " + startOffset + ")"; + } else if (startContainer == endContainer) { + return "range on " + startContainer + " from " + startOffset + " to " + endOffset; + } else { + return "range from (" + startContainer + ", " + startOffset + ") to (" + endContainer + ", " + endOffset + ")"; + } +} + +// Lists of the various types of nodes we'll want to use. We use strings that +// we can later eval(), so that we can produce legible test names. +var textNodes = [ + "paras[0].firstChild", + "paras[1].firstChild", + "foreignTextNode", + "xmlTextNode", + "detachedTextNode", + "detachedForeignTextNode", + "detachedXmlTextNode", +]; +var commentNodes = [ + "comment", + "foreignComment", + "xmlComment", + "detachedComment", + "detachedForeignComment", + "detachedXmlComment", +]; +var characterDataNodes = textNodes.concat(commentNodes); + +// This function is slightly scary, but it works well enough, so . . . +// sourceTests is an array of test data that will be altered in mysterious ways +// before being passed off to doTest, descFn is something that takes an element +// of sourceTests and produces the first part of a human-readable description +// of the test, testFn is the function that doTest will call to do the actual +// work and tell it what results to expect. +function doTests(sourceTests, descFn, testFn) { + var tests = []; + for (var i = 0; i < sourceTests.length; i++) { + var params = sourceTests[i]; + var len = params.length; + tests.push([ + descFn(params) + ", with unselected " + describeRange(params[len - 4], params[len - 3], params[len - 2], params[len - 1]), + // The closure here ensures that the params that testFn get are the + // current version of params, not the version from the last + // iteration of this loop. We test that none of the parameters + // evaluate to undefined to catch bugs in our eval'ing, like + // mistyping a property name. + function(params) { return function() { + var evaledParams = params.map(eval); + for (var i = 0; i < evaledParams.length; i++) { + assert_not_equals(typeof evaledParams[i], "undefined", + "Test bug: " + params[i] + " is undefined"); + } + return testFn.apply(null, evaledParams); + } }(params), + false, + params[len - 4], + params[len - 3], + params[len - 2], + params[len - 1] + ]); + tests.push([ + descFn(params) + ", with selected " + describeRange(params[len - 4], params[len - 3], params[len - 2], params[len - 1]), + function(params) { return function(selectedRange) { + var evaledParams = params.slice(0, len - 4).map(eval); + for (var i = 0; i < evaledParams.length; i++) { + assert_not_equals(typeof evaledParams[i], "undefined", + "Test bug: " + params[i] + " is undefined"); + } + // Override input range with the one that was actually selected when computing the expected result. + evaledParams = evaledParams.concat([selectedRange.startContainer, selectedRange.startOffset, selectedRange.endContainer, selectedRange.endOffset]); + return testFn.apply(null, evaledParams); + } }(params), + true, + params[len - 4], + params[len - 3], + params[len - 2], + params[len - 1] + ]); + } + generate_tests(doTest, tests); +} + +// Set up the range, call the callback function to do the DOM modification and +// tell us what to expect. The callback function needs to return a +// four-element array with the expected start/end containers/offsets, and +// receives no arguments. useSelection tells us whether the Range should be +// added to a Selection and the Selection tested to ensure that the mutation +// affects user selections as well as other ranges; every test is run with this +// both false and true, because when it's set to true WebKit and Opera fail all +// tests' sanity checks, which is unhelpful. The last four parameters just +// tell us what range to build. +function doTest(callback, useSelection, startContainer, startOffset, endContainer, endOffset) { + // Recreate all the test nodes in case they were altered by the last test + // run. + setupRangeTests(); + startContainer = eval(startContainer); + startOffset = eval(startOffset); + endContainer = eval(endContainer); + endOffset = eval(endOffset); + + var ownerDoc = startContainer.nodeType == Node.DOCUMENT_NODE + ? startContainer + : startContainer.ownerDocument; + var range = ownerDoc.createRange(); + range.setStart(startContainer, startOffset); + range.setEnd(endContainer, endOffset); + + if (useSelection) { + getSelection().removeAllRanges(); + getSelection().addRange(range); + + // Some browsers refuse to add a range unless it results in an actual visible selection. + if (!getSelection().rangeCount) + return; + + // Override range with the one that was actually selected as it differs in some browsers. + range = getSelection().getRangeAt(0); + } + + var expected = callback(range); + + assert_equals(range.startContainer, expected[0], + "Wrong start container"); + assert_equals(range.startOffset, expected[1], + "Wrong start offset"); + assert_equals(range.endContainer, expected[2], + "Wrong end container"); + assert_equals(range.endOffset, expected[3], + "Wrong end offset"); +} + + +// Now we get to the specific tests. + +function testSplitText(oldNode, offset, startContainer, startOffset, endContainer, endOffset) { + // Save these for later + var originalStartOffset = startOffset; + var originalEndOffset = endOffset; + var originalLength = oldNode.length; + + var newNode; + try { + newNode = oldNode.splitText(offset); + } catch (e) { + // Should only happen if offset is negative + return [startContainer, startOffset, endContainer, endOffset]; + } + + // First we adjust for replacing data: + // + // "Replace data with offset offset, count count, and data the empty + // string." + // + // That translates to offset = offset, count = originalLength - offset, + // data = "". node is oldNode. + // + // "For every boundary point whose node is node, and whose offset is + // greater than offset but less than or equal to offset plus count, set its + // offset to offset." + if (startContainer == oldNode + && startOffset > offset + && startOffset <= originalLength) { + startOffset = offset; + } + + if (endContainer == oldNode + && endOffset > offset + && endOffset <= originalLength) { + endOffset = offset; + } + + // "For every boundary point whose node is node, and whose offset is + // greater than offset plus count, add the length of data to its offset, + // then subtract count from it." + // + // Can't happen: offset plus count is originalLength. + + // Now we insert a node, if oldNode's parent isn't null: "For each boundary + // point whose node is the new parent of the affected node and whose offset + // is greater than the new index of the affected node, add one to the + // boundary point's offset." + if (startContainer == oldNode.parentNode + && startOffset > 1 + indexOf(oldNode)) { + startOffset++; + } + + if (endContainer == oldNode.parentNode + && endOffset > 1 + indexOf(oldNode)) { + endOffset++; + } + + // Finally, the splitText stuff itself: + // + // "If parent is not null, run these substeps: + // + // * "For each range whose start node is node and start offset is greater + // than offset, set its start node to new node and decrease its start + // offset by offset. + // + // * "For each range whose end node is node and end offset is greater + // than offset, set its end node to new node and decrease its end offset + // by offset. + // + // * "For each range whose start node is parent and start offset is equal + // to the index of node + 1, increase its start offset by one. + // + // * "For each range whose end node is parent and end offset is equal to + // the index of node + 1, increase its end offset by one." + if (oldNode.parentNode) { + if (startContainer == oldNode && originalStartOffset > offset) { + startContainer = newNode; + startOffset = originalStartOffset - offset; + } + + if (endContainer == oldNode && originalEndOffset > offset) { + endContainer = newNode; + endOffset = originalEndOffset - offset; + } + + if (startContainer == oldNode.parentNode + && startOffset == 1 + indexOf(oldNode)) { + startOffset++; + } + + if (endContainer == oldNode.parentNode + && endOffset == 1 + indexOf(oldNode)) { + endOffset++; + } + } + + return [startContainer, startOffset, endContainer, endOffset]; +} + +// The offset argument is unsigned, so per WebIDL -1 should wrap to 4294967295, +// which is probably longer than the length, so it should throw an exception. +// This is no different from the other cases where the offset is longer than +// the length, and the wrapping complicates my testing slightly, so I won't +// bother testing negative values here or in other cases. +var splitTextTests = []; +for (var i = 0; i < textNodes.length; i++) { + var node = textNodes[i]; + splitTextTests.push([node, 376, node, 0, node, 1]); + splitTextTests.push([node, 0, node, 0, node, 0]); + splitTextTests.push([node, 1, node, 1, node, 1]); + splitTextTests.push([node, node + ".length", node, node + ".length", node, node + ".length"]); + splitTextTests.push([node, 1, node, 1, node, 3]); + splitTextTests.push([node, 2, node, 1, node, 3]); + splitTextTests.push([node, 3, node, 1, node, 3]); +} + +splitTextTests.push( + ["paras[0].firstChild", 1, "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, "paras[0]", 0, "paras[0].firstChild", 3] +); + + +function testReplaceDataAlgorithm(node, offset, count, data, callback, startContainer, startOffset, endContainer, endOffset) { + // Mutation works the same any time DOM Core's "replace data" algorithm is + // invoked. node, offset, count, data are as in that algorithm. The + // callback is what does the actual setting. Not to be confused with + // testReplaceData, which tests the replaceData() method. + + // Barring any provision to the contrary, the containers and offsets must + // not change. + var expectedStartContainer = startContainer; + var expectedStartOffset = startOffset; + var expectedEndContainer = endContainer; + var expectedEndOffset = endOffset; + + var originalParent = node.parentNode; + var originalData = node.data; + + var exceptionThrown = false; + try { + callback(); + } catch (e) { + // Should only happen if offset is greater than length + exceptionThrown = true; + } + + assert_equals(node.parentNode, originalParent, + "Sanity check failed: changing data changed the parent"); + + // "User agents must run the following steps whenever they replace data of + // a CharacterData node, as though they were written in the specification + // for that algorithm after all other steps. In particular, the steps must + // not be executed if the algorithm threw an exception." + if (exceptionThrown) { + assert_equals(node.data, originalData, + "Sanity check failed: exception thrown but data changed"); + } else { + assert_equals(node.data, + originalData.substr(0, offset) + data + originalData.substr(offset + count), + "Sanity check failed: data not changed as expected"); + } + + // "For every boundary point whose node is node, and whose offset is + // greater than offset but less than or equal to offset plus count, set + // its offset to offset." + if (!exceptionThrown + && startContainer == node + && startOffset > offset + && startOffset <= offset + count) { + expectedStartOffset = offset; + } + + if (!exceptionThrown + && endContainer == node + && endOffset > offset + && endOffset <= offset + count) { + expectedEndOffset = offset; + } + + // "For every boundary point whose node is node, and whose offset is + // greater than offset plus count, add the length of data to its offset, + // then subtract count from it." + if (!exceptionThrown + && startContainer == node + && startOffset > offset + count) { + expectedStartOffset += data.length - count; + } + + if (!exceptionThrown + && endContainer == node + && endOffset > offset + count) { + expectedEndOffset += data.length - count; + } + + return [expectedStartContainer, expectedStartOffset, expectedEndContainer, expectedEndOffset]; +} + +function testInsertData(node, offset, data, startContainer, startOffset, endContainer, endOffset) { + return testReplaceDataAlgorithm(node, offset, 0, data, + function() { node.insertData(offset, data) }, + startContainer, startOffset, endContainer, endOffset); +} + +var insertDataTests = []; +for (var i = 0; i < characterDataNodes.length; i++) { + var node = characterDataNodes[i]; + insertDataTests.push([node, 376, '"foo"', node, 0, node, 1]); + insertDataTests.push([node, 0, '"foo"', node, 0, node, 0]); + insertDataTests.push([node, 1, '"foo"', node, 1, node, 1]); + insertDataTests.push([node, node + ".length", '"foo"', node, node + ".length", node, node + ".length"]); + insertDataTests.push([node, 1, '"foo"', node, 1, node, 3]); + insertDataTests.push([node, 2, '"foo"', node, 1, node, 3]); + insertDataTests.push([node, 3, '"foo"', node, 1, node, 3]); + + insertDataTests.push([node, 376, '""', node, 0, node, 1]); + insertDataTests.push([node, 0, '""', node, 0, node, 0]); + insertDataTests.push([node, 1, '""', node, 1, node, 1]); + insertDataTests.push([node, node + ".length", '""', node, node + ".length", node, node + ".length"]); + insertDataTests.push([node, 1, '""', node, 1, node, 3]); + insertDataTests.push([node, 2, '""', node, 1, node, 3]); + insertDataTests.push([node, 3, '""', node, 1, node, 3]); +} + +insertDataTests.push( + ["paras[0].firstChild", 1, '"foo"', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, '"foo"', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, '"foo"', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3] +); + + +function testAppendData(node, data, startContainer, startOffset, endContainer, endOffset) { + return testReplaceDataAlgorithm(node, node.length, 0, data, + function() { node.appendData(data) }, + startContainer, startOffset, endContainer, endOffset); +} + +var appendDataTests = []; +for (var i = 0; i < characterDataNodes.length; i++) { + var node = characterDataNodes[i]; + appendDataTests.push([node, '"foo"', node, 0, node, 1]); + appendDataTests.push([node, '"foo"', node, 0, node, 0]); + appendDataTests.push([node, '"foo"', node, 1, node, 1]); + appendDataTests.push([node, '"foo"', node, 0, node, node + ".length"]); + appendDataTests.push([node, '"foo"', node, 1, node, node + ".length"]); + appendDataTests.push([node, '"foo"', node, node + ".length", node, node + ".length"]); + appendDataTests.push([node, '"foo"', node, 1, node, 3]); + + appendDataTests.push([node, '""', node, 0, node, 1]); + appendDataTests.push([node, '""', node, 0, node, 0]); + appendDataTests.push([node, '""', node, 1, node, 1]); + appendDataTests.push([node, '""', node, 0, node, node + ".length"]); + appendDataTests.push([node, '""', node, 1, node, node + ".length"]); + appendDataTests.push([node, '""', node, node + ".length", node, node + ".length"]); + appendDataTests.push([node, '""', node, 1, node, 3]); +} + +appendDataTests.push( + ["paras[0].firstChild", '""', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", '""', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", '""', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", '""', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", '""', "paras[0]", 0, "paras[0].firstChild", 3], + + ["paras[0].firstChild", '"foo"', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", '"foo"', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", '"foo"', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", '"foo"', "paras[0]", 0, "paras[0].firstChild", 3] +); + + +function testDeleteData(node, offset, count, startContainer, startOffset, endContainer, endOffset) { + return testReplaceDataAlgorithm(node, offset, count, "", + function() { node.deleteData(offset, count) }, + startContainer, startOffset, endContainer, endOffset); +} + +var deleteDataTests = []; +for (var i = 0; i < characterDataNodes.length; i++) { + var node = characterDataNodes[i]; + deleteDataTests.push([node, 376, 2, node, 0, node, 1]); + deleteDataTests.push([node, 0, 2, node, 0, node, 0]); + deleteDataTests.push([node, 1, 2, node, 1, node, 1]); + deleteDataTests.push([node, node + ".length", 2, node, node + ".length", node, node + ".length"]); + deleteDataTests.push([node, 1, 2, node, 1, node, 3]); + deleteDataTests.push([node, 2, 2, node, 1, node, 3]); + deleteDataTests.push([node, 3, 2, node, 1, node, 3]); + + deleteDataTests.push([node, 376, 0, node, 0, node, 1]); + deleteDataTests.push([node, 0, 0, node, 0, node, 0]); + deleteDataTests.push([node, 1, 0, node, 1, node, 1]); + deleteDataTests.push([node, node + ".length", 0, node, node + ".length", node, node + ".length"]); + deleteDataTests.push([node, 1, 0, node, 1, node, 3]); + deleteDataTests.push([node, 2, 0, node, 1, node, 3]); + deleteDataTests.push([node, 3, 0, node, 1, node, 3]); + + deleteDataTests.push([node, 376, 631, node, 0, node, 1]); + deleteDataTests.push([node, 0, 631, node, 0, node, 0]); + deleteDataTests.push([node, 1, 631, node, 1, node, 1]); + deleteDataTests.push([node, node + ".length", 631, node, node + ".length", node, node + ".length"]); + deleteDataTests.push([node, 1, 631, node, 1, node, 3]); + deleteDataTests.push([node, 2, 631, node, 1, node, 3]); + deleteDataTests.push([node, 3, 631, node, 1, node, 3]); +} + +deleteDataTests.push( + ["paras[0].firstChild", 1, 2, "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, 2, "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, 2, "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 2, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, 2, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, 2, "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 2, "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, 2, "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, 2, "paras[0]", 0, "paras[0].firstChild", 3] +); + + +function testReplaceData(node, offset, count, data, startContainer, startOffset, endContainer, endOffset) { + return testReplaceDataAlgorithm(node, offset, count, data, + function() { node.replaceData(offset, count, data) }, + startContainer, startOffset, endContainer, endOffset); +} + +var replaceDataTests = []; +for (var i = 0; i < characterDataNodes.length; i++) { + var node = characterDataNodes[i]; + replaceDataTests.push([node, 376, 0, '"foo"', node, 0, node, 1]); + replaceDataTests.push([node, 0, 0, '"foo"', node, 0, node, 0]); + replaceDataTests.push([node, 1, 0, '"foo"', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 0, '"foo"', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 0, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 2, 0, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 3, 0, '"foo"', node, 1, node, 3]); + + replaceDataTests.push([node, 376, 0, '""', node, 0, node, 1]); + replaceDataTests.push([node, 0, 0, '""', node, 0, node, 0]); + replaceDataTests.push([node, 1, 0, '""', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 0, '""', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 0, '""', node, 1, node, 3]); + replaceDataTests.push([node, 2, 0, '""', node, 1, node, 3]); + replaceDataTests.push([node, 3, 0, '""', node, 1, node, 3]); + + replaceDataTests.push([node, 376, 1, '"foo"', node, 0, node, 1]); + replaceDataTests.push([node, 0, 1, '"foo"', node, 0, node, 0]); + replaceDataTests.push([node, 1, 1, '"foo"', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 1, '"foo"', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 1, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 2, 1, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 3, 1, '"foo"', node, 1, node, 3]); + + replaceDataTests.push([node, 376, 1, '""', node, 0, node, 1]); + replaceDataTests.push([node, 0, 1, '""', node, 0, node, 0]); + replaceDataTests.push([node, 1, 1, '""', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 1, '""', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 1, '""', node, 1, node, 3]); + replaceDataTests.push([node, 2, 1, '""', node, 1, node, 3]); + replaceDataTests.push([node, 3, 1, '""', node, 1, node, 3]); + + replaceDataTests.push([node, 376, 47, '"foo"', node, 0, node, 1]); + replaceDataTests.push([node, 0, 47, '"foo"', node, 0, node, 0]); + replaceDataTests.push([node, 1, 47, '"foo"', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 47, '"foo"', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 47, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 2, 47, '"foo"', node, 1, node, 3]); + replaceDataTests.push([node, 3, 47, '"foo"', node, 1, node, 3]); + + replaceDataTests.push([node, 376, 47, '""', node, 0, node, 1]); + replaceDataTests.push([node, 0, 47, '""', node, 0, node, 0]); + replaceDataTests.push([node, 1, 47, '""', node, 1, node, 1]); + replaceDataTests.push([node, node + ".length", 47, '""', node, node + ".length", node, node + ".length"]); + replaceDataTests.push([node, 1, 47, '""', node, 1, node, 3]); + replaceDataTests.push([node, 2, 47, '""', node, 1, node, 3]); + replaceDataTests.push([node, 3, 47, '""', node, 1, node, 3]); +} + +replaceDataTests.push( + ["paras[0].firstChild", 1, 0, '"foo"', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, 0, '"foo"', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, 0, '"foo"', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 0, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, 0, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, 0, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 0, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, 0, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, 0, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + + ["paras[0].firstChild", 1, 1, '"foo"', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, 1, '"foo"', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, 1, '"foo"', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 1, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, 1, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, 1, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 1, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, 1, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, 1, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + + ["paras[0].firstChild", 1, 47, '"foo"', "paras[0]", 0, "paras[0]", 0], + ["paras[0].firstChild", 1, 47, '"foo"', "paras[0]", 0, "paras[0]", 1], + ["paras[0].firstChild", 1, 47, '"foo"', "paras[0]", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 47, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 2, 47, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 3, 47, '"foo"', "paras[0].firstChild", 1, "paras[0]", 1], + ["paras[0].firstChild", 1, 47, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 2, 47, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3], + ["paras[0].firstChild", 3, 47, '"foo"', "paras[0]", 0, "paras[0].firstChild", 3] +); + + +// There are lots of ways to set data, so we pass a callback that does the +// actual setting. +function testDataChange(node, attr, op, rval, startContainer, startOffset, endContainer, endOffset) { + return testReplaceDataAlgorithm(node, 0, node.length, op == "=" ? rval : node[attr] + rval, + function() { + if (op == "=") { + node[attr] = rval; + } else if (op == "+=") { + node[attr] += rval; + } else { + throw "Unknown op " + op; + } + }, + startContainer, startOffset, endContainer, endOffset); +} + +var dataChangeTests = []; +var dataChangeTestAttrs = ["data", "textContent", "nodeValue"]; +for (var i = 0; i < characterDataNodes.length; i++) { + var node = characterDataNodes[i]; + var dataChangeTestRanges = [ + [node, 0, node, 0], + [node, 0, node, 1], + [node, 1, node, 1], + [node, 0, node, node + ".length"], + [node, 1, node, node + ".length"], + [node, node + ".length", node, node + ".length"], + ]; + + for (var j = 0; j < dataChangeTestRanges.length; j++) { + for (var k = 0; k < dataChangeTestAttrs.length; k++) { + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"="', + '""', + ].concat(dataChangeTestRanges[j])); + + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"="', + '"foo"', + ].concat(dataChangeTestRanges[j])); + + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"="', + node + "." + dataChangeTestAttrs[k], + ].concat(dataChangeTestRanges[j])); + + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"+="', + '""', + ].concat(dataChangeTestRanges[j])); + + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"+="', + '"foo"', + ].concat(dataChangeTestRanges[j])); + + dataChangeTests.push([ + node, + '"' + dataChangeTestAttrs[k] + '"', + '"+="', + node + "." + dataChangeTestAttrs[k] + ].concat(dataChangeTestRanges[j])); + } + } +} + + +// Now we test node insertions and deletions, as opposed to just data changes. +// To avoid loads of repetition, we define modifyForRemove() and +// modifyForInsert(). + +// If we were to remove removedNode from its parent, what would the boundary +// point [node, offset] become? Returns [new node, new offset]. Must be +// called BEFORE the node is actually removed, so its parent is not null. (If +// the parent is null, it will do nothing.) +function modifyForRemove(removedNode, point) { + var oldParent = removedNode.parentNode; + var oldIndex = indexOf(removedNode); + if (!oldParent) { + return point; + } + + // "For each boundary point whose node is removed node or a descendant of + // it, set the boundary point to (old parent, old index)." + if (point[0] == removedNode || isDescendant(point[0], removedNode)) { + return [oldParent, oldIndex]; + } + + // "For each boundary point whose node is old parent and whose offset is + // greater than old index, subtract one from its offset." + if (point[0] == oldParent && point[1] > oldIndex) { + return [point[0], point[1] - 1]; + } + + return point; +} + +// Update the given boundary point [node, offset] to account for the fact that +// insertedNode was just inserted into its current position. This must be +// called AFTER insertedNode was already inserted. +function modifyForInsert(insertedNode, point) { + // "For each boundary point whose node is the new parent of the affected + // node and whose offset is greater than the new index of the affected + // node, add one to the boundary point's offset." + if (point[0] == insertedNode.parentNode && point[1] > indexOf(insertedNode)) { + return [point[0], point[1] + 1]; + } + + return point; +} + + +function testInsertBefore(newParent, affectedNode, refNode, startContainer, startOffset, endContainer, endOffset) { + var expectedStart = [startContainer, startOffset]; + var expectedEnd = [endContainer, endOffset]; + + expectedStart = modifyForRemove(affectedNode, expectedStart); + expectedEnd = modifyForRemove(affectedNode, expectedEnd); + + try { + newParent.insertBefore(affectedNode, refNode); + } catch (e) { + // For our purposes, assume that DOM Core is true -- i.e., ignore + // mutation events and similar. + return [startContainer, startOffset, endContainer, endOffset]; + } + + expectedStart = modifyForInsert(affectedNode, expectedStart); + expectedEnd = modifyForInsert(affectedNode, expectedEnd); + + return expectedStart.concat(expectedEnd); +} + +var insertBeforeTests = [ + // Moving a node to its current position + ["testDiv", "paras[0]", "paras[1]", "paras[0]", 0, "paras[0]", 0], + ["testDiv", "paras[0]", "paras[1]", "paras[0]", 0, "paras[0]", 1], + ["testDiv", "paras[0]", "paras[1]", "paras[0]", 1, "paras[0]", 1], + ["testDiv", "paras[0]", "paras[1]", "testDiv", 0, "testDiv", 2], + ["testDiv", "paras[0]", "paras[1]", "testDiv", 1, "testDiv", 1], + ["testDiv", "paras[0]", "paras[1]", "testDiv", 1, "testDiv", 2], + ["testDiv", "paras[0]", "paras[1]", "testDiv", 2, "testDiv", 2], + + // Stuff that actually moves something. Note that paras[0] and paras[1] + // are both children of testDiv. + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 1, "paras[0]", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 0, "testDiv", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 0, "testDiv", 2], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 1, "testDiv", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 1, "testDiv", 2], + ["paras[0]", "paras[1]", "null", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "paras[1]", "null", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "paras[1]", "null", "paras[0]", 1, "paras[0]", 1], + ["paras[0]", "paras[1]", "null", "testDiv", 0, "testDiv", 1], + ["paras[0]", "paras[1]", "null", "testDiv", 0, "testDiv", 2], + ["paras[0]", "paras[1]", "null", "testDiv", 1, "testDiv", 1], + ["paras[0]", "paras[1]", "null", "testDiv", 1, "testDiv", 2], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 0], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 2], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 1, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 0], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 2], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 1, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "null", "foreignDoc", 0, "foreignDoc", 1], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 1, "paras[0]", 1], + + // Stuff that throws exceptions + ["paras[0]", "paras[0]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "testDiv", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "foreignDoc", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document.doctype", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], +]; + + +function testReplaceChild(newParent, newChild, oldChild, startContainer, startOffset, endContainer, endOffset) { + var expectedStart = [startContainer, startOffset]; + var expectedEnd = [endContainer, endOffset]; + + expectedStart = modifyForRemove(oldChild, expectedStart); + expectedEnd = modifyForRemove(oldChild, expectedEnd); + + if (newChild != oldChild) { + // Don't do this twice, if they're the same! + expectedStart = modifyForRemove(newChild, expectedStart); + expectedEnd = modifyForRemove(newChild, expectedEnd); + } + + try { + newParent.replaceChild(newChild, oldChild); + } catch (e) { + return [startContainer, startOffset, endContainer, endOffset]; + } + + expectedStart = modifyForInsert(newChild, expectedStart); + expectedEnd = modifyForInsert(newChild, expectedEnd); + + return expectedStart.concat(expectedEnd); +} + +var replaceChildTests = [ + // Moving a node to its current position. Doesn't match most browsers' + // behavior, but we probably want to keep the spec the same anyway: + // https://bugzilla.mozilla.org/show_bug.cgi?id=647603 + ["testDiv", "paras[0]", "paras[0]", "paras[0]", 0, "paras[0]", 0], + ["testDiv", "paras[0]", "paras[0]", "paras[0]", 0, "paras[0]", 1], + ["testDiv", "paras[0]", "paras[0]", "paras[0]", 1, "paras[0]", 1], + ["testDiv", "paras[0]", "paras[0]", "testDiv", 0, "testDiv", 2], + ["testDiv", "paras[0]", "paras[0]", "testDiv", 1, "testDiv", 1], + ["testDiv", "paras[0]", "paras[0]", "testDiv", 1, "testDiv", 2], + ["testDiv", "paras[0]", "paras[0]", "testDiv", 2, "testDiv", 2], + + // Stuff that actually moves something. + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "paras[0]", 1, "paras[0]", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 0, "testDiv", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 0, "testDiv", 2], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 1, "testDiv", 1], + ["paras[0]", "paras[1]", "paras[0].firstChild", "testDiv", 1, "testDiv", 2], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 0], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", 2], + ["foreignDoc", "detachedComment", "foreignDoc.documentElement", "foreignDoc", 1, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 0], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 1], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 0, "foreignDoc", 2], + ["foreignDoc", "detachedComment", "foreignDoc.doctype", "foreignDoc", 1, "foreignDoc", 1], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "xmlTextNode", "paras[0].firstChild", "paras[0]", 1, "paras[0]", 1], + + // Stuff that throws exceptions + ["paras[0]", "paras[0]", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "testDiv", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "foreignDoc", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document.doctype", "paras[0].firstChild", "paras[0]", 0, "paras[0]", 1], +]; + + +function testAppendChild(newParent, affectedNode, startContainer, startOffset, endContainer, endOffset) { + var expectedStart = [startContainer, startOffset]; + var expectedEnd = [endContainer, endOffset]; + + expectedStart = modifyForRemove(affectedNode, expectedStart); + expectedEnd = modifyForRemove(affectedNode, expectedEnd); + + try { + newParent.appendChild(affectedNode); + } catch (e) { + return [startContainer, startOffset, endContainer, endOffset]; + } + + // These two lines will actually never do anything, if you think about it, + // but let's leave them in so correctness is more obvious. + expectedStart = modifyForInsert(affectedNode, expectedStart); + expectedEnd = modifyForInsert(affectedNode, expectedEnd); + + return expectedStart.concat(expectedEnd); +} + +var appendChildTests = [ + // Moving a node to its current position + ["testDiv", "testDiv.lastChild", "testDiv.lastChild", 0, "testDiv.lastChild", 0], + ["testDiv", "testDiv.lastChild", "testDiv.lastChild", 0, "testDiv.lastChild", 1], + ["testDiv", "testDiv.lastChild", "testDiv.lastChild", 1, "testDiv.lastChild", 1], + ["testDiv", "testDiv.lastChild", "testDiv", "testDiv.childNodes.length - 2", "testDiv", "testDiv.childNodes.length"], + ["testDiv", "testDiv.lastChild", "testDiv", "testDiv.childNodes.length - 2", "testDiv", "testDiv.childNodes.length - 1"], + ["testDiv", "testDiv.lastChild", "testDiv", "testDiv.childNodes.length - 1", "testDiv", "testDiv.childNodes.length"], + ["testDiv", "testDiv.lastChild", "testDiv", "testDiv.childNodes.length - 1", "testDiv", "testDiv.childNodes.length - 1"], + ["testDiv", "testDiv.lastChild", "testDiv", "testDiv.childNodes.length", "testDiv", "testDiv.childNodes.length"], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv.lastChild", 0, "detachedDiv.lastChild", 0], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv.lastChild", 0, "detachedDiv.lastChild", 1], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv.lastChild", 1, "detachedDiv.lastChild", 1], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv", "detachedDiv.childNodes.length - 2", "detachedDiv", "detachedDiv.childNodes.length"], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv", "detachedDiv.childNodes.length - 2", "detachedDiv", "detachedDiv.childNodes.length - 1"], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv", "detachedDiv.childNodes.length - 1", "detachedDiv", "detachedDiv.childNodes.length"], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv", "detachedDiv.childNodes.length - 1", "detachedDiv", "detachedDiv.childNodes.length - 1"], + ["detachedDiv", "detachedDiv.lastChild", "detachedDiv", "detachedDiv.childNodes.length", "detachedDiv", "detachedDiv.childNodes.length"], + + // Stuff that actually moves something + ["paras[0]", "paras[1]", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "paras[1]", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "paras[1]", "paras[0]", 1, "paras[0]", 1], + ["paras[0]", "paras[1]", "testDiv", 0, "testDiv", 1], + ["paras[0]", "paras[1]", "testDiv", 0, "testDiv", 2], + ["paras[0]", "paras[1]", "testDiv", 1, "testDiv", 1], + ["paras[0]", "paras[1]", "testDiv", 1, "testDiv", 2], + ["foreignDoc", "detachedComment", "foreignDoc", "foreignDoc.childNodes.length - 1", "foreignDoc", "foreignDoc.childNodes.length"], + ["foreignDoc", "detachedComment", "foreignDoc", "foreignDoc.childNodes.length - 1", "foreignDoc", "foreignDoc.childNodes.length - 1"], + ["foreignDoc", "detachedComment", "foreignDoc", "foreignDoc.childNodes.length", "foreignDoc", "foreignDoc.childNodes.length"], + ["foreignDoc", "detachedComment", "detachedComment", 0, "detachedComment", 5], + ["paras[0]", "xmlTextNode", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "xmlTextNode", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "xmlTextNode", "paras[0]", 1, "paras[0]", 1], + + // Stuff that throws exceptions + ["paras[0]", "paras[0]", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "testDiv", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "foreignDoc", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "document.doctype", "paras[0]", 0, "paras[0]", 1], +]; + + +function testRemoveChild(affectedNode, startContainer, startOffset, endContainer, endOffset) { + var expectedStart = [startContainer, startOffset]; + var expectedEnd = [endContainer, endOffset]; + + expectedStart = modifyForRemove(affectedNode, expectedStart); + expectedEnd = modifyForRemove(affectedNode, expectedEnd); + + // We don't test cases where the parent is wrong, so this should never + // throw an exception. + affectedNode.parentNode.removeChild(affectedNode); + + return expectedStart.concat(expectedEnd); +} + +var removeChildTests = [ + ["paras[0]", "paras[0]", 0, "paras[0]", 0], + ["paras[0]", "paras[0]", 0, "paras[0]", 1], + ["paras[0]", "paras[0]", 1, "paras[0]", 1], + ["paras[0]", "testDiv", 0, "testDiv", 0], + ["paras[0]", "testDiv", 0, "testDiv", 1], + ["paras[0]", "testDiv", 1, "testDiv", 1], + ["paras[0]", "testDiv", 0, "testDiv", 2], + ["paras[0]", "testDiv", 1, "testDiv", 2], + ["paras[0]", "testDiv", 2, "testDiv", 2], + + ["foreignDoc.documentElement", "foreignDoc", 0, "foreignDoc", "foreignDoc.childNodes.length"], +]; diff --git a/testing/web-platform/tests/dom/ranges/Range-selectNode.html b/testing/web-platform/tests/dom/ranges/Range-selectNode.html new file mode 100644 index 0000000000..fe9b1f7860 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-selectNode.html @@ -0,0 +1,99 @@ +<!doctype html> +<title>Range.selectNode() and .selectNodeContents() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +function testSelectNode(range, node) { + try { + range.collapsed; + } catch (e) { + // Range is detached + assert_throws_dom("INVALID_STATE_ERR", function () { + range.selectNode(node); + }, "selectNode() on a detached node must throw INVALID_STATE_ERR"); + assert_throws_dom("INVALID_STATE_ERR", function () { + range.selectNodeContents(node); + }, "selectNodeContents() on a detached node must throw INVALID_STATE_ERR"); + return; + } + + if (!node.parentNode) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { + range.selectNode(node); + }, "selectNode() on a node with no parent must throw INVALID_NODE_TYPE_ERR"); + } else { + var index = 0; + while (node.parentNode.childNodes[index] != node) { + index++; + } + + range.selectNode(node); + assert_equals(range.startContainer, node.parentNode, + "After selectNode(), startContainer must equal parent node"); + assert_equals(range.endContainer, node.parentNode, + "After selectNode(), endContainer must equal parent node"); + assert_equals(range.startOffset, index, + "After selectNode(), startOffset must be index of node in parent (" + index + ")"); + assert_equals(range.endOffset, index + 1, + "After selectNode(), endOffset must be one plus index of node in parent (" + (index + 1) + ")"); + } + + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function () { + range.selectNodeContents(node); + }, "selectNodeContents() on a doctype must throw INVALID_NODE_TYPE_ERR"); + } else { + range.selectNodeContents(node); + assert_equals(range.startContainer, node, + "After selectNodeContents(), startContainer must equal node"); + assert_equals(range.endContainer, node, + "After selectNodeContents(), endContainer must equal node"); + assert_equals(range.startOffset, 0, + "After selectNodeContents(), startOffset must equal 0"); + var len = nodeLength(node); + assert_equals(range.endOffset, len, + "After selectNodeContents(), endOffset must equal node length (" + len + ")"); + } +} + +var range = document.createRange(); +var foreignRange = foreignDoc.createRange(); +var xmlRange = xmlDoc.createRange(); +var detachedRange = document.createRange(); +detachedRange.detach(); +var tests = []; +function testTree(root, marker) { + if (root.nodeType == Node.ELEMENT_NODE && root.id == "log") { + // This is being modified during the tests, so let's not test it. + return; + } + tests.push([marker + ": " + root.nodeName.toLowerCase() + " node, current doc's range, type " + root.nodeType, range, root]); + tests.push([marker + ": " + root.nodeName.toLowerCase() + " node, foreign doc's range, type " + root.nodeType, foreignRange, root]); + tests.push([marker + ": " + root.nodeName.toLowerCase() + " node, XML doc's range, type " + root.nodeType, xmlRange, root]); + tests.push([marker + ": " + root.nodeName.toLowerCase() + " node, detached range, type " + root.nodeType, detachedRange, root]); + for (var i = 0; i < root.childNodes.length; i++) { + testTree(root.childNodes[i], marker + "[" + i + "]"); + } +} +testTree(document, "current doc"); +testTree(foreignDoc, "foreign doc"); +testTree(detachedDiv, "detached div in current doc"); + +var otherTests = ["xmlDoc", "xmlElement", "detachedTextNode", +"foreignTextNode", "xmlTextNode", "processingInstruction", "comment", +"foreignComment", "xmlComment", "docfrag", "foreignDocfrag", "xmlDocfrag"]; + +for (var i = 0; i < otherTests.length; i++) { + testTree(window[otherTests[i]], otherTests[i]); +} + +generate_tests(testSelectNode, tests); + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-set.html b/testing/web-platform/tests/dom/ranges/Range-set.html new file mode 100644 index 0000000000..694fc60749 --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-set.html @@ -0,0 +1,221 @@ +<!doctype html> +<title>Range setting tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> + +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +function testSetStart(range, node, offset) { + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { + range.setStart(node, offset); + }, "setStart() to a doctype must throw INVALID_NODE_TYPE_ERR"); + return; + } + + if (offset < 0 || offset > nodeLength(node)) { + assert_throws_dom("INDEX_SIZE_ERR", function() { + range.setStart(node, offset); + }, "setStart() to a too-large offset must throw INDEX_SIZE_ERR"); + return; + } + + var newRange = range.cloneRange(); + newRange.setStart(node, offset); + + assert_equals(newRange.startContainer, node, + "setStart() must change startContainer to the new node"); + assert_equals(newRange.startOffset, offset, + "setStart() must change startOffset to the new offset"); + + // FIXME: I'm assuming comparePoint() is correct, but the tests for that + // will depend on setStart()/setEnd(). + if (furthestAncestor(node) != furthestAncestor(range.startContainer) + || range.comparePoint(node, offset) > 0) { + assert_equals(newRange.endContainer, node, + "setStart(node, offset) where node is after current end or in different document must set the end node to node too"); + assert_equals(newRange.endOffset, offset, + "setStart(node, offset) where node is after current end or in different document must set the end offset to offset too"); + } else { + assert_equals(newRange.endContainer, range.endContainer, + "setStart() must not change the end node if the new start is before the old end"); + assert_equals(newRange.endOffset, range.endOffset, + "setStart() must not change the end offset if the new start is before the old end"); + } +} + +function testSetEnd(range, node, offset) { + if (node.nodeType == Node.DOCUMENT_TYPE_NODE) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function() { + range.setEnd(node, offset); + }, "setEnd() to a doctype must throw INVALID_NODE_TYPE_ERR"); + return; + } + + if (offset < 0 || offset > nodeLength(node)) { + assert_throws_dom("INDEX_SIZE_ERR", function() { + range.setEnd(node, offset); + }, "setEnd() to a too-large offset must throw INDEX_SIZE_ERR"); + return; + } + + var newRange = range.cloneRange(); + newRange.setEnd(node, offset); + + // FIXME: I'm assuming comparePoint() is correct, but the tests for that + // will depend on setStart()/setEnd(). + if (furthestAncestor(node) != furthestAncestor(range.startContainer) + || range.comparePoint(node, offset) < 0) { + assert_equals(newRange.startContainer, node, + "setEnd(node, offset) where node is before current start or in different document must set the end node to node too"); + assert_equals(newRange.startOffset, offset, + "setEnd(node, offset) where node is before current start or in different document must set the end offset to offset too"); + } else { + assert_equals(newRange.startContainer, range.startContainer, + "setEnd() must not change the start node if the new end is after the old start"); + assert_equals(newRange.startOffset, range.startOffset, + "setEnd() must not change the start offset if the new end is after the old start"); + } + + assert_equals(newRange.endContainer, node, + "setEnd() must change endContainer to the new node"); + assert_equals(newRange.endOffset, offset, + "setEnd() must change endOffset to the new offset"); +} + +function testSetStartBefore(range, node) { + var parent = node.parentNode; + if (parent === null) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function () { + range.setStartBefore(node); + }, "setStartBefore() to a node with null parent must throw INVALID_NODE_TYPE_ERR"); + return; + } + + var idx = 0; + while (node.parentNode.childNodes[idx] != node) { + idx++; + } + + testSetStart(range, node.parentNode, idx); +} + +function testSetStartAfter(range, node) { + var parent = node.parentNode; + if (parent === null) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function () { + range.setStartAfter(node); + }, "setStartAfter() to a node with null parent must throw INVALID_NODE_TYPE_ERR"); + return; + } + + var idx = 0; + while (node.parentNode.childNodes[idx] != node) { + idx++; + } + + testSetStart(range, node.parentNode, idx + 1); +} + +function testSetEndBefore(range, node) { + var parent = node.parentNode; + if (parent === null) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function () { + range.setEndBefore(node); + }, "setEndBefore() to a node with null parent must throw INVALID_NODE_TYPE_ERR"); + return; + } + + var idx = 0; + while (node.parentNode.childNodes[idx] != node) { + idx++; + } + + testSetEnd(range, node.parentNode, idx); +} + +function testSetEndAfter(range, node) { + var parent = node.parentNode; + if (parent === null) { + assert_throws_dom("INVALID_NODE_TYPE_ERR", function () { + range.setEndAfter(node); + }, "setEndAfter() to a node with null parent must throw INVALID_NODE_TYPE_ERR"); + return; + } + + var idx = 0; + while (node.parentNode.childNodes[idx] != node) { + idx++; + } + + testSetEnd(range, node.parentNode, idx + 1); +} + + +var startTests = []; +var endTests = []; +var startBeforeTests = []; +var startAfterTests = []; +var endBeforeTests = []; +var endAfterTests = []; + +// Don't want to eval() each point a bazillion times +var testPointsCached = testPoints.map(eval); +var testNodesCached = testNodesShort.map(eval); + +for (var i = 0; i < testRangesShort.length; i++) { + var endpoints = eval(testRangesShort[i]); + var range; + test(function() { + range = ownerDocument(endpoints[0]).createRange(); + range.setStart(endpoints[0], endpoints[1]); + range.setEnd(endpoints[2], endpoints[3]); + }, "Set up range " + i + " " + testRangesShort[i]); + + for (var j = 0; j < testPoints.length; j++) { + startTests.push(["setStart() with range " + i + " " + testRangesShort[i] + ", point " + j + " " + testPoints[j], + range, + testPointsCached[j][0], + testPointsCached[j][1] + ]); + endTests.push(["setEnd() with range " + i + " " + testRangesShort[i] + ", point " + j + " " + testPoints[j], + range, + testPointsCached[j][0], + testPointsCached[j][1] + ]); + } + + for (var j = 0; j < testNodesShort.length; j++) { + startBeforeTests.push(["setStartBefore() with range " + i + " " + testRangesShort[i] + ", node " + j + " " + testNodesShort[j], + range, + testNodesCached[j] + ]); + startAfterTests.push(["setStartAfter() with range " + i + " " + testRangesShort[i] + ", node " + j + " " + testNodesShort[j], + range, + testNodesCached[j] + ]); + endBeforeTests.push(["setEndBefore() with range " + i + " " + testRangesShort[i] + ", node " + j + " " + testNodesShort[j], + range, + testNodesCached[j] + ]); + endAfterTests.push(["setEndAfter() with range " + i + " " + testRangesShort[i] + ", node " + j + " " + testNodesShort[j], + range, + testNodesCached[j] + ]); + } +} + +generate_tests(testSetStart, startTests); +generate_tests(testSetEnd, endTests); +generate_tests(testSetStartBefore, startBeforeTests); +generate_tests(testSetStartAfter, startAfterTests); +generate_tests(testSetEndBefore, endBeforeTests); +generate_tests(testSetEndAfter, endAfterTests); + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-stringifier.html b/testing/web-platform/tests/dom/ranges/Range-stringifier.html new file mode 100644 index 0000000000..330c7421ea --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-stringifier.html @@ -0,0 +1,44 @@ +<!doctype html> +<meta charset="utf-8"> +<title>Range stringifier</title> +<link rel="author" title="KiChjang" href="mailto:kungfukeith11@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=test>Test div</div> +<div id=another>Another div</div> +<div id=last>Last div</div> +<div id=log></div> +<script> +test(function() { + var r = new Range(); + var testDiv = document.getElementById("test"); + test(function() { + r.selectNodeContents(testDiv); + assert_equals(r.collapsed, false); + assert_equals(r.toString(), testDiv.textContent); + }, "Node contents of a single div"); + + var textNode = testDiv.childNodes[0]; + test(function() { + r.setStart(textNode, 5); + r.setEnd(textNode, 7); + assert_equals(r.collapsed, false); + assert_equals(r.toString(), "di"); + }, "Text node with offsets"); + + var anotherDiv = document.getElementById("another"); + test(function() { + r.setStart(testDiv, 0); + r.setEnd(anotherDiv, 0); + assert_equals(r.toString(), "Test div\n"); + }, "Two nodes, each with a text node"); + + var lastDiv = document.getElementById("last"); + var lastText = lastDiv.childNodes[0]; + test(function() { + r.setStart(textNode, 5); + r.setEnd(lastText, 4); + assert_equals(r.toString(), "div\nAnother div\nLast"); + }, "Three nodes with start offset and end offset on text nodes"); +}); +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-surroundContents.html b/testing/web-platform/tests/dom/ranges/Range-surroundContents.html new file mode 100644 index 0000000000..c9d47fcbad --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-surroundContents.html @@ -0,0 +1,324 @@ +<!doctype html> +<meta charset=utf-8> +<title>Range.surroundContents() tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<p>To debug test failures, add a query parameter "subtest" with the test id (like +"?subtest=5,16"). Only that test will be run. Then you can look at the resulting +iframes in the DOM. +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +testDiv.parentNode.removeChild(testDiv); + +function mySurroundContents(range, newParent) { + try { + // "If a non-Text node is partially contained in the context object, + // throw a "InvalidStateError" exception and terminate these steps." + var node = range.commonAncestorContainer; + var stop = nextNodeDescendants(node); + for (; node != stop; node = nextNode(node)) { + if (node.nodeType != Node.TEXT_NODE + && isPartiallyContained(node, range)) { + return "INVALID_STATE_ERR"; + } + } + + // "If newParent is a Document, DocumentType, or DocumentFragment node, + // throw an "InvalidNodeTypeError" exception and terminate these + // steps." + if (newParent.nodeType == Node.DOCUMENT_NODE + || newParent.nodeType == Node.DOCUMENT_TYPE_NODE + || newParent.nodeType == Node.DOCUMENT_FRAGMENT_NODE) { + return "INVALID_NODE_TYPE_ERR"; + } + + // "Call extractContents() on the context object, and let fragment be + // the result." + var fragment = myExtractContents(range); + if (typeof fragment == "string") { + return fragment; + } + + // "While newParent has children, remove its first child." + while (newParent.childNodes.length) { + newParent.removeChild(newParent.firstChild); + } + + // "Call insertNode(newParent) on the context object." + var ret = myInsertNode(range, newParent); + if (typeof ret == "string") { + return ret; + } + + // "Call appendChild(fragment) on newParent." + newParent.appendChild(fragment); + + // "Call selectNode(newParent) on the context object." + // + // We just reimplement this in-place. + if (!newParent.parentNode) { + return "INVALID_NODE_TYPE_ERR"; + } + var index = indexOf(newParent); + range.setStart(newParent.parentNode, index); + range.setEnd(newParent.parentNode, index + 1); + } catch (e) { + return getDomExceptionName(e); + } +} + +function restoreIframe(iframe, i, j) { + // Most of this function is designed to work around the fact that Opera + // doesn't let you add a doctype to a document that no longer has one, in + // any way I can figure out. I eventually compromised on something that + // will still let Opera pass most tests that don't actually involve + // doctypes. + while (iframe.contentDocument.firstChild + && iframe.contentDocument.firstChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.firstChild); + } + + while (iframe.contentDocument.lastChild + && iframe.contentDocument.lastChild.nodeType != Node.DOCUMENT_TYPE_NODE) { + iframe.contentDocument.removeChild(iframe.contentDocument.lastChild); + } + + if (!iframe.contentDocument.firstChild) { + // This will throw an exception in Opera if we reach here, which is why + // I try to avoid it. It will never happen in a browser that obeys the + // spec, so it's really just insurance. I don't think it actually gets + // hit by anything. + iframe.contentDocument.appendChild(iframe.contentDocument.implementation.createDocumentType("html", "", "")); + } + iframe.contentDocument.appendChild(referenceDoc.documentElement.cloneNode(true)); + iframe.contentWindow.setupRangeTests(); + iframe.contentWindow.testRangeInput = testRangesShort[i]; + iframe.contentWindow.testNodeInput = testNodesShort[j]; + iframe.contentWindow.run(); +} + +function testSurroundContents(i, j) { + var actualRange; + var expectedRange; + var actualNode; + var expectedNode; + var actualRoots = []; + var expectedRoots = []; + + domTests[i][j].step(function() { + restoreIframe(actualIframe, i, j); + restoreIframe(expectedIframe, i, j); + + actualRange = actualIframe.contentWindow.testRange; + expectedRange = expectedIframe.contentWindow.testRange; + actualNode = actualIframe.contentWindow.testNode; + expectedNode = expectedIframe.contentWindow.testNode; + + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual surroundContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated surroundContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_not_equals(actualRange, null, + "Range produced in actual iframe was null"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + assert_not_equals(expectedRange, null, + "Range produced in expected iframe was null"); + assert_equals(typeof actualNode, "object", + "typeof Node produced in actual iframe"); + assert_not_equals(actualNode, null, + "Node produced in actual iframe was null"); + assert_equals(typeof expectedNode, "object", + "typeof Node produced in expected iframe"); + assert_not_equals(expectedNode, null, + "Node produced in expected iframe was null"); + + // We want to test that the trees containing the ranges are equal, and + // also the trees containing the moved nodes. These might not be the + // same, if we're inserting a node from a detached tree or a different + // document. + actualRoots.push(furthestAncestor(actualRange.startContainer)); + expectedRoots.push(furthestAncestor(expectedRange.startContainer)); + + if (furthestAncestor(actualNode) != actualRoots[0]) { + actualRoots.push(furthestAncestor(actualNode)); + } + if (furthestAncestor(expectedNode) != expectedRoots[0]) { + expectedRoots.push(furthestAncestor(expectedNode)); + } + + assert_equals(actualRoots.length, expectedRoots.length, + "Either the actual node and actual range are in the same tree but the expected are in different trees, or vice versa"); + + // This doctype stuff is to work around the fact that Opera 11.00 will + // move around doctypes within a document, even to totally invalid + // positions, but it won't allow a new doctype to be added to a + // document in any way I can figure out. So if we try moving a doctype + // to some invalid place, in Opera it will actually succeed, and then + // restoreIframe() will remove the doctype along with the root element, + // and then nothing can re-add the doctype. So instead, we catch it + // during the test itself and move it back to the right place while we + // still can. + // + // I spent *way* too much time debugging and working around this bug. + var actualDoctype = actualIframe.contentDocument.doctype; + var expectedDoctype = expectedIframe.contentDocument.doctype; + + var result; + try { + result = mySurroundContents(expectedRange, expectedNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + throw e; + } + if (typeof result == "string") { + assert_throws_dom(result, actualIframe.contentWindow.DOMException, function() { + try { + actualRange.surroundContents(actualNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + if (actualDoctype != actualIframe.contentDocument.firstChild) { + actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild); + } + throw e; + } + }, "A " + result + " must be thrown in this case"); + // Don't return, we still need to test DOM equality + } else { + try { + actualRange.surroundContents(actualNode); + } catch (e) { + if (expectedDoctype != expectedIframe.contentDocument.firstChild) { + expectedIframe.contentDocument.insertBefore(expectedDoctype, expectedIframe.contentDocument.firstChild); + } + if (actualDoctype != actualIframe.contentDocument.firstChild) { + actualIframe.contentDocument.insertBefore(actualDoctype, actualIframe.contentDocument.firstChild); + } + throw e; + } + } + + for (var k = 0; k < actualRoots.length; k++) { + assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root"); + } + }); + domTests[i][j].done(); + + positionTests[i][j].step(function() { + assert_equals(actualIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for actual surroundContents()"); + assert_equals(expectedIframe.contentWindow.unexpectedException, null, + "Unexpected exception thrown when setting up Range for simulated surroundContents()"); + assert_equals(typeof actualRange, "object", + "typeof Range produced in actual iframe"); + assert_not_equals(actualRange, null, + "Range produced in actual iframe was null"); + assert_equals(typeof expectedRange, "object", + "typeof Range produced in expected iframe"); + assert_not_equals(expectedRange, null, + "Range produced in expected iframe was null"); + assert_equals(typeof actualNode, "object", + "typeof Node produced in actual iframe"); + assert_not_equals(actualNode, null, + "Node produced in actual iframe was null"); + assert_equals(typeof expectedNode, "object", + "typeof Node produced in expected iframe"); + assert_not_equals(expectedNode, null, + "Node produced in expected iframe was null"); + + for (var k = 0; k < actualRoots.length; k++) { + assertNodesEqual(actualRoots[k], expectedRoots[k], k ? "moved node's tree root" : "range's tree root"); + } + + assert_equals(actualRange.startOffset, expectedRange.startOffset, + "Unexpected startOffset after surroundContents()"); + assert_equals(actualRange.endOffset, expectedRange.endOffset, + "Unexpected endOffset after surroundContents()"); + // How do we decide that the two nodes are equal, since they're in + // different trees? Since the DOMs are the same, it's enough to check + // that the index in the parent is the same all the way up the tree. + // But we can first cheat by just checking they're actually equal. + assert_true(actualRange.startContainer.isEqualNode(expectedRange.startContainer), + "Unexpected startContainer after surroundContents(), expected " + + expectedRange.startContainer.nodeName.toLowerCase() + " but got " + + actualRange.startContainer.nodeName.toLowerCase()); + var currentActual = actualRange.startContainer; + var currentExpected = expectedRange.startContainer; + var actual = ""; + var expected = ""; + while (currentActual && currentExpected) { + actual = indexOf(currentActual) + "-" + actual; + expected = indexOf(currentExpected) + "-" + expected; + + currentActual = currentActual.parentNode; + currentExpected = currentExpected.parentNode; + } + actual = actual.substr(0, actual.length - 1); + expected = expected.substr(0, expected.length - 1); + assert_equals(actual, expected, + "startContainer superficially looks right but is actually the wrong node if you trace back its index in all its ancestors (I'm surprised this actually happened"); + }); + positionTests[i][j].done(); +} + +var iStart = 0; +var iStop = testRangesShort.length; +var jStart = 0; +var jStop = testNodesShort.length; + +if (/subtest=[0-9]+,[0-9]+/.test(location.search)) { + var matches = /subtest=([0-9]+),([0-9]+)/.exec(location.search); + iStart = Number(matches[1]); + iStop = Number(matches[1]) + 1; + jStart = Number(matches[2]) + 0; + jStop = Number(matches[2]) + 1; +} + +var domTests = []; +var positionTests = []; +for (var i = iStart; i < iStop; i++) { + domTests[i] = []; + positionTests[i] = []; + for (var j = jStart; j < jStop; j++) { + domTests[i][j] = async_test(i + "," + j + ": resulting DOM for range " + testRangesShort[i] + ", node " + testNodesShort[j]); + positionTests[i][j] = async_test(i + "," + j + ": resulting range position for range " + testRangesShort[i] + ", node " + testNodesShort[j]); + } +} + +var actualIframe = document.createElement("iframe"); +actualIframe.style.display = "none"; +actualIframe.id = "actual"; +document.body.appendChild(actualIframe); + +var expectedIframe = document.createElement("iframe"); +expectedIframe.style.display = "none"; +expectedIframe.id = "expected"; +document.body.appendChild(expectedIframe); + +var referenceDoc = document.implementation.createHTMLDocument(""); +referenceDoc.removeChild(referenceDoc.documentElement); + +actualIframe.onload = function() { + expectedIframe.onload = function() { + for (var i = iStart; i < iStop; i++) { + for (var j = jStart; j < jStop; j++) { + testSurroundContents(i, j); + } + } + } + expectedIframe.src = "Range-test-iframe.html"; + referenceDoc.appendChild(actualIframe.contentDocument.documentElement.cloneNode(true)); +} +actualIframe.src = "Range-test-iframe.html"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/Range-test-iframe.html b/testing/web-platform/tests/dom/ranges/Range-test-iframe.html new file mode 100644 index 0000000000..f354ff758f --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/Range-test-iframe.html @@ -0,0 +1,56 @@ +<!doctype html> +<title>Range test iframe</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<body onload=run()> +<script src=../common.js></script> +<script> +"use strict"; + +// This script only exists because we want to evaluate the range endpoints +// in each iframe using that iframe's local variables set up by common.js. It +// just creates the range and does nothing else. The data is returned via +// window.testRange, and if an exception is thrown, it's put in +// window.unexpectedException. +window.unexpectedException = null; + +function run() { + try { + window.unexpectedException = null; + + if (typeof window.testNodeInput != "undefined") { + window.testNode = eval(window.testNodeInput); + } + + var rangeEndpoints; + if (typeof window.testRangeInput == "undefined") { + // Use the hash (old way of doing things, bad because it requires + // navigation) + if (location.hash == "") { + return; + } + rangeEndpoints = eval(location.hash.substr(1)); + } else { + // Get the variable directly off the window, faster and can be done + // synchronously + rangeEndpoints = eval(window.testRangeInput); + } + + var range; + if (rangeEndpoints == "detached") { + range = document.createRange(); + range.detach(); + } else { + range = ownerDocument(rangeEndpoints[0]).createRange(); + range.setStart(rangeEndpoints[0], rangeEndpoints[1]); + range.setEnd(rangeEndpoints[2], rangeEndpoints[3]); + } + + window.testRange = range; + } catch(e) { + window.unexpectedException = e; + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/ranges/StaticRange-constructor.html b/testing/web-platform/tests/dom/ranges/StaticRange-constructor.html new file mode 100644 index 0000000000..6aae93f49b --- /dev/null +++ b/testing/web-platform/tests/dom/ranges/StaticRange-constructor.html @@ -0,0 +1,200 @@ +<!doctype html> +<title>StaticRange constructor test</title> +<link rel='author' title='Sanket Joshi' href='mailto:sajos@microsoft.com'> +<div id='log'></div> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<div id='testDiv'>abc<span>def</span>ghi</div> +<script> +'use strict'; + +const testDiv = document.getElementById('testDiv'); +const testTextNode = testDiv.firstChild; +const testPINode = document.createProcessingInstruction('foo', 'abc'); +const testCommentNode = document.createComment('abc'); +document.body.append(testPINode, testCommentNode); + +test(function() { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 1, endContainer: testDiv, endOffset: 2}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDiv, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Element container'); + +test(function() { + const staticRange = new StaticRange({startContainer: testTextNode, startOffset: 1, endContainer: testTextNode, endOffset: 2}); + assert_equals(staticRange.startContainer, testTextNode, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testTextNode, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Text container'); + +test(function() { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endContainer: testTextNode, endOffset: 1}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testTextNode, 'valid endContainer'); + assert_equals(staticRange.endOffset, 1, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Element startContainer and Text endContainer'); + +test(function() { + const staticRange = new StaticRange({startContainer: testTextNode, startOffset: 0, endContainer: testDiv, endOffset: 3}); + assert_equals(staticRange.startContainer, testTextNode, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDiv, 'valid endContainer'); + assert_equals(staticRange.endOffset, 3, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Text startContainer and Element endContainer'); + +test(function() { + const staticRange = new StaticRange({startContainer: testPINode, startOffset: 1, endContainer: testPINode, endOffset: 2}); + assert_equals(staticRange.startContainer, testPINode, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testPINode, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with ProcessingInstruction container'); + +test(function() { + const staticRange = new StaticRange({startContainer: testCommentNode, startOffset: 1, endContainer: testCommentNode, endOffset: 2}); + assert_equals(staticRange.startContainer, testCommentNode, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testCommentNode, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Comment container'); + +test(function() { + const xmlDoc = new DOMParser().parseFromString('<xml></xml>', 'application/xml'); + const testCDATASection = xmlDoc.createCDATASection('abc'); + const staticRange = new StaticRange({startContainer: testCDATASection, startOffset: 1, endContainer: testCDATASection, endOffset: 2}); + assert_equals(staticRange.startContainer, testCDATASection, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testCDATASection, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with CDATASection container'); + +test(function() { + const staticRange = new StaticRange({startContainer: document, startOffset: 0, endContainer: document, endOffset: 1}); + assert_equals(staticRange.startContainer, document, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, document, 'valid endContainer'); + assert_equals(staticRange.endOffset, 1, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with Document container'); + +test(function() { + const testDocFrag = document.createDocumentFragment(); + testDocFrag.append('a','b','c'); + const staticRange = new StaticRange({startContainer: testDocFrag, startOffset: 0, endContainer: testDocFrag, endOffset: 1}); + assert_equals(staticRange.startContainer, testDocFrag, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDocFrag, 'valid endContainer'); + assert_equals(staticRange.endOffset, 1, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with DocumentFragment container'); + +test(function() { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endContainer: testDiv, endOffset: 0}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDiv, 'valid endContainer'); + assert_equals(staticRange.endOffset, 0, 'valid endOffset'); + assert_true(staticRange.collapsed, 'collapsed'); +}, 'Construct collapsed static range'); + +test(function() { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 1, endContainer: document.body, endOffset: 0}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, document.body, 'valid endContainer'); + assert_equals(staticRange.endOffset, 0, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct inverted static range'); + +test(function() { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endContainer: testDiv, endOffset: 15}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDiv, 'valid endContainer'); + assert_equals(staticRange.endOffset, 15, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with offset greater than length'); + +test(function() { + const testNode = document.createTextNode('abc'); + const staticRange = new StaticRange({startContainer: testNode, startOffset: 1, endContainer: testNode, endOffset: 2}); + assert_equals(staticRange.startContainer, testNode, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testNode, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with standalone Node container'); + +test(function() { + const testRoot = document.createElement('div'); + testRoot.append('a','b'); + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 1, endContainer: testRoot, endOffset: 2}); + assert_equals(staticRange.startContainer, testDiv, 'valid startContainer'); + assert_equals(staticRange.startOffset, 1, 'valid startOffset'); + assert_equals(staticRange.endContainer, testRoot, 'valid endContainer'); + assert_equals(staticRange.endOffset, 2, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with endpoints in disconnected trees'); + +test(function() { + const testDocNode = document.implementation.createDocument('about:blank', 'html', null); + const staticRange = new StaticRange({startContainer: document, startOffset: 0, endContainer: testDocNode.documentElement, endOffset: 0}); + assert_equals(staticRange.startContainer, document, 'valid startContainer'); + assert_equals(staticRange.startOffset, 0, 'valid startOffset'); + assert_equals(staticRange.endContainer, testDocNode.documentElement, 'valid endContainer'); + assert_equals(staticRange.endOffset, 0, 'valid endOffset'); + assert_false(staticRange.collapsed, 'not collapsed'); +}, 'Construct static range with endpoints in disconnected documents'); + +test(function() { + assert_throws_dom('INVALID_NODE_TYPE_ERR', function() { + const staticRange = new StaticRange({startContainer: document.doctype, startOffset: 0, endContainer: document.doctype, endOffset: 0}); + }, 'throw a InvalidNodeTypeError when a DocumentType is passed as a startContainer or endContainer'); + + assert_throws_dom('INVALID_NODE_TYPE_ERR', function() { + const testAttrNode = testDiv.getAttributeNode('id'); + const staticRange = new StaticRange({startContainer: testAttrNode, startOffset: 0, endContainer: testAttrNode, endOffset: 0}); + }, 'throw a InvalidNodeTypeError when a Attr is passed as a startContainer or endContainer'); +}, 'Throw on DocumentType or Attr container'); + +test(function () { + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange(); + }, 'throw a TypeError when no argument is passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startOffset: 0, endContainer: testDiv, endOffset: 0}); + }, 'throw a TypeError when a startContainer is not passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startContainer: testDiv, endContainer: testDiv, endOffset: 0}); + }, 'throw a TypeError when a startOffset is not passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endOffset: 0}); + }, 'throw a TypeError when an endContainer is not passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endContainer: testDiv}); + }, 'throw a TypeError when an endOffset is not passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startContainer: null, startOffset: 0, endContainer: testDiv, endOffset: 0}); + }, 'throw a TypeError when a null startContainer is passed'); + + assert_throws_js(TypeError, function () { + const staticRange = new StaticRange({startContainer: testDiv, startOffset: 0, endContainer: null, endOffset: 0}); + }, 'throw a TypeError when a null endContainer is passed'); +}, 'Throw on missing or invalid arguments'); +</script> diff --git a/testing/web-platform/tests/dom/slot-recalc-ref.html b/testing/web-platform/tests/dom/slot-recalc-ref.html new file mode 100644 index 0000000000..521eedb42a --- /dev/null +++ b/testing/web-platform/tests/dom/slot-recalc-ref.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<div> + <p>there should be more text below this</p> + <p>PASS if this text is visible</p> +</div> diff --git a/testing/web-platform/tests/dom/slot-recalc.html b/testing/web-platform/tests/dom/slot-recalc.html new file mode 100644 index 0000000000..5124336ad2 --- /dev/null +++ b/testing/web-platform/tests/dom/slot-recalc.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" title="Joey Arhar" href="mailto:jarhar@chromium.org"> +<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1184357"> + +<link rel="match" href="/dom/slot-recalc-ref.html"> + +<body> +<script> +const host = document.createElement('div'); +document.body.appendChild(host); +const root = host.attachShadow({mode: 'open'}); + +const slot = document.createElement('slot'); +slot.innerHTML = `<p>there should be more text below this</p>`; +root.appendChild(slot); + +onload = () => { + const shouldBeVisible = document.createElement('p'); + shouldBeVisible.textContent = 'PASS if this text is visible'; + slot.appendChild(shouldBeVisible); +}; +</script> diff --git a/testing/web-platform/tests/dom/svg-insert-crash.html b/testing/web-platform/tests/dom/svg-insert-crash.html new file mode 100644 index 0000000000..80eec1fba7 --- /dev/null +++ b/testing/web-platform/tests/dom/svg-insert-crash.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<link rel="author" href="mailto:masonf@chromium.org"> +<link rel="help" href="https://crbug.com/1029262"> +<meta name="assert" content="The renderer should not crash."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<svg> + <!-- Note that the SVG in the data URL below is intentionally malformed: --> + <feImage xlink:href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect"/> +</svg> + +<script> +async_test(t => { + window.onload = t.step_func_done(); +}, 'The renderer should not crash.'); +</script> diff --git a/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html b/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html new file mode 100644 index 0000000000..1ce4736cc6 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/NodeFilter-constants.html @@ -0,0 +1,34 @@ +<!doctype html> +<title>NodeFilter constants</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../constants.js"></script> +<div id="log"></div> +<script> +var objects; +setup(function() { + objects = [ + [NodeFilter, "NodeFilter interface object"], + ] +}) +testConstants(objects, [ + ["FILTER_ACCEPT", 1], + ["FILTER_REJECT", 2], + ["FILTER_SKIP", 3] +], "acceptNode") +testConstants(objects, [ + ["SHOW_ALL", 0xFFFFFFFF], + ["SHOW_ELEMENT", 0x1], + ["SHOW_ATTRIBUTE", 0x2], + ["SHOW_TEXT", 0x4], + ["SHOW_CDATA_SECTION", 0x8], + ["SHOW_ENTITY_REFERENCE", 0x10], + ["SHOW_ENTITY", 0x20], + ["SHOW_PROCESSING_INSTRUCTION", 0x40], + ["SHOW_COMMENT", 0x80], + ["SHOW_DOCUMENT", 0x100], + ["SHOW_DOCUMENT_TYPE", 0x200], + ["SHOW_DOCUMENT_FRAGMENT", 0x400], + ["SHOW_NOTATION", 0x800] +], "whatToShow") +</script> diff --git a/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html b/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html new file mode 100644 index 0000000000..b5fc69541a --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/NodeIterator-removal.html @@ -0,0 +1,100 @@ +<!doctype html> +<title>NodeIterator removal tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +for (var i = 0; i < testNodes.length; i++) { + var node = eval(testNodes[i]); + if (!node.parentNode) { + // Nothing to test + continue; + } + test(function() { + var iters = []; + var descs = []; + var expectedReferenceNodes = []; + var expectedPointers = []; + + for (var j = 0; j < testNodes.length; j++) { + var root = eval(testNodes[j]); + // Add all distinct iterators with this root, calling nextNode() + // repeatedly until it winds up with the same iterator. + for (var k = 0; ; k++) { + var iter = document.createNodeIterator(root); + for (var l = 0; l < k; l++) { + iter.nextNode(); + } + if (k && iter.referenceNode == iters[iters.length - 1].referenceNode + && iter.pointerBeforeReferenceNode + == iters[iters.length - 1].pointerBeforeReferenceNode) { + break; + } else { + iters.push(iter); + descs.push("document.createNodeIterator(" + testNodes[j] + + ") advanced " + k + " times"); + expectedReferenceNodes.push(iter.referenceNode); + expectedPointers.push(iter.pointerBeforeReferenceNode); + + var idx = iters.length - 1; + + // "If the node is root or is not an inclusive ancestor of the + // referenceNode attribute value, terminate these steps." + // + // We also have to rule out the case where node is an ancestor of + // root, which is implicitly handled by the spec since such a node + // was not part of the iterator collection to start with. + if (isInclusiveAncestor(node, root) + || !isInclusiveAncestor(node, iter.referenceNode)) { + continue; + } + + // "If the pointerBeforeReferenceNode attribute value is false, set + // the referenceNode attribute to the first node preceding the node + // that is being removed, and terminate these steps." + if (!iter.pointerBeforeReferenceNode) { + expectedReferenceNodes[idx] = previousNode(node); + continue; + } + + // "If there is a node following the last inclusive descendant of the + // node that is being removed, set the referenceNode attribute to the + // first such node, and terminate these steps." + var next = nextNodeDescendants(node); + if (next) { + expectedReferenceNodes[idx] = next; + continue; + } + + // "Set the referenceNode attribute to the first node preceding the + // node that is being removed and set the pointerBeforeReferenceNode + // attribute to false." + expectedReferenceNodes[idx] = previousNode(node); + expectedPointers[idx] = false; + } + } + } + + var oldParent = node.parentNode; + var oldSibling = node.nextSibling; + oldParent.removeChild(node); + + for (var j = 0; j < iters.length; j++) { + var iter = iters[j]; + assert_equals(iter.referenceNode, expectedReferenceNodes[j], + ".referenceNode of " + descs[j]); + assert_equals(iter.pointerBeforeReferenceNode, expectedPointers[j], + ".pointerBeforeReferenceNode of " + descs[j]); + } + + oldParent.insertBefore(node, oldSibling); + }, "Test removing node " + testNodes[i]); +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/traversal/NodeIterator.html b/testing/web-platform/tests/dom/traversal/NodeIterator.html new file mode 100644 index 0000000000..fb81676cc5 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/NodeIterator.html @@ -0,0 +1,215 @@ +<!doctype html> +<title>NodeIterator tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +function check_iter(iter, root, whatToShowValue) { + whatToShowValue = whatToShowValue === undefined ? 0xFFFFFFFF : whatToShowValue; + + assert_equals(iter.toString(), '[object NodeIterator]', 'toString'); + assert_equals(iter.root, root, 'root'); + assert_equals(iter.whatToShow, whatToShowValue, 'whatToShow'); + assert_equals(iter.filter, null, 'filter'); + assert_equals(iter.referenceNode, root, 'referenceNode'); + assert_equals(iter.pointerBeforeReferenceNode, true, 'pointerBeforeReferenceNode'); + assert_readonly(iter, 'root'); + assert_readonly(iter, 'whatToShow'); + assert_readonly(iter, 'filter'); + assert_readonly(iter, 'referenceNode'); + assert_readonly(iter, 'pointerBeforeReferenceNode'); +} + +test(function() { + var iter = document.createNodeIterator(document); + iter.detach(); + iter.detach(); +}, "detach() should be a no-op"); + +test(function() { + var iter = document.createNodeIterator(document); + check_iter(iter, document); +}, "createNodeIterator() parameter defaults"); + +test(function() { + var iter = document.createNodeIterator(document, null, null); + check_iter(iter, document, 0); +}, "createNodeIterator() with null as arguments"); + +test(function() { + var iter = document.createNodeIterator(document, undefined, undefined); + check_iter(iter, document); +}, "createNodeIterator() with undefined as arguments"); + +test(function() { + var err = {name: "failed"}; + var iter = document.createNodeIterator(document, NodeFilter.SHOW_ALL, + function() { throw err; }); + assert_throws_exactly(err, function() { iter.nextNode() }); +}, "Propagate exception from filter function"); + +test(function() { + var depth = 0; + var iter = document.createNodeIterator(document, NodeFilter.SHOW_ALL, + function() { + if (iter.referenceNode != document && depth == 0) { + depth++; + iter.nextNode(); + } + return NodeFilter.FILTER_ACCEPT; + }); + iter.nextNode(); + iter.nextNode(); + assert_throws_dom("InvalidStateError", function() { iter.nextNode() }); + depth--; + assert_throws_dom("InvalidStateError", function() { iter.previousNode() }); +}, "Recursive filters need to throw"); + +function testIterator(root, whatToShow, filter) { + var iter = document.createNodeIterator(root, whatToShow, filter); + + assert_equals(iter.root, root, ".root"); + assert_equals(iter.referenceNode, root, "Initial .referenceNode"); + assert_equals(iter.pointerBeforeReferenceNode, true, + ".pointerBeforeReferenceNode"); + assert_equals(iter.whatToShow, whatToShow, ".whatToShow"); + assert_equals(iter.filter, filter, ".filter"); + + var expectedReferenceNode = root; + var expectedBeforeNode = true; + // "Let node be the value of the referenceNode attribute." + var node = root; + // "Let before node be the value of the pointerBeforeReferenceNode + // attribute." + var beforeNode = true; + var i = 1; + // Each loop iteration runs nextNode() once. + while (node) { + do { + if (!beforeNode) { + // "If before node is false, let node be the first node following node + // in the iterator collection. If there is no such node return null." + node = nextNode(node); + if (!isInclusiveDescendant(node, root)) { + node = null; + break; + } + } else { + // "If before node is true, set it to false." + beforeNode = false; + } + // "Filter node and let result be the return value. + // + // "If result is FILTER_ACCEPT, go to the next step in the overall set of + // steps. + // + // "Otherwise, run these substeps again." + if (!((1 << (node.nodeType - 1)) & whatToShow) + || (filter && filter(node) != NodeFilter.FILTER_ACCEPT)) { + continue; + } + + // "Set the referenceNode attribute to node, set the + // pointerBeforeReferenceNode attribute to before node, and return node." + expectedReferenceNode = node; + expectedBeforeNode = beforeNode; + + break; + } while (true); + + assert_equals(iter.nextNode(), node, ".nextNode() " + i + " time(s)"); + assert_equals(iter.referenceNode, expectedReferenceNode, + ".referenceNode after nextNode() " + i + " time(s)"); + assert_equals(iter.pointerBeforeReferenceNode, expectedBeforeNode, + ".pointerBeforeReferenceNode after nextNode() " + i + " time(s)"); + + i++; + } + + // Same but for previousNode() (mostly copy-pasted, oh well) + var iter = document.createNodeIterator(root, whatToShow, filter); + + var expectedReferenceNode = root; + var expectedBeforeNode = true; + // "Let node be the value of the referenceNode attribute." + var node = root; + // "Let before node be the value of the pointerBeforeReferenceNode + // attribute." + var beforeNode = true; + var i = 1; + // Each loop iteration runs previousNode() once. + while (node) { + do { + if (beforeNode) { + // "If before node is true, let node be the first node preceding node + // in the iterator collection. If there is no such node return null." + node = previousNode(node); + if (!isInclusiveDescendant(node, root)) { + node = null; + break; + } + } else { + // "If before node is false, set it to true." + beforeNode = true; + } + // "Filter node and let result be the return value. + // + // "If result is FILTER_ACCEPT, go to the next step in the overall set of + // steps. + // + // "Otherwise, run these substeps again." + if (!((1 << (node.nodeType - 1)) & whatToShow) + || (filter && filter(node) != NodeFilter.FILTER_ACCEPT)) { + continue; + } + + // "Set the referenceNode attribute to node, set the + // pointerBeforeReferenceNode attribute to before node, and return node." + expectedReferenceNode = node; + expectedBeforeNode = beforeNode; + + break; + } while (true); + + assert_equals(iter.previousNode(), node, ".previousNode() " + i + " time(s)"); + assert_equals(iter.referenceNode, expectedReferenceNode, + ".referenceNode after previousNode() " + i + " time(s)"); + assert_equals(iter.pointerBeforeReferenceNode, expectedBeforeNode, + ".pointerBeforeReferenceNode after previousNode() " + i + " time(s)"); + + i++; + } +} + +var whatToShows = [ + "0", + "0xFFFFFFFF", + "NodeFilter.SHOW_ELEMENT", + "NodeFilter.SHOW_ATTRIBUTE", + "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT", +]; + +var callbacks = [ + "null", + "(function(node) { return true })", + "(function(node) { return false })", + "(function(node) { return node.nodeName[0] == '#' })", +]; + +for (var i = 0; i < testNodes.length; i++) { + for (var j = 0; j < whatToShows.length; j++) { + for (var k = 0; k < callbacks.length; k++) { + test(() => { + testIterator(eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k])); + }, "document.createNodeIterator(" + testNodes[i] + ", " + whatToShows[j] + ", " + callbacks[k] + ")"); + } + } +} + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html new file mode 100644 index 0000000000..f8e71bcdf5 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context.html @@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>TreeWalker: NodeFilter from detached iframe doesn't get called</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<div></div> + +<script> +const t = async_test(); + +const iframe = document.createElement("iframe"); +iframe.src = "support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html"; +iframe.onload = t.step_func_done(() => { + const nodeIterator = iframe.contentWindow.createNodeIterator(); + iframe.remove(); + + assert_equals(iframe.contentWindow, null); + + let errorWasThrown = false; + try { nodeIterator.nextNode(); } + catch { errorWasThrown = true; } + + assert_true(errorWasThrown); + assert_false(nodeIterator.dummyFilterCalled); +}); + +document.body.append(iframe); +</script> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html new file mode 100644 index 0000000000..da91cf6cb2 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter-cross-realm.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>TreeWalker: cross-realm NodeFilter throws TypeError of its associated Realm</title> +<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe name="nodeFilterGlobalObject" src="support/empty-document.html"></iframe> + +<div id="treeWalkerRoot"> + <div class="firstChild"></div> +</div> + +<script> +test_onload(() => { + const nodeFilter = new nodeFilterGlobalObject.Object; + + const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter); + assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); }); +}, "NodeFilter is cross-realm plain object without 'acceptNode' property"); + +test_onload(() => { + const nodeFilter = new nodeFilterGlobalObject.Object; + nodeFilter.acceptNode = {}; + + const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter); + assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); }); +}, "NodeFilter is cross-realm plain object with non-callable 'acceptNode' property"); + +test_onload(() => { + const { proxy, revoke } = Proxy.revocable(() => {}, {}); + revoke(); + + const nodeFilter = new nodeFilterGlobalObject.Object; + nodeFilter.acceptNode = proxy; + + const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, nodeFilter); + assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); }); +}, "NodeFilter is cross-realm plain object with revoked Proxy as 'acceptNode' property"); + +test_onload(() => { + const { proxy, revoke } = nodeFilterGlobalObject.Proxy.revocable({}, {}); + revoke(); + + const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, proxy); + assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); }); +}, "NodeFilter is cross-realm non-callable revoked Proxy"); + +test_onload(() => { + const { proxy, revoke } = nodeFilterGlobalObject.Proxy.revocable(() => {}, {}); + revoke(); + + const walker = document.createTreeWalker(treeWalkerRoot, NodeFilter.SHOW_ELEMENT, proxy); + assert_throws_js(nodeFilterGlobalObject.TypeError, () => { walker.firstChild(); }); +}, "NodeFilter is cross-realm callable revoked Proxy"); + +function test_onload(fn, desc) { + async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc); +} +</script> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html new file mode 100644 index 0000000000..282dc9d142 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-acceptNode-filter.html @@ -0,0 +1,195 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/acceptNode-filter.js +--> +<head> +<title>TreeWalker: acceptNode-filter</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<link rel="help" href="https://dom.spec.whatwg.org/#callbackdef-nodefilter"> +<div id=log></div> +</head> +<body> +<p>Test JS objects as NodeFilters</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + //testElement.innerHTML='<div id="A1"><div id="B1"></div><div id="B2"></div></div>'; + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); + a1.id = "A1"; + var b1 = document.createElement("div"); + b1.id = "B1"; + var b2 = document.createElement("div"); + b2.id = "B2"; + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2); +}); + +test(function() +{ + function filter(node) + { + if (node.id == "B1") + return NodeFilter.FILTER_SKIP; + return NodeFilter.FILTER_ACCEPT; + } + + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.currentNode, { type: Element, id: 'B2' }); +}, 'Testing with raw function filter'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, { + acceptNode : function(node) { + if (node.id == "B1") + return NodeFilter.FILTER_SKIP; + return NodeFilter.FILTER_ACCEPT; + } + }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.currentNode, { type: Element, id: 'B2' }); +}, 'Testing with object filter'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, null); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B1' }); + assert_node(walker.currentNode, { type: Element, id: 'B1' }); +}, 'Testing with null filter'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, undefined); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B1' }); + assert_node(walker.currentNode, { type: Element, id: 'B1' }); +}, 'Testing with undefined filter'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, {}); + assert_throws_js(TypeError, function () { walker.firstChild(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_throws_js(TypeError, function () { walker.nextNode(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); +}, 'Testing with object lacking acceptNode property'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, { acceptNode: "foo" }); + assert_throws_js(TypeError, function () { walker.firstChild(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_throws_js(TypeError, function () { walker.nextNode(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); +}, 'Testing with object with non-function acceptNode property'); + +test(function(t) +{ + var filter = function() { return NodeFilter.FILTER_ACCEPT; }; + filter.acceptNode = t.unreached_func("`acceptNode` method should not be called on functions"); + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B1' }); +}, 'Testing with function having acceptNode function'); + +test(function() +{ + var test_error = { name: "test" }; + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, + function(node) { + throw test_error; + }); + assert_throws_exactly(test_error, function () { walker.firstChild(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_throws_exactly(test_error, function () { walker.nextNode(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); +}, 'Testing with filter function that throws'); + +test(function() { + var testError = { name: "test" }; + var filter = { + get acceptNode() { + throw testError; + }, + }; + + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_throws_exactly(testError, function() { walker.firstChild(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_throws_exactly(testError, function() { walker.nextNode(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); +}, "rethrows errors when getting `acceptNode`"); + +test(function() { + var calls = 0; + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, { + get acceptNode() { + calls++; + return function() { + return NodeFilter.FILTER_ACCEPT; + }; + }, + }); + + assert_equals(calls, 0); + walker.nextNode(); + walker.nextNode(); + assert_equals(calls, 2); +}, "performs `Get` on every traverse"); + +test(function() +{ + var test_error = { name: "test" }; + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, + { + acceptNode : function(node) { + throw test_error; + } + }); + assert_throws_exactly(test_error, function () { walker.firstChild(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_throws_exactly(test_error, function () { walker.nextNode(); }); + assert_node(walker.currentNode, { type: Element, id: 'root' }); +}, 'Testing with filter object that throws'); + +test(() => +{ + let thisValue, nodeArgID; + const filter = { + acceptNode(node) { + thisValue = this; + nodeArgID = node.id; + return NodeFilter.FILTER_ACCEPT; + }, + }; + + const walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + walker.nextNode(); + + assert_equals(thisValue, filter); + assert_equals(nodeArgID, 'A1'); +}, 'Testing with filter object: this value and `node` argument'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html b/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html new file mode 100644 index 0000000000..bd8b112840 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-basic.html @@ -0,0 +1,154 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/TreeWalker-basic.html +--> +<head> +<title>TreeWalker: Basic test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>This test checks the basic functionality of TreeWalker.</p> +<script> +function createSampleDOM() +{ + // Tree structure: + // #a + // | + // +----+----+ + // | | + // "b" #c + // | + // +----+----+ + // | | + // #d <!--j--> + // | + // +----+----+ + // | | | + // "e" #f "i" + // | + // +--+--+ + // | | + // "g" <!--h--> + var div = document.createElement('div'); + div.id = 'a'; + // div.innerHTML = 'b<div id="c"><div id="d">e<span id="f">g<!--h--></span>i</div><!--j--></div>'; + + div.appendChild(document.createTextNode("b")); + + var c = document.createElement("div"); + c.id = 'c'; + div.appendChild(c); + + var d = document.createElement("div"); + d.id = 'd'; + c.appendChild(d); + + var e = document.createTextNode("e"); + d.appendChild(e); + + var f = document.createElement("span"); + f.id = 'f'; + d.appendChild(f); + + var g = document.createTextNode("g"); + f.appendChild(g); + + var h = document.createComment("h"); + f.appendChild(h); + + var i = document.createTextNode("i"); + d.appendChild(i); + + var j = document.createComment("j"); + c.appendChild(j); + + return div; +} + +function check_walker(walker, root, whatToShowValue) +{ + whatToShowValue = whatToShowValue === undefined ? 0xFFFFFFFF : whatToShowValue; + + assert_equals(walker.toString(), '[object TreeWalker]', 'toString'); + assert_equals(walker.root, root, 'root'); + assert_equals(walker.whatToShow, whatToShowValue, 'whatToShow'); + assert_equals(walker.filter, null, 'filter'); + assert_equals(walker.currentNode, root, 'currentNode'); + assert_readonly(walker, 'root'); + assert_readonly(walker, 'whatToShow'); + assert_readonly(walker, 'filter'); +} + +test(function () +{ + var root = createSampleDOM(); + var walker = document.createTreeWalker(root); + check_walker(walker, root); +}, 'Construct a TreeWalker by document.createTreeWalker(root).'); + +test(function () +{ + var root = createSampleDOM(); + var walker = document.createTreeWalker(root, null, null); + check_walker(walker, root, 0); +}, 'Construct a TreeWalker by document.createTreeWalker(root, null, null).'); + +test(function () +{ + var root = createSampleDOM(); + var walker = document.createTreeWalker(root, undefined, undefined); + check_walker(walker, root); +}, 'Construct a TreeWalker by document.createTreeWalker(root, undefined, undefined).'); + +test(function () +{ + assert_throws_js(TypeError, function () { document.createTreeWalker(); }); + assert_throws_js(TypeError, function () { document.createTreeWalker(null); }); + assert_throws_js(TypeError, function () { document.createTreeWalker(undefined); }); + assert_throws_js(TypeError, function () { document.createTreeWalker(new Object()); }); + assert_throws_js(TypeError, function () { document.createTreeWalker(1); }); +}, 'Give an invalid root node to document.createTreeWalker().'); + +test(function () +{ + var root = createSampleDOM(); + var walker = document.createTreeWalker(root); + var f = root.lastChild.firstChild.childNodes[1]; // An element node: div#f. + + assert_node(walker.currentNode, { type: Element, id: 'a' }); + assert_equals(walker.parentNode(), null); + assert_node(walker.currentNode, { type: Element, id: 'a' }); + assert_node(walker.firstChild(), { type: Text, nodeValue: 'b' }); + assert_node(walker.currentNode, { type: Text, nodeValue: 'b' }); + assert_node(walker.nextSibling(), { type: Element, id: 'c' }); + assert_node(walker.currentNode, { type: Element, id: 'c' }); + assert_node(walker.lastChild(), { type: Comment, nodeValue: 'j' }); + assert_node(walker.currentNode, { type: Comment, nodeValue: 'j' }); + assert_node(walker.previousSibling(), { type: Element, id: 'd' }); + assert_node(walker.currentNode, { type: Element, id: 'd' }); + assert_node(walker.nextNode(), { type: Text, nodeValue: 'e' }); + assert_node(walker.currentNode, { type: Text, nodeValue: 'e' }); + assert_node(walker.parentNode(), { type: Element, id: 'd' }); + assert_node(walker.currentNode, { type: Element, id: 'd' }); + assert_node(walker.previousNode(), { type: Element, id: 'c' }); + assert_node(walker.currentNode, { type: Element, id: 'c' }); + assert_equals(walker.nextSibling(), null); + assert_node(walker.currentNode, { type: Element, id: 'c' }); + walker.currentNode = f; + assert_equals(walker.currentNode, f); +}, 'Walk over nodes.'); + +test(function() { + var treeWalker = document.createTreeWalker(document.body, 42, null); + assert_equals(treeWalker.root, document.body); + assert_equals(treeWalker.currentNode, document.body); + assert_equals(treeWalker.whatToShow, 42); + assert_equals(treeWalker.filter, null); +}, "Optional arguments to createTreeWalker should be optional (3 passed, null)."); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html b/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html new file mode 100644 index 0000000000..f795abe0d2 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-currentNode.html @@ -0,0 +1,73 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/resources/TreeWalker-currentNode.js +--> +<head> +<title>TreeWalker: currentNode</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<div id='parent'> +<div id='subTree'><p>Lorem ipsum <span>dolor <b>sit</b> amet</span>, consectetur <i>adipisicing</i> elit, sed do eiusmod <tt>tempor <b><i>incididunt ut</i> labore</b> et dolore magna</tt> aliqua.</p></div> +</div> +<p>Test TreeWalker currentNode functionality</p> +<script> +// var subTree = document.createElement('div'); +// subTree.innerHTML = "<p>Lorem ipsum <span>dolor <b>sit</b> amet</span>, consectetur <i>adipisicing</i> elit, sed do eiusmod <tt>tempor <b><i>incididunt ut</i> labore</b> et dolore magna</tt> aliqua.</p>" +// document.body.appendChild(subTree); +var subTree = document.getElementById("subTree"); + +var all = function(node) { return true; } + +test(function() +{ + var w = document.createTreeWalker(subTree, NodeFilter.SHOW_ELEMENT, all); + assert_node(w.currentNode, { type: Element, id: 'subTree' }); + assert_equals(w.parentNode(), null); + assert_node(w.currentNode, { type: Element, id: 'subTree' }); +}, "Test that TreeWalker.parent() doesn't set the currentNode to a node not under the root."); + +test(function() +{ + var w = document.createTreeWalker(subTree, + NodeFilter.SHOW_ELEMENT + | NodeFilter.SHOW_COMMENT, + all); + w.currentNode = document.documentElement; + assert_equals(w.parentNode(), null); + assert_equals(w.currentNode, document.documentElement); + w.currentNode = document.documentElement; + assert_equals(w.nextNode(), document.documentElement.firstChild); + assert_equals(w.currentNode, document.documentElement.firstChild); + w.currentNode = document.documentElement; + assert_equals(w.previousNode(), null); + assert_equals(w.currentNode, document.documentElement); + w.currentNode = document.documentElement; + assert_equals(w.firstChild(), document.documentElement.firstChild); + assert_equals(w.currentNode, document.documentElement.firstChild); + w.currentNode = document.documentElement; + assert_equals(w.lastChild(), document.documentElement.lastChild); + assert_equals(w.currentNode, document.documentElement.lastChild); + w.currentNode = document.documentElement; + assert_equals(w.nextSibling(), null); + assert_equals(w.currentNode, document.documentElement); + w.currentNode = document.documentElement; + assert_equals(w.previousSibling(), null); + assert_equals(w.currentNode, document.documentElement); +}, "Test that we handle setting the currentNode to arbitrary nodes not under the root element."); + +test(function() +{ + var w = document.createTreeWalker(subTree, NodeFilter.SHOW_ELEMENT, all); + w.currentNode = subTree.previousSibling; + assert_equals(w.nextNode(), subTree); + w.currentNode = document.getElementById("parent"); + assert_equals(w.firstChild(), subTree); +}, "Test how we handle the case when the traversed to node is within the root, but the currentElement is not."); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html b/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html new file mode 100644 index 0000000000..e24ca06e20 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-previousNodeLastChildReject.html @@ -0,0 +1,87 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/previousNodeLastChildReject.js +--> +<head> +<title>TreeWalker: previousNodeLastChildReject</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>Test that previousNode properly respects the filter.</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + // testElement.innerHTML='<div id="A1"><div id="B1"><div id="C1"></div><div id="C2"><div id="D1"></div><div id="D2"></div></div></div><div id="B2"><div id="C3"></div><div id="C4"></div></div></div>'; + // testElement.innerHTML=' + // <div id="A1"> + // <div id="B1"> + // <div id="C1"> + // </div> + // <div id="C2"> + // <div id="D1"> + // </div> + // <div id="D2"> + // </div> + // </div> + // </div> + // <div id="B2"> + // <div id="C3"> + // </div> + // <div id="C4"> + // </div> + // </div> + // </div>'; + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); a1.id = "A1"; + var b1 = document.createElement("div"); b1.id = "B1"; + var b2 = document.createElement("div"); b2.id = "B2"; + var c1 = document.createElement("div"); c1.id = "C1"; + var c2 = document.createElement("div"); c2.id = "C2"; + var c3 = document.createElement("div"); c3.id = "C3"; + var c4 = document.createElement("div"); c4.id = "C4"; + var d1 = document.createElement("div"); d1.id = "D1"; + var d2 = document.createElement("div"); d2.id = "D2"; + + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2); + b1.appendChild(c1); + b1.appendChild(c2); + b2.appendChild(c3); + b2.appendChild(c4); + c2.appendChild(d1); + c2.appendChild(d2); +}); + +test(function() +{ + function filter(node) + { + if (node.id == "C2") + return NodeFilter.FILTER_REJECT; + return NodeFilter.FILTER_ACCEPT; + } + + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B1' }); + assert_node(walker.currentNode, { type: Element, id: 'B1' }); + assert_node(walker.nextNode(), { type: Element, id: 'C1' }); + assert_node(walker.currentNode, { type: Element, id: 'C1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.currentNode, { type: Element, id: 'B2' }); + assert_node(walker.previousNode(), { type: Element, id: 'C1' }); + assert_node(walker.currentNode, { type: Element, id: 'C1' }); +}, 'Test that previousNode properly respects the filter.'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html b/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html new file mode 100644 index 0000000000..5e28aa5142 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-previousSiblingLastChildSkip.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/previousSiblingLastChildSkip.js +--> +<head> +<title>TreeWalker: previousSiblingLastChildSkip</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>Test that previousSibling properly respects the filter.</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + // testElement.innerHTML='<div id="A1"><div id="B1"><div id="C1"></div><div id="C2"><div id="D1"></div><div id="D2"></div></div></div><div id="B2"><div id="C3"></div><div id="C4"></div></div></div>'; + // testElement.innerHTML=' + // <div id="A1"> + // <div id="B1"> + // <div id="C1"> + // </div> + // <div id="C2"> + // <div id="D1"> + // </div> + // <div id="D2"> + // </div> + // </div> + // </div> + // <div id="B2"> + // <div id="C3"> + // </div> + // <div id="C4"> + // </div> + // </div> + // </div>'; + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); a1.id = "A1"; + var b1 = document.createElement("div"); b1.id = "B1"; + var b2 = document.createElement("div"); b2.id = "B2"; + var c1 = document.createElement("div"); c1.id = "C1"; + var c2 = document.createElement("div"); c2.id = "C2"; + var c3 = document.createElement("div"); c3.id = "C3"; + var c4 = document.createElement("div"); c4.id = "C4"; + var d1 = document.createElement("div"); d1.id = "D1"; + var d2 = document.createElement("div"); d2.id = "D2"; + + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2); + b1.appendChild(c1); + b1.appendChild(c2); + b2.appendChild(c3); + b2.appendChild(c4); + c2.appendChild(d1); + c2.appendChild(d2); +}); + +test(function() +{ + function filter(node) + { + if (node.id == "B1") + return NodeFilter.FILTER_SKIP; + return NodeFilter.FILTER_ACCEPT; + } + + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_node(walker.currentNode, { type: Element, id: 'root' }); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.currentNode, { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'C1' }); + assert_node(walker.currentNode, { type: Element, id: 'C1' }); + assert_node(walker.nextNode(), { type: Element, id: 'C2' }); + assert_node(walker.currentNode, { type: Element, id: 'C2' }); + assert_node(walker.nextNode(), { type: Element, id: 'D1' }); + assert_node(walker.currentNode, { type: Element, id: 'D1' }); + assert_node(walker.nextNode(), { type: Element, id: 'D2' }); + assert_node(walker.currentNode, { type: Element, id: 'D2' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.currentNode, { type: Element, id: 'B2' }); + assert_node(walker.previousSibling(), { type: Element, id: 'C2' }); + assert_node(walker.currentNode, { type: Element, id: 'C2' }); +}, 'Test that previousSibling properly respects the filter.'); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html new file mode 100644 index 0000000000..d6c96adc11 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-reject.html @@ -0,0 +1,109 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-reject.js +--> +<head> +<title>TreeWalker: traversal-reject</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>Test TreeWalker with rejection</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + //testElement.innerHTML='<div id="A1"> <div id="B1"> <div id="C1"></div> </div> <div id="B2"></div><div id="B3"></div> </div>'; + // <div id="A1"> + // <div id="B1"> + // <div id="C1"></div> + // </div> + // <div id="B2"></div> + // <div id="B3"></div> + // </div> + + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); a1.id = "A1"; + var b1 = document.createElement("div"); b1.id = "B1"; + var b2 = document.createElement("div"); b2.id = "B2"; + var b3 = document.createElement("div"); b3.id = "B3"; + var c1 = document.createElement("div"); c1.id = "C1"; + + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2); + a1.appendChild(b3); + b1.appendChild(c1); +}); + +var rejectB1Filter = { + acceptNode: function(node) { + if (node.id == 'B1') + return NodeFilter.FILTER_REJECT; + + return NodeFilter.FILTER_ACCEPT; + } +} + +var skipB2Filter = { + acceptNode: function(node) { + if (node.id == 'B2') + return NodeFilter.FILTER_SKIP; + + return NodeFilter.FILTER_ACCEPT; + } +} + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter); + assert_node(walker.nextNode(), { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.nextNode(), { type: Element, id: 'B3' }); +}, 'Testing nextNode'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.firstChild(), { type: Element, id: 'B2' }); +}, 'Testing firstChild'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.firstChild(), { type: Element, id: 'B1' }); + assert_node(walker.nextSibling(), { type: Element, id: 'B3' }); +}, 'Testing nextSibling'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter); + walker.currentNode = testElement.querySelectorAll('#C1')[0]; + assert_node(walker.parentNode(), { type: Element, id: 'A1' }); +}, 'Testing parentNode'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter); + walker.currentNode = testElement.querySelectorAll('#B3')[0]; + assert_node(walker.previousSibling(), { type: Element, id: 'B1' }); +}, 'Testing previousSibling'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, rejectB1Filter); + walker.currentNode = testElement.querySelectorAll('#B3')[0]; + assert_node(walker.previousNode(), { type: Element, id: 'B2' }); + assert_node(walker.previousNode(), { type: Element, id: 'A1' }); +}, 'Testing previousNode'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html new file mode 100644 index 0000000000..b6eafd4596 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip-most.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-skip-most.js +--> +<head> +<title>TreeWalker: traversal-skip-most</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>Test TreeWalker with skipping</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + // testElement.innerHTML='<div id="A1"><div id="B1" class="keep"></div><div id="B2">this text matters</div><div id="B3" class="keep"></div></div>'; + // <div id="A1"> + // <div id="B1" class="keep"></div> + // <div id="B2">this text matters</div> + // <div id="B3" class="keep"></div> + // </div> + + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); a1.id = "A1"; + var b1 = document.createElement("div"); b1.id = "B1"; b1.className = "keep"; + var b2 = document.createElement("div"); b2.id = "B2"; + var b3 = document.createElement("div"); b3.id = "B3"; b3.className = "keep"; + + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2) + .appendChild(document.createTextNode("this text matters")); + a1.appendChild(b3); +}); + +var filter = { + acceptNode: function(node) { + if (node.className == 'keep') + return NodeFilter.FILTER_ACCEPT; + + return NodeFilter.FILTER_SKIP; + } +} + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + assert_node(walker.firstChild(), { type: Element, id: 'B1' }); + assert_node(walker.nextSibling(), { type: Element, id: 'B3' }); +}, 'Testing nextSibling'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, filter); + walker.currentNode = testElement.querySelectorAll('#B3')[0]; + assert_node(walker.previousSibling(), { type: Element, id: 'B1' }); +}, 'Testing previousSibling'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html new file mode 100644 index 0000000000..6bbebe667e --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-traversal-skip.html @@ -0,0 +1,111 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from chromium/source/src/third_party/WebKit/LayoutTests/fast/dom/TreeWalker/script-tests/traversal-skip.js +--> +<head> +<title>TreeWalker: traversal-skip</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>Test TreeWalker with skipping</p> +<script> +var testElement; +setup(function() { + testElement = document.createElement("div"); + testElement.id = 'root'; + // testElement.innerHTML='<div id="A1"> <div id="B1"> <div id="C1"></div> </div> <div id="B2"></div><div id="B3"></div> </div>'; + // <div id="A1"> + // <div id="B1"> + // <div id="C1"></div> + // </div> + // <div id="B2"></div> + // <div id="B3"></div> + // </div> + + + // XXX for Servo, build the tree without using innerHTML + var a1 = document.createElement("div"); a1.id = "A1"; + var b1 = document.createElement("div"); b1.id = "B1"; + var b2 = document.createElement("div"); b2.id = "B2"; + var b3 = document.createElement("div"); b3.id = "B3"; + var c1 = document.createElement("div"); c1.id = "C1"; + + testElement.appendChild(a1); + a1.appendChild(b1); + a1.appendChild(b2); + a1.appendChild(b3); + b1.appendChild(c1); +}); + +var skipB1Filter = { + acceptNode: function(node) { + if (node.id == 'B1') + return NodeFilter.FILTER_SKIP; + + return NodeFilter.FILTER_ACCEPT; + } +} + +var skipB2Filter = { + acceptNode: function(node) { + if (node.id == 'B2') + return NodeFilter.FILTER_SKIP; + + return NodeFilter.FILTER_ACCEPT; + } +} + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter); + assert_node(walker.nextNode(), { type: Element, id: 'A1' }); + assert_node(walker.nextNode(), { type: Element, id: 'C1' }); + assert_node(walker.nextNode(), { type: Element, id: 'B2' }); + assert_node(walker.nextNode(), { type: Element, id: 'B3' }); +}, 'Testing nextNode'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.firstChild(), { type: Element, id: 'C1' }); +}, 'Testing firstChild'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter); + assert_node(walker.firstChild(), { type: Element, id: 'A1' }); + assert_node(walker.firstChild(), { type: Element, id: 'B1' }); + assert_node(walker.nextSibling(), { type: Element, id: 'B3' }); +}, 'Testing nextSibling'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter); + walker.currentNode = testElement.querySelectorAll('#C1')[0]; + assert_node(walker.parentNode(), { type: Element, id: 'A1' }); +}, 'Testing parentNode'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB2Filter); + walker.currentNode = testElement.querySelectorAll('#B3')[0]; + assert_node(walker.previousSibling(), { type: Element, id: 'B1' }); +}, 'Testing previousSibling'); + +test(function() +{ + var walker = document.createTreeWalker(testElement, NodeFilter.SHOW_ELEMENT, skipB1Filter); + walker.currentNode = testElement.querySelectorAll('#B3')[0]; + assert_node(walker.previousNode(), { type: Element, id: 'B2' }); + assert_node(walker.previousNode(), { type: Element, id: 'C1' }); + assert_node(walker.previousNode(), { type: Element, id: 'A1' }); +}, 'Testing previousNode'); + +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html b/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html new file mode 100644 index 0000000000..b99e33e01f --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker-walking-outside-a-tree.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<!-- +Test adapted from https://github.com/operasoftware/presto-testo/blob/master/core/standards/acid3/individual/006a.html +--> +<head> +<title>TreeWalker: walking-outside-a-tree</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="support/assert-node.js"></script> +<div id=log></div> +</head> +<body> +<p>[Acid3 - Test 006a] walking outside a tree</p> +<script> +test(function () { + // test 6: walking outside a tree + var doc = document.createElement("div"); + var head = document.createElement('head'); + var title = document.createElement('title'); + var body = document.createElement('body'); + var p = document.createElement('p'); + doc.appendChild(head); + head.appendChild(title); + doc.appendChild(body); + body.appendChild(p); + + var w = document.createTreeWalker(body, 0xFFFFFFFF, null); + doc.removeChild(body); + assert_equals(w.lastChild(), p, "TreeWalker failed after removing the current node from the tree"); + doc.appendChild(p); + assert_equals(w.previousNode(), title, "failed to handle regrafting correctly"); + p.appendChild(body); + assert_equals(w.nextNode(), p, "couldn't retrace steps"); + assert_equals(w.nextNode(), body, "couldn't step back into root"); + assert_equals(w.previousNode(), null, "root didn't retake its rootish position"); +}, "walking outside a tree"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/TreeWalker.html b/testing/web-platform/tests/dom/traversal/TreeWalker.html new file mode 100644 index 0000000000..093c781447 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/TreeWalker.html @@ -0,0 +1,324 @@ +<!doctype html> +<title>TreeWalker tests</title> +<link rel="author" title="Aryeh Gregor" href=ayg@aryeh.name> +<meta name=timeout content=long> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src=../common.js></script> +<script> +"use strict"; + +// TODO .previousNode, .nextNode + +test(function() { + var depth = 0; + var walker = document.createTreeWalker(document, NodeFilter.SHOW_ALL, + function() { + if (depth == 0) { + depth++; + walker.firstChild(); + } + return NodeFilter.FILTER_ACCEPT; + }); + walker.currentNode = document.body; + assert_throws_dom("InvalidStateError", function() { walker.parentNode() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.firstChild() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.lastChild() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.previousSibling() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.nextSibling() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.previousNode() }); + depth--; + assert_throws_dom("InvalidStateError", function() { walker.nextNode() }); +}, "Recursive filters need to throw"); + +function filterNode(node, whatToShow, filter) { + // "If active flag is set throw an "InvalidStateError"." + // Ignore active flag for these tests, we aren't calling recursively + // TODO Test me + + // "Let n be node's nodeType attribute value minus 1." + var n = node.nodeType - 1; + + // "If the nth bit (where 0 is the least significant bit) of whatToShow is + // not set, return FILTER_SKIP." + if (!(whatToShow & (1 << n))) { + return NodeFilter.FILTER_SKIP; + } + + // "If filter is null, return FILTER_ACCEPT." + if (!filter) { + return NodeFilter.FILTER_ACCEPT; + } + + // "Set the active flag." + // + // "Let result be the return value of invoking filter." + // + // "Unset the active flag." + // + // "If an exception was thrown, re-throw the exception." + // TODO Test me + // + // "Return result." + return filter(node); +} + +function testTraverseChildren(type, walker, root, whatToShow, filter) { + // TODO We don't test .currentNode other than the root + walker.currentNode = root; + assert_equals(walker.currentNode, root, "Setting .currentNode"); + + var expectedReturn = null; + var expectedCurrentNode = root; + + // "To traverse children of type type, run these steps: + // + // "Let node be the value of the currentNode attribute." + var node = walker.currentNode; + + // "Set node to node's first child if type is first, and node's last child + // if type is last." + node = type == "first" ? node.firstChild : node.lastChild; + + // "Main: While node is not null, run these substeps:" + while (node) { + // "Filter node and let result be the return value." + var result = filterNode(node, whatToShow, filter); + + // "If result is FILTER_ACCEPT, then set the currentNode attribute to + // node and return node." + if (result == NodeFilter.FILTER_ACCEPT) { + expectedCurrentNode = expectedReturn = node; + break; + } + + // "If result is FILTER_SKIP, run these subsubsteps:" + if (result == NodeFilter.FILTER_SKIP) { + // "Let child be node's first child if type is first, and node's + // last child if type is last." + var child = type == "first" ? node.firstChild : node.lastChild; + + // "If child is not null, set node to child and goto Main." + if (child) { + node = child; + continue; + } + } + + // "While node is not null, run these subsubsteps:" + while (node) { + // "Let sibling be node's next sibling if type is first, and node's + // previous sibling if type is last." + var sibling = type == "first" ? node.nextSibling + : node.previousSibling; + + // "If sibling is not null, set node to sibling and goto Main." + if (sibling) { + node = sibling; + break; + } + + // "Let parent be node's parent." + var parent = node.parentNode; + + // "If parent is null, parent is root, or parent is currentNode + // attribute's value, return null." + if (!parent || parent == root || parent == walker.currentNode) { + expectedReturn = node = null; + break; + } else { + // "Otherwise, set node to parent." + node = parent; + } + } + } + + if (type == "first") { + assert_equals(walker.firstChild(), expectedReturn, ".firstChild()"); + assert_equals(walker.currentNode, expectedCurrentNode, + ".currentNode after .firstChild()"); + } else { + assert_equals(walker.lastChild(), expectedReturn, ".lastChild()"); + assert_equals(walker.currentNode, expectedCurrentNode, + ".currentNode after .lastChild()"); + } +} + +function testTraverseSiblings(type, walker, root, whatToShow, filter) { + // TODO We don't test .currentNode other than the root's first or last child + if (!root.firstChild) { + // Nothing much to test + + walker.currentNode = root; + assert_equals(walker.currentNode, root, "Setting .currentNode"); + + if (type == "next") { + assert_equals(walker.nextSibling(), null, ".nextSibling()"); + assert_equals(walker.currentNode, root, + ".currentNode after .nextSibling()") + } else { + assert_equals(walker.previousSibling(), null, ".previousSibling()"); + assert_equals(walker.currentNode, root, + ".currentNode after .previousSibling()") + } + return; + } + + if (type == "next") { + walker.currentNode = root.firstChild; + assert_equals(walker.currentNode, root.firstChild, + "Setting .currentNode"); + } else { + walker.currentNode = root.lastChild; + assert_equals(walker.currentNode, root.lastChild, + "Setting .currentNode"); + } + + var expectedReturn = null; + var expectedCurrentNode = type == "next" ? root.firstChild : root.lastChild; + + // "To traverse siblings of type type run these steps:" + (function() { + // "Let node be the value of the currentNode attribute." + var node = type == "next" ? root.firstChild : root.lastChild; + + // "If node is root, return null. + // + // "Run these substeps: + do { + // "Let sibling be node's next sibling if type is next, and node's + // previous sibling if type is previous." + var sibling = type == "next" ? node.nextSibling : + node.previousSibling; + + // "While sibling is not null, run these subsubsteps:" + while (sibling) { + // "Set node to sibling." + node = sibling; + + // "Filter node and let result be the return value." + var result = filterNode(node, whatToShow, filter); + + // "If result is FILTER_ACCEPT, then set the currentNode + // attribute to node and return node." + if (result == NodeFilter.FILTER_ACCEPT) { + expectedCurrentNode = expectedReturn = node; + return; + } + + // "Set sibling to node's first child if type is next, and + // node's last child if type is previous." + sibling = type == "next" ? node.firstChild : node.lastChild; + + // "If result is FILTER_REJECT or sibling is null, then set + // sibling to node's next sibling if type is next, and node's + // previous sibling if type is previous." + if (result == NodeFilter.FILTER_REJECT || !sibling) { + sibling = type == "next" ? node.nextSibling : + node.previousSibling; + } + } + + // "Set node to its parent." + node = node.parentNode; + + // "If node is null or is root, return null. + if (!node || node == root) { + return; + } + // "Filter node and if the return value is FILTER_ACCEPT, then + // return null." + if (filterNode(node, whatToShow, filter)) { + return; + } + + // "Run these substeps again." + } while (true); + })(); + + if (type == "next") { + assert_equals(walker.nextSibling(), expectedReturn, ".nextSibling()"); + assert_equals(walker.currentNode, expectedCurrentNode, + ".currentNode after .nextSibling()"); + } else { + assert_equals(walker.previousSibling(), expectedReturn, ".previousSibling()"); + assert_equals(walker.currentNode, expectedCurrentNode, + ".currentNode after .previousSibling()"); + } +} + +function testWalker(root, whatToShow, filter) { + var walker = document.createTreeWalker(root, whatToShow, filter); + + assert_equals(walker.root, root, ".root"); + assert_equals(walker.whatToShow, whatToShow, ".whatToShow"); + assert_equals(walker.filter, filter, ".filter"); + assert_equals(walker.currentNode, root, ".currentNode"); + + var expectedReturn = null; + var expectedCurrentNode = walker.currentNode; + // "The parentNode() method must run these steps:" + // + // "Let node be the value of the currentNode attribute." + var node = walker.currentNode; + + // "While node is not null and is not root, run these substeps:" + while (node && node != root) { + // "Let node be node's parent." + node = node.parentNode; + + // "If node is not null and filtering node returns FILTER_ACCEPT, then + // set the currentNode attribute to node, return node." + if (node && filterNode(node, whatToShow, filter) == + NodeFilter.FILTER_ACCEPT) { + expectedCurrentNode = expectedReturn = node; + } + } + assert_equals(walker.parentNode(), expectedReturn, ".parentNode()"); + assert_equals(walker.currentNode, expectedCurrentNode, + ".currentNode after .parentNode()"); + + testTraverseChildren("first", walker, root, whatToShow, filter); + testTraverseChildren("last", walker, root, whatToShow, filter); + + testTraverseSiblings("next", walker, root, whatToShow, filter); + testTraverseSiblings("previous", walker, root, whatToShow, filter); +} + +var whatToShows = [ + "0", + "0xFFFFFFFF", + "NodeFilter.SHOW_ELEMENT", + "NodeFilter.SHOW_ATTRIBUTE", + "NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_DOCUMENT", +]; + +var callbacks = [ + "null", + "(function(node) { return true })", + "(function(node) { return false })", + "(function(node) { return node.nodeName[0] == '#' })", +]; + +var tests = []; +for (var i = 0; i < testNodes.length; i++) { + for (var j = 0; j < whatToShows.length; j++) { + for (var k = 0; k < callbacks.length; k++) { + tests.push([ + "document.createTreeWalker(" + testNodes[i] + + ", " + whatToShows[j] + ", " + callbacks[k] + ")", + eval(testNodes[i]), eval(whatToShows[j]), eval(callbacks[k]) + ]); + } + } +} +generate_tests(testWalker, tests); + +testDiv.style.display = "none"; +</script> diff --git a/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html b/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html new file mode 100644 index 0000000000..f5e393d0f0 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/support/TreeWalker-acceptNode-filter-cross-realm-null-browsing-context-subframe.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> + +<script> +function createNodeIterator() { + function filter() { + nodeIterator.dummyFilterCalled = true; + return true; + } + const nodeIterator = parent.document.createNodeIterator(parent.document.body, NodeFilter.SHOW_ELEMENT, filter); + nodeIterator.dummyFilterCalled = false; + return nodeIterator; +} +</script> diff --git a/testing/web-platform/tests/dom/traversal/support/assert-node.js b/testing/web-platform/tests/dom/traversal/support/assert-node.js new file mode 100644 index 0000000000..0d5d8ad74f --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/support/assert-node.js @@ -0,0 +1,10 @@ +// |expected| should be an object indicating the expected type of node. +function assert_node(actual, expected) +{ + assert_true(actual instanceof expected.type, + 'Node type mismatch: actual = ' + actual.nodeType + ', expected = ' + expected.nodeType); + if (typeof(expected.id) !== 'undefined') + assert_equals(actual.id, expected.id); + if (typeof(expected.nodeValue) !== 'undefined') + assert_equals(actual.nodeValue, expected.nodeValue); +} diff --git a/testing/web-platform/tests/dom/traversal/support/empty-document.html b/testing/web-platform/tests/dom/traversal/support/empty-document.html new file mode 100644 index 0000000000..b9cd130a07 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/support/empty-document.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<body> diff --git a/testing/web-platform/tests/dom/traversal/unfinished/001.xml b/testing/web-platform/tests/dom/traversal/unfinished/001.xml new file mode 100644 index 0000000000..08bce72fcf --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/001.xml @@ -0,0 +1,53 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Basics</title> + <script type="text/javascript"> <![CDATA[ + function doTest() { + var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false); + var expected = new Array(9, // document + 1, // html + 3, 1, // head + 3, 1, 3, // title + 3, 1, 3, 4, // script and CDATA block + 3, 3, 1, // body + 3, 1, 3, // pre + 3, // </body> + 3, 8, // <!-- --> + 3, 7, // <? ?>, + 3, 4, 3); // CDATA + var found = new Array(); + + // walk document + var node; + while (node = iterator.nextNode()) + found.push(node.nodeType); + + // check results + var errors = 0; + var s = ''; + var length = (found.length > expected.length) ? found.length : expected.length; + s += 'EXPECTED FOUND\n'; + for (var i = 0; i < length; i += 1) { + s += ' ' + (expected[i] ? expected[i] : '-') + + ' ' + (found[i] ? found[i] : '-'); + if (found[i] != expected[i]) { + s += ' MISMATCH'; + errors += 1; + } + s += '\n'; + } + var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0]; + if (errors) + p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s; + else + p.firstChild.data = 'PASS'; + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script failed to run.</pre> + </body> + <!-- some more nodes to test this: --> + <?test node?> + <![CDATA[]]> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/002.xml b/testing/web-platform/tests/dom/traversal/unfinished/002.xml new file mode 100644 index 0000000000..bf3489688c --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/002.xml @@ -0,0 +1,54 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Basics Backwards</title> + <script type="text/javascript"> <![CDATA[ + function doTest() { + var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false); + var expected = new Array(9, // document + 1, // html + 3, 1, // head + 3, 1, 3, // title + 3, 1, 3, 4, // script and CDATA block + 3, 3, 1, // body + 3, 1, 3, // pre + 3, // </body> + 3, 8, // <!-- --> + 3, 7, // <? ?>, + 3, 4, 3); // CDATA + var found = new Array(); + + // walk document + var node; + while (node = iterator.nextNode()); + while (node = iterator.previousNode()) + found.unshift(node.nodeType); + + // check results + var errors = 0; + var s = ''; + var length = (found.length > expected.length) ? found.length : expected.length; + s += 'EXPECTED FOUND\n'; + for (var i = 0; i < length; i += 1) { + s += ' ' + (expected[i] ? expected[i] : '-') + + ' ' + (found[i] ? found[i] : '-'); + if (found[i] != expected[i]) { + s += ' MISMATCH'; + errors += 1; + } + s += '\n'; + } + var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0]; + if (errors) + p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s; + else + p.firstChild.data = 'PASS'; + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script failed to run.</pre> + </body> + <!-- some more nodes to test this: --> + <?test node?> + <![CDATA[]]> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/003.xml b/testing/web-platform/tests/dom/traversal/unfinished/003.xml new file mode 100644 index 0000000000..268e6bb4d7 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/003.xml @@ -0,0 +1,58 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of nodes that should have no effect</title> + <!-- + This tests these cases that should have no effect: + 1. Remove a node unrelated to the reference node + 2. Remove an ancestor of the root node + 3. Remove the root node itself + 4. Remove descendant of reference node + --> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var B = document.getElementById('B'); + var C = document.getElementById('C'); + var D = document.getElementById('D'); + var E = document.getElementById('E'); + check(iterator.nextNode(), root); + remove(document.getElementById('X')); + check(iterator.nextNode(), A); + remove(document.getElementById('Y')); + check(iterator.nextNode(), B); + remove(root); + check(iterator.nextNode(), C); + remove(E); + check(iterator.nextNode(), D); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="X"></span><span id="Y"><span id="root"><span id="A"><span id="B"><span id="C"><span id="D"><span id="E"></span></span></span></span></span></span></span></p> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/004.xml b/testing/web-platform/tests/dom/traversal/unfinished/004.xml new file mode 100644 index 0000000000..618978f021 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/004.xml @@ -0,0 +1,49 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of the Reference Node</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var AA = document.getElementById('AA'); + var B = document.getElementById('B'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), AA); + check(iterator.nextNode(), B); + remove(B); + check(iterator.previousNode(), AA); + remove(AA); + check(iterator.nextNode(), C); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/005.xml b/testing/web-platform/tests/dom/traversal/unfinished/005.xml new file mode 100644 index 0000000000..643e2f1cd4 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/005.xml @@ -0,0 +1,57 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of the Reference Node (deep check)</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var AA = document.getElementById('AA'); + var B = document.getElementById('B'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), AA); + check(iterator.nextNode(), B); + remove(B); + var X = addChildTo(AA); + check(iterator.nextNode(), X); + check(iterator.previousNode(), X); + remove(X); + var Y = addChildTo(AA); + check(iterator.previousNode(), Y); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + function addChildTo(a) { + var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span'); + a.appendChild(x); + return x; + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/006.xml b/testing/web-platform/tests/dom/traversal/unfinished/006.xml new file mode 100644 index 0000000000..c2302af836 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/006.xml @@ -0,0 +1,47 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards)</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var B = document.getElementById('B'); + var BB = document.getElementById('BB'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), B); + check(iterator.nextNode(), BB); + remove(B); + check(iterator.previousNode(), A); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p> + </body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/unfinished/007.xml b/testing/web-platform/tests/dom/traversal/unfinished/007.xml new file mode 100644 index 0000000000..98b212e4e5 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/007.xml @@ -0,0 +1,54 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards) (deep check)</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var B = document.getElementById('B'); + var BB = document.getElementById('BB'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), B); + check(iterator.nextNode(), BB); + remove(B); + var X = addChildTo(A); + check(iterator.nextNode(), X); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + function addChildTo(a) { + var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span'); + x.id = 'X'; + a.appendChild(x); + return x; + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p> + </body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/unfinished/008.xml b/testing/web-platform/tests/dom/traversal/unfinished/008.xml new file mode 100644 index 0000000000..41d7008ae4 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/008.xml @@ -0,0 +1,48 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards)</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var B = document.getElementById('B'); + var BB = document.getElementById('BB'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), B); + check(iterator.nextNode(), BB); + check(iterator.previousNode(), BB); + remove(B); + check(iterator.nextNode(), C); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p> + </body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/unfinished/009.xml b/testing/web-platform/tests/dom/traversal/unfinished/009.xml new file mode 100644 index 0000000000..c3006ecbd6 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/009.xml @@ -0,0 +1,55 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards) (deep check)</title> + <script type="text/javascript"> <![CDATA[ + var errors = 0; + var log = ''; + function doTest() { + var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false); + var root = document.getElementById('root'); + var A = document.getElementById('A'); + var B = document.getElementById('B'); + var BB = document.getElementById('BB'); + var C = document.getElementById('C'); + check(iterator.nextNode(), root); + check(iterator.nextNode(), A); + check(iterator.nextNode(), B); + check(iterator.nextNode(), BB); + check(iterator.previousNode(), BB); + remove(B); + var X = addChildTo(A); + check(iterator.previousNode(), X); + if (errors) + document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log; + else + document.getElementById('result').firstChild.data = 'PASS'; + } + function check(a, b) { + if (!a) { + errors += 1; + log += 'Found null but expected ' + b + ' (' + b.id + ').\n'; + } else if (a != b) { + errors += 1; + log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n'; + } + } + function remove(a) { + if (!a) { + errors += 1; + log += 'Tried removing null node.\n'; + } else + a.parentNode.removeChild(a); + } + function addChildTo(a) { + var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span'); + x.id = 'X'; + a.appendChild(x); + return x; + } + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script did not complete.</pre> + <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p> + </body> +</html> diff --git a/testing/web-platform/tests/dom/traversal/unfinished/010.xml b/testing/web-platform/tests/dom/traversal/unfinished/010.xml new file mode 100644 index 0000000000..63263a5fd7 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/010.xml @@ -0,0 +1,64 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>DOM Traversal: NodeIterator: Filters</title> + <script type="text/javascript"> <![CDATA[ + function doTest() { + var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, testFilter, false); + // skips text nodes and body element + var expected = new Array(9, // document + 1, // html + 1, // head + 1, // title + 1, 4, // script and CDATA block + // body (skipped) + 1, // pre + // </body> + 8, // <!-- --> + // PI skipped + 4); // CDATA + var found = new Array(); + + // walk document + var node; + while (node = iterator.nextNode()) + found.push(node.nodeType); + + // check results + var errors = 0; + var s = ''; + var length = (found.length > expected.length) ? found.length : expected.length; + s += 'EXPECTED FOUND\n'; + for (var i = 0; i < length; i += 1) { + s += ' ' + (expected[i] ? expected[i] : '-') + + ' ' + (found[i] ? found[i] : '-'); + if (found[i] != expected[i]) { + s += ' MISMATCH'; + errors += 1; + } + s += '\n'; + } + var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0]; + if (errors) + p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s; + else + p.firstChild.data = 'PASS'; + } + + function testFilter(n) { + if (n.nodeType == 3) { + return NodeFilter.FILTER_SKIP; + } else if (n.nodeName == 'body') { + return NodeFilter.FILTER_REJECT; // same as _SKIP + } + return 1; // FILTER_ACCEPT + } + + ]]></script> + </head> + <body onload="doTest()"> + <pre id="result">FAIL: Script failed to run.</pre> + </body> + <!-- some more nodes to test this: --> + <?body test?> + <![CDATA[]]> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/traversal/unfinished/TODO b/testing/web-platform/tests/dom/traversal/unfinished/TODO new file mode 100644 index 0000000000..cecdf98b08 --- /dev/null +++ b/testing/web-platform/tests/dom/traversal/unfinished/TODO @@ -0,0 +1 @@ +Check what happens when a NodeFilter turns a number not in the range 1..3
\ No newline at end of file diff --git a/testing/web-platform/tests/dom/window-extends-event-target.html b/testing/web-platform/tests/dom/window-extends-event-target.html new file mode 100644 index 0000000000..3b690324e5 --- /dev/null +++ b/testing/web-platform/tests/dom/window-extends-event-target.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Window extends EventTarget</title> +<link rel="help" href="https://github.com/jsdom/jsdom/issues/2830"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +test(() => { + + assert_equals(window.addEventListener, EventTarget.prototype.addEventListener); + assert_equals(window.removeEventListener, EventTarget.prototype.removeEventListener); + assert_equals(window.dispatchEvent, EventTarget.prototype.dispatchEvent); + +}, "EventTarget methods on Window instances are inherited from the EventTarget prototype"); + +test(() => { + + const kCustom = "custom-event"; + const customEvent = new CustomEvent(kCustom, { + bubbles: true + }); + + let target; + window.addEventListener.call(document.body, kCustom, function () { + target = this; + }); + + document.body.dispatchEvent(customEvent); + + assert_equals(target, document.body); + +}, "window.addEventListener respects custom `this`"); + +test(() => { + + const kCustom = "custom-event"; + const customEvent = new CustomEvent(kCustom, { + bubbles: true + }); + + let target; + window.addEventListener.call(null, kCustom, function () { + target = this; + }); + + document.body.dispatchEvent(customEvent); + + assert_equals(target, window); + +}, "window.addEventListener treats nullish `this` as `window`"); +</script> diff --git a/testing/web-platform/tests/dom/xslt/README.md b/testing/web-platform/tests/dom/xslt/README.md new file mode 100644 index 0000000000..ac713ce179 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/README.md @@ -0,0 +1,11 @@ +# XSLT + +This directory contains tentative tests for [XSLT](https://dom.spec.whatwg.org/#xslt). + +See [whatwg/dom#181](https://github.com/whatwg/dom/issues/181) for getting XSLT +better specified. + +There are additional details on XSLT in HTML: +- [Interactions with XPath and XSLT](https://html.spec.whatwg.org/multipage/infrastructure.html#interactions-with-xpath-and-xslt) +- [Interaction of `script` elements and XSLT](https://html.spec.whatwg.org/multipage/scripting.html#scriptTagXSLT) (non-normative) +- [Interaction of `template` elements with XSLT and XPath](https://html.spec.whatwg.org/multipage/scripting.html#template-XSLT-XPath) (non-normative) diff --git a/testing/web-platform/tests/dom/xslt/externalScript.js b/testing/web-platform/tests/dom/xslt/externalScript.js new file mode 100644 index 0000000000..7a2bf36225 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/externalScript.js @@ -0,0 +1 @@ +window.externalScript = true; diff --git a/testing/web-platform/tests/dom/xslt/invalid-output-encoding-crash.html b/testing/web-platform/tests/dom/xslt/invalid-output-encoding-crash.html new file mode 100644 index 0000000000..d84bb5b3c3 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/invalid-output-encoding-crash.html @@ -0,0 +1,26 @@ +<body> + +<script id=o_xml type="text/plain"> + <?xml version="1.0" encoding="UTF-8"?> +</script> + +<script id=o_xslt type="text/plain"><?xml version="1.0" encoding="UTF-8"?> + <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:output indent="no" omit-xml-declaration="no" encoding="bad-encoding" standalone="yes" /> + </xsl:transform> +</script> + +<script> +addEventListener("load", function() { + const doc = new DOMParser(); + const xml = doc.parseFromString(o_xml.textContent, "text/xml"); + const xsl = doc.parseFromString(o_xslt.textContent, "text/xml"); + const xsltPrs = new XSLTProcessor(); + xsltPrs.importStylesheet(xsl); + xsltPrs.transformToDocument(xml); + + document.body.appendChild(document.createTextNode("PASS: renderer didn't crash")); +}); +</script> + +</body> diff --git a/testing/web-platform/tests/dom/xslt/sort-ref.html b/testing/web-platform/tests/dom/xslt/sort-ref.html new file mode 100644 index 0000000000..163002d0d0 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/sort-ref.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1399858"> + +<div> + <div>1</div> + <div>2</div> + <div>3</div> + <div>7</div> +</div> diff --git a/testing/web-platform/tests/dom/xslt/sort.html b/testing/web-platform/tests/dom/xslt/sort.html new file mode 100644 index 0000000000..631c3edd6a --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/sort.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<link rel=match href="sort-ref.html"> + +<body> + <div id="container"></div> +</body> + +<script type="text/xml" id="sampleXml"> + <root> + <node id="1" /> + <node id="7" /> + <node id="3" /> + <node id="2" /> + </root> +</script> + +<script type="text/xml" id="sampleXsl"> + <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"> + + <xsl:template match="/"> + <xsl:apply-templates select="//node"> + <xsl:sort select="@id" data-type="number" /> + </xsl:apply-templates> + </xsl:template> + + <xsl:template match="node"> + <div> + <xsl:value-of select="@id"/> + </div> + </xsl:template> + + </xsl:stylesheet> +</script> + +<script> + let parser = new DOMParser(); + const xslStyleSheet = parser.parseFromString(document.getElementById('sampleXsl').textContent, 'text/xml'); + + const xsltProcessor = new XSLTProcessor(); + xsltProcessor.importStylesheet(xslStyleSheet); + + parser = new DOMParser(); + const xmlDoc = parser.parseFromString(document.getElementById('sampleXml').textContent, 'text/xml'); + + const fragment = xsltProcessor.transformToFragment(xmlDoc, document); + + document.getElementById('container').appendChild(fragment); +</script> diff --git a/testing/web-platform/tests/dom/xslt/strip-space-crash.xml b/testing/web-platform/tests/dom/xslt/strip-space-crash.xml new file mode 100644 index 0000000000..61a906a5e7 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/strip-space-crash.xml @@ -0,0 +1,33 @@ +<?xml-stylesheet type="text/xsl" href="#style"?> +<xsl:stylesheet + version="1.0" + xml:id="style" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:exsl="http://exslt.org/common" + extension-element-prefixes="exsl" +> + <xsl:strip-space elements="s"/> + + <xsl:template match="/"> + <xsl:variable name="space"> + <s> + <xsl:text> </xsl:text> + <e/> + <xsl:text> </xsl:text> + <e/> + <xsl:text> </xsl:text> + </s> + </xsl:variable> + <xsl:apply-templates select="exsl:node-set($space)/s"/> + </xsl:template> + + <xsl:template match="s"> + <r> + <xsl:variable name="text-nodes" select="text()"/> + <xsl:apply-templates/> + <xsl:copy-of select="$text-nodes"/> + </r> + </xsl:template> + + <xsl:template match="node()"/> +</xsl:stylesheet> diff --git a/testing/web-platform/tests/dom/xslt/transformToFragment-on-node-from-inactive-document-crash.html b/testing/web-platform/tests/dom/xslt/transformToFragment-on-node-from-inactive-document-crash.html new file mode 100644 index 0000000000..38a62a0a9d --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/transformToFragment-on-node-from-inactive-document-crash.html @@ -0,0 +1,11 @@ +<body> +<iframe id=i></iframe> +<script> +var el = i.contentDocument.documentElement; +i.remove() +var x = new XSLTProcessor(); +var xsl =new DOMParser().parseFromString('<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"/>','application/xml'); +x.importStylesheet(xsl); +x.transformToDocument(el); +</script> +</body> diff --git a/testing/web-platform/tests/dom/xslt/transformToFragment.tentative.window.js b/testing/web-platform/tests/dom/xslt/transformToFragment.tentative.window.js new file mode 100644 index 0000000000..7bb6a56855 --- /dev/null +++ b/testing/web-platform/tests/dom/xslt/transformToFragment.tentative.window.js @@ -0,0 +1,39 @@ +const cases = { + internal: '<script>window.internalScript = true;</script>', + external: '<script src="externalScript.js"></script>', +}; + +const loaded = new Promise(resolve => { + window.addEventListener('load', resolve); +}); + +Object.entries(cases).forEach(([k, v]) => { + const xsltSrc = `<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="html" encoding="utf-8" version="5"/> +<xsl:template match="/"> + <section> + ${v} + </section> +</xsl:template> +</xsl:stylesheet>`; + + const processor = new XSLTProcessor(); + const parser = new DOMParser(); + processor.importStylesheet( + parser.parseFromString(xsltSrc, 'application/xml') + ); + document.body.appendChild( + processor.transformToFragment( + parser.parseFromString('<x/>', 'application/xml'), + document + ) + ); + + promise_test(async () => { + await loaded; + assert_true( + window[`${k}Script`], + 'script element from XSLTProcessor.transformToFragment() is evaluated' + ); + }, `${k} script`); +}) diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html new file mode 100644 index 0000000000..0dd4468cf2 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-encoding.html @@ -0,0 +1,47 @@ +<!doctype html> +<title>DOMParser encoding test</title> +<meta charset="windows-1252"> <!-- intentional to make sure the results are UTF-8 anyway --> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +function assertEncoding(doc) { + assert_equals(doc.charset, "UTF-8", "document.charset"); + assert_equals(doc.characterSet, "UTF-8", "document.characterSet"); + assert_equals(doc.inputEncoding, "UTF-8", "document.characterSet"); +} + +setup(() => { + assert_equals(document.characterSet, "windows-1252", "the meta charset must be in effect, making the main document windows-1252"); +}); + +test(() => { + const parser = new DOMParser(); + const doc = parser.parseFromString("", "text/html"); + + assertEncoding(doc); +}, "HTML: empty"); + +test(() => { + const parser = new DOMParser(); + const doc = parser.parseFromString("", "text/xml"); + + assertEncoding(doc); +}, "XML: empty"); + +test(() => { + const parser = new DOMParser(); + const doc = parser.parseFromString(`<meta charset="latin2">`, "text/html"); + + assertEncoding(doc); +}, "HTML: meta charset"); + +test(() => { + const parser = new DOMParser(); + const doc = parser.parseFromString(`<?xml version="1.0" encoding="latin2"?><x/>`, "text/xml"); + + assertEncoding(doc); +}, "XML: XML declaration"); +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html new file mode 100644 index 0000000000..86e516d618 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-html.html @@ -0,0 +1,86 @@ +<!doctype html> +<title>DOMParser basic test of HTML parsing</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// |expected| should be an object indicating the expected type of node. +function assert_node(actual, expected) { + assert_true(actual instanceof expected.type, + 'Node type mismatch: actual = ' + actual.constructor.name + ', expected = ' + expected.type.name); + if (typeof(expected.id) !== 'undefined') + assert_equals(actual.id, expected.id, expected.idMessage); +} + +var doc; +setup(function() { + var parser = new DOMParser(); + var input = '<html id="root"><head></head><body></body></html>'; + doc = parser.parseFromString(input, 'text/html'); +}); + +test(function() { + var root = doc.documentElement; + assert_node(root, { type: HTMLHtmlElement, id: 'root', + idMessage: 'documentElement id attribute should be root.' }); +}, 'Parsing of id attribute'); + +test(function() { + assert_equals(doc.contentType, "text/html") +}, 'contentType'); + +test(function() { + assert_equals(doc.compatMode, "BackCompat") +}, 'compatMode'); + +test(function() { + var parser = new DOMParser(); + var input = '<!DOCTYPE html><html id="root"><head></head><body></body></html>'; + doc = parser.parseFromString(input, 'text/html'); + assert_equals(doc.compatMode, "CSS1Compat") +}, 'compatMode for a proper DOCTYPE'); + +// URL- and encoding-related stuff tested separately. + +test(function() { + assert_equals(doc.location, null, + 'The document must have a location value of null.'); +}, 'Location value'); + +test(function() { + var soup = "<!DOCTYPE foo></><foo></multiple></>"; + var htmldoc = new DOMParser().parseFromString(soup, "text/html"); + assert_equals(htmldoc.documentElement.localName, "html"); + assert_equals(htmldoc.documentElement.namespaceURI, "http://www.w3.org/1999/xhtml"); +}, "DOMParser parses HTML tag soup with no problems"); + +test(function() { + const doc = new DOMParser().parseFromString('<noembed><a></noembed>', 'text/html'); + assert_equals(doc.querySelector('noembed').textContent, '<a>'); +}, 'DOMParser should handle the content of <noembed> as raw text'); + +test(function() { + assert_throws_js(TypeError, function() { + new DOMParser().parseFromString("", "text/foo-this-is-invalid"); + }) +}, "DOMParser throws on an invalid enum value") + +test(() => { + const doc = new DOMParser().parseFromString(` +<html><body> +<style> + @import url(/dummy.css) +</style> +<script>document.x = 8<\/script> +</body></html>`, 'text/html'); + + assert_not_equals(doc.querySelector('script'), null, 'script must be found'); + assert_equals(doc.x, undefined, 'script must not be executed on the inner document'); + assert_equals(document.x, undefined, 'script must not be executed on the outer document'); +}, 'script is found synchronously even when there is a css import'); + +test(() => { + const doc = new DOMParser().parseFromString(`<body><noscript><p id="test1">test1<p id="test2">test2</noscript>`, 'text/html'); + assert_node(doc.body.firstChild.childNodes[0], { type: HTMLParagraphElement, id: 'test1' }); + assert_node(doc.body.firstChild.childNodes[1], { type: HTMLParagraphElement, id: 'test2' }); +}, 'must be parsed with scripting disabled, so noscript works'); +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html new file mode 100644 index 0000000000..41d7344a64 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base-pushstate.html @@ -0,0 +1,13 @@ +<!doctype html> +<title>DOMParser test of how the document's URL is set (base, pushstate)</title> +<base href="/fake/base-from-outer-frame"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/domparsing/resources/domparser-iframe-base-pushstate.html" onload="window.resolveLoadPromise();"></iframe> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-outer-frame"); +</script> +<script src="/domparsing/resources/domparser-url-tests.js"></script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html new file mode 100644 index 0000000000..5af1cee1c5 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-base.html @@ -0,0 +1,8 @@ +<!doctype html> +<title>DOMParser test of how the document's URL is set (base, no pushstate)</title> +<base href="/fake/base-from-outer-frame"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/domparsing/resources/domparser-iframe-base.html" onload="window.resolveLoadPromise();"></iframe> +<script src="/domparsing/resources/domparser-url-tests.js"></script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html new file mode 100644 index 0000000000..e7599f306e --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-moretests.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>DOMParser: Document's url</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +async_test(function() { + var iframe = document.createElement("iframe"); + iframe.onload = this.step_func(function() { + var child = iframe.contentWindow; + var supportedTypes = [ + "text/html", + "text/xml", + "application/xml", + "application/xhtml+xml", + "image/svg+xml", + ]; + + supportedTypes.forEach(function(type) { + test(function() { + var dp = new DOMParser(); + var doc = dp.parseFromString("<html></html>", type); + assert_equals(doc.URL, document.URL); + }, "Parent window (" + type + ")"); + + test(function() { + var dp = new child.DOMParser(); + var doc = dp.parseFromString("<html></html>", type); + assert_equals(doc.URL, child.document.URL); + }, "Child window (" + type + ")"); + + test(function() { + var dp = new DOMParser(); + var doc = child.DOMParser.prototype.parseFromString.call(dp, "<html></html>", type); + assert_equals(doc.URL, document.URL); + }, "Parent window with child method (" + type + ")"); + + test(function() { + var dp = new child.DOMParser(); + var doc = DOMParser.prototype.parseFromString.call(dp, "<html></html>", type); + assert_equals(doc.URL, child.document.URL); + }, "Child window with parent method (" + type + ")"); + }); + + var dpBeforeNavigation = new child.DOMParser(), urlBeforeNavigation = child.document.URL; + iframe.onload = this.step_func_done(function() { + supportedTypes.forEach(function(type) { + test(function() { + var doc = dpBeforeNavigation.parseFromString("<html></html>", type); + assert_equals(doc.URL, urlBeforeNavigation); + }, "Child window crossing navigation (" + type + ")"); + + test(function() { + var dp = new child.DOMParser(); + var doc = dp.parseFromString("<html></html>", type); + assert_equals(doc.URL, child.document.URL); + }, "Child window after navigation (" + type + ")"); + }); + }); + iframe.src = "/common/blank.html?2"; + }); + iframe.src = "/common/blank.html?1"; + document.body.appendChild(iframe); +}); +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html new file mode 100644 index 0000000000..ecb89bc741 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url-pushstate.html @@ -0,0 +1,12 @@ +<!doctype html> +<title>DOMParser test of how the document's URL is set (no base, pushstate)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/domparsing/resources/domparser-iframe-pushstate.html" onload="window.resolveLoadPromise();"></iframe> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-outer-frame"); +</script> +<script src="/domparsing/resources/domparser-url-tests.js"></script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html new file mode 100644 index 0000000000..9b9a672c48 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-url.html @@ -0,0 +1,7 @@ +<!doctype html> +<title>DOMParser test of how the document's URL is set (no pushstate, no base)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe src="/domparsing/resources/domparser-iframe.html" onload="window.resolveLoadPromise();"></iframe> +<script src="/domparsing/resources/domparser-url-tests.js"></script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html new file mode 100644 index 0000000000..cd655acf93 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-doctype.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>HTML entities for various XHTML Doctype variants</title> +<link rel=help href="http://w3c.github.io/html/xhtml.html#parsing-xhtml-documents"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + test(function () { + var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"><html><div id="test"/></html>', 'application/xhtml+xml'); + var div = doc.getElementById('test'); + assert_equals(div, null); // If null, then this was a an error document (didn't parse the input successfully) + }, "Doctype parsing of System Id must fail on ommitted value"); + + test(function () { + var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ""><html><div id="test"/></html>', 'application/xhtml+xml'); + var div = doc.getElementById('test'); + assert_not_equals(div, null); // If found, then the DOMParser didn't generate an error document + }, "Doctype parsing of System Id can handle empty string"); + + test(function () { + var doc = new DOMParser().parseFromString('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "x"><html><div id="test"/></html>', 'application/xhtml+xml'); + var div = doc.getElementById('test'); + assert_not_equals(div, null); + }, "Doctype parsing of System Id can handle a quoted value"); + +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html new file mode 100644 index 0000000000..26b5fa99f1 --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-internal-subset.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<title>Parsing and serialization of doctype internal subset</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +test(function () { + // https://www.w3.org/TR/xml11/#sec-prolog-dtd has intSubset as part of the + // syntax, which is not represented in the DocumentType interface. Check that + // publicId and systemId are not affected. + var doc = new DOMParser().parseFromString('<!DOCTYPE foo [ <!ENTITY x "y"> ]><foo>&x;</foo>', 'text/xml'); + var doctype = doc.doctype; + assert_equals(doctype.name, 'foo', 'doctype name'); + assert_equals(doctype.publicId, '', 'doctype publicId'); + assert_equals(doctype.systemId, '', 'doctype systemId'); + // Check that document itself was parsed correctly. + var documentElementString = new XMLSerializer().serializeToString(doc.documentElement); + assert_equals(documentElementString, '<foo>y</foo>', 'serialized document element'); + // https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documenttype-node also + // does not have any notion of the internal subset, so also check that it + // isn't serialized by XMLSerializer. + var doctypeString = new XMLSerializer().serializeToString(doctype); + assert_equals(doctypeString, '<!DOCTYPE foo>', 'serialized doctype'); +}); +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html new file mode 100644 index 0000000000..f6985aa20a --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml-parsererror.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<title>DOMParser: <parsererror> element added on error</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +const xhtml_prologue = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"' + + ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n' + + '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n' + + '<body>\n', + xhtml_epilogue = '</body>\n</html>\n'; + +[ + '<span x:test="testing">1</span>', // undeclared 'x' namespace prefix + '< span>2</span>', // bad start tag + '<span :test="testing">3</span>', // empty namespace prefix + '<span><em>4</span></em>', // staggered tags + '<span>5', // missing end </span> tag + '6</span>', // missing start <span> tag + '<span>7< /span>', // bad end tag + '<span>8</ span>', // bad end tag + '<span novalue>9</span>', // missing attribute value + '<span ="noattr">10</span>', // missing attribute name + '<span ::="test">11</span>', // bad namespace prefix + '<span xmlns:="urn:x-test:test">12</span>', // missing namespace prefix + '<span xmlns:xmlns="">13</span>', // invalid namespace prefix + '<span data-test=testing>14</span>', // unquoted attribute value + '15<span', // bad start tag + '<8:test xmlns:8="urn:x-test:test">16</8:test>', // invalid namespace prefix + '<span xmlns:p1 xmlns:p2="urn:x-test:test"/>17', // missing namespace URI +].forEach(fragment => { + test(() => { + var document_string = xhtml_prologue + fragment + xhtml_epilogue; + var doc = (new DOMParser).parseFromString(document_string, "application/xhtml+xml"); + var parsererrors = doc.getElementsByTagName("parsererror"); + assert_equals(parsererrors.length, 1, 'expecting one parsererror'); + }, document.title + ', ' + fragment); +}); + +[ + 'text/xml', + 'application/xml', + 'application/xhtml+xml', + 'image/svg+xml' +].forEach(mimeType => { + test(() => { + const doc = (new DOMParser()).parseFromString('<span x:test="testing">1</span>', mimeType); + assert_equals(doc.contentType, mimeType); + }, `${mimeType} is preserved in the error document`); +}) +</script> diff --git a/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html new file mode 100644 index 0000000000..b07bb3d87c --- /dev/null +++ b/testing/web-platform/tests/domparsing/DOMParser-parseFromString-xml.html @@ -0,0 +1,77 @@ +<!DOCTYPE html> +<title>DOMParser</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function checkMetadata(doc, contentType) { + assert_true(doc instanceof Document, "Should be Document"); + assert_equals(doc.URL, document.URL, "URL"); + assert_equals(doc.documentURI, document.URL, "documentURI"); + assert_equals(doc.baseURI, document.URL, "baseURI"); + assert_equals(doc.characterSet, "UTF-8", "characterSet"); + assert_equals(doc.charset, "UTF-8", "charset"); + assert_equals(doc.inputEncoding, "UTF-8", "inputEncoding"); + assert_equals(doc.contentType, contentType, "contentType"); + assert_equals(doc.location, null, "location"); +} + +var allowedTypes = ["text/xml", "application/xml", "application/xhtml+xml", "image/svg+xml"]; + +allowedTypes.forEach(function(type) { + test(function() { + var p = new DOMParser(); + var doc = p.parseFromString("<foo/>", type); + assert_true(doc instanceof Document, "Should be Document"); + checkMetadata(doc, type); + assert_equals(doc.documentElement.namespaceURI, null); + assert_equals(doc.documentElement.localName, "foo"); + assert_equals(doc.documentElement.tagName, "foo"); + }, "Should parse correctly in type " + type); + + test(function() { + var p = new DOMParser(); + var doc = p.parseFromString("<foo/>", type); + assert_false(doc instanceof XMLDocument, "Should not be XMLDocument"); + }, "XMLDocument interface for correctly parsed document with type " + type); + + test(function() { + var p = new DOMParser(); + var doc = p.parseFromString("<foo>", type); + checkMetadata(doc, type); + assert_equals(doc.documentElement.namespaceURI, "http://www.mozilla.org/newlayout/xml/parsererror.xml"); + assert_equals(doc.documentElement.localName, "parsererror"); + assert_equals(doc.documentElement.tagName, "parsererror"); + }, "Should return an error document for XML wellformedness errors in type " + type); + + test(function() { + var p = new DOMParser(); + var doc = p.parseFromString("<foo>", type); + assert_false(doc instanceof XMLDocument, "Should not be XMLDocument"); + }, "XMLDocument interface for incorrectly parsed document with type " + type); + + test(function() { + var p = new DOMParser(); + var doc = p.parseFromString(` + <html> + <head></head> + <body> + <script>document.x = 5;<\/script> + <noscript><p>test1</p><p>test2</p></noscript> + </body> + </html>` + , type); + + assert_equals(doc.x, undefined, "script must not be executed on the inner document"); + assert_equals(document.x, undefined, "script must not be executed on the outer document"); + + const body = doc.documentElement.children[1]; + assert_equals(body.localName, "body"); + assert_equals(body.children[1].localName, "noscript"); + assert_equals(body.children[1].children.length, 2); + assert_equals(body.children[1].children[0].localName, "p"); + assert_equals(body.children[1].children[1].localName, "p"); + }, "scripting must be disabled with type " + type); +}); +</script> diff --git a/testing/web-platform/tests/domparsing/META.yml b/testing/web-platform/tests/domparsing/META.yml new file mode 100644 index 0000000000..72f66c4301 --- /dev/null +++ b/testing/web-platform/tests/domparsing/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/DOM-Parsing/ +suggested_reviewers: + - ChrisParis + - jdm diff --git a/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html b/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html new file mode 100644 index 0000000000..17280af7b8 --- /dev/null +++ b/testing/web-platform/tests/domparsing/XMLSerializer-serializeToString.html @@ -0,0 +1,231 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<html> + <head> + <title>domparsing Test: XMLSerializer.serializeToString</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <h1>domparsing_XMLSerializer_serializeToString</h1> + <script> +const XMLNS_URI = 'http://www.w3.org/2000/xmlns/'; + +function createXmlDoc(){ + var input = '<?xml version="1.0" encoding="UTF-8"?><root><child1>value1</child1></root>'; + var parser = new DOMParser(); + return parser.parseFromString(input, 'text/xml'); +} + +// Returns the root element. +function parse(xmlString) { + return (new DOMParser()).parseFromString(xmlString, 'text/xml').documentElement; +} + +function serialize(node) { + return (new XMLSerializer()).serializeToString(node); +} + +test(function() { + var root = createXmlDoc().documentElement; + assert_equals(serialize(root), '<root><child1>value1</child1></root>'); +}, 'check XMLSerializer.serializeToString method could parsing xmldoc to string'); + +test(function() { + var root = parse('<html><head></head><body><div></div><span></span></body></html>'); + assert_equals(serialize(root.ownerDocument), '<html><head/><body><div/><span/></body></html>'); +}, 'check XMLSerializer.serializeToString method could parsing document to string'); + +test(function() { + var root = createXmlDoc().documentElement; + var element = root.ownerDocument.createElementNS('urn:foo', 'another'); + var child1 = root.firstChild; + root.replaceChild(element, child1); + element.appendChild(child1); + assert_equals(serialize(root), '<root><another xmlns="urn:foo"><child1 xmlns="">value1</child1></another></root>'); +}, 'Check if the default namespace is correctly reset.'); + +test(function() { + var root = parse('<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'); + assert_equals(serialize(root), '<root xmlns="urn:bar"><outer xmlns=""><inner>value1</inner></outer></root>'); +}, 'Check if there is no redundant empty namespace declaration.'); + +// https://github.com/w3c/DOM-Parsing/issues/47 +test(function() { + assert_equals(serialize(parse('<root><child xmlns=""/></root>')), + '<root><child/></root>'); + assert_equals(serialize(parse('<root xmlns=""><child xmlns=""/></root>')), + '<root><child/></root>'); + assert_equals(serialize(parse('<root xmlns="u1"><child xmlns="u1"/></root>')), + '<root xmlns="u1"><child/></root>'); +}, 'Check if redundant xmlns="..." is dropped.'); + +test(function() { + const root = parse('<root xmlns="uri1"/>'); + const child = root.ownerDocument.createElement('child'); + child.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL1'); + root.appendChild(child); + const child2 = root.ownerDocument.createElementNS('uri2', 'child2'); + child2.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL2'); + root.appendChild(child2); + const child3 = root.ownerDocument.createElementNS('uri1', 'child3'); + child3.setAttributeNS(XMLNS_URI, 'xmlns', 'FAIL3'); + root.appendChild(child3); + const child4 = root.ownerDocument.createElementNS('uri4', 'child4'); + child4.setAttributeNS(XMLNS_URI, 'xmlns', 'uri4'); + root.appendChild(child4); + const child5 = root.ownerDocument.createElement('child5'); + child5.setAttributeNS(XMLNS_URI, 'xmlns', ''); + root.appendChild(child5); + assert_equals(serialize(root), '<root xmlns="uri1"><child xmlns=""/><child2 xmlns="uri2"/><child3/><child4 xmlns="uri4"/><child5 xmlns=""/></root>'); +}, 'Check if inconsistent xmlns="..." is dropped.'); + +test(function() { + let root = parse('<r xmlns:xx="uri"></r>'); + root.setAttributeNS('uri', 'name', 'v'); + assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>'); + + let root2 = parse('<r xmlns:xx="uri"><b/></r>'); + let child = root2.firstChild; + child.setAttributeNS('uri', 'name', 'v'); + assert_equals(serialize(root2), '<r xmlns:xx="uri"><b xx:name="v"/></r>'); + + let root3 = parse('<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri"/></r>'); + let child3 = root3.firstChild; + child3.setAttributeNS('uri', 'name', 'v'); + assert_equals(serialize(root3), + '<r xmlns:x0="uri" xmlns:x2="uri"><b xmlns:x1="uri" x1:name="v"/></r>', + 'Should choose the nearest prefix'); +}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix'); + +// https://github.com/w3c/DOM-Parsing/issues/45 +test(function() { + let root = parse('<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2"/></el1>'); + root.firstChild.setAttributeNS('u1', 'name', 'v'); + assert_equals(serialize(root), + '<el1 xmlns:p="u1" xmlns:q="u1"><el2 xmlns:q="u2" q:name="v"/></el1>'); +}, 'Check if an attribute with namespace and no prefix is serialized with the nearest-declared prefix even if the prefix is assigned to another namespace.'); + +test(function() { + let root = parse('<r xmlns:xx="uri"></r>'); + root.setAttributeNS('uri', 'p:name', 'v'); + assert_equals(serialize(root), '<r xmlns:xx="uri" xx:name="v"/>'); + + let root2 = parse('<r xmlns:xx="uri"><b/></r>'); + let child = root2.firstChild; + child.setAttributeNS('uri', 'p:name', 'value'); + assert_equals(serialize(root2), + '<r xmlns:xx="uri"><b xx:name="value"/></r>'); +}, 'Check if the prefix of an attribute is replaced with another existing prefix mapped to the same namespace URI.'); + +// https://github.com/w3c/DOM-Parsing/issues/29 +test(function() { + let root = parse('<r xmlns:xx="uri"></r>'); + root.setAttributeNS('uri2', 'p:name', 'value'); + assert_equals(serialize(root), + '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>'); +}, 'Check if the prefix of an attribute is NOT preserved in a case where neither its prefix nor its namespace URI is not already used.'); + +test(function() { + let root = parse('<r xmlns:xx="uri"></r>'); + root.setAttributeNS('uri2', 'xx:name', 'value'); + assert_equals(serialize(root), + '<r xmlns:xx="uri" xmlns:ns1="uri2" ns1:name="value"/>'); +}, 'Check if the prefix of an attribute is replaced with a generated one in a case where the prefix is already mapped to a different namespace URI.'); + +test(function() { + var root = parse('<root />'); + root.setAttribute('attr', '\t'); + assert_in_array(serialize(root), [ + '<root attr="	"/>', '<root attr="	"/>']); + root.setAttribute('attr', '\n'); + assert_in_array(serialize(root), [ + '<root attr="
"/>', '<root attr=" "/>']); + root.setAttribute('attr', '\r'); + assert_in_array(serialize(root), [ + '<root attr="
"/>', '<root attr=" "/>']); +}, 'check XMLSerializer.serializeToString escapes attribute values for roundtripping'); + +test(function() { + const root = (new Document()).createElement('root'); + root.setAttributeNS('uri1', 'p:foobar', 'value1'); + root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2'); + assert_equals(serialize(root), '<root xmlns:ns1="uri1" ns1:foobar="value1" xmlns:p="uri2"/>'); +}, 'Check if attribute serialization takes into account of following xmlns:* attributes'); + +test(function() { + const root = parse('<root xmlns:p="uri1"><child/></root>'); + root.firstChild.setAttributeNS('uri2', 'p:foobar', 'v'); + assert_equals(serialize(root), '<root xmlns:p="uri1"><child xmlns:ns1="uri2" ns1:foobar="v"/></root>'); +}, 'Check if attribute serialization takes into account of the same prefix declared in an ancestor element'); + +test(function() { + assert_equals(serialize(parse('<root><child/></root>')), '<root><child/></root>'); + assert_equals(serialize(parse('<root xmlns="u1"><p:child xmlns:p="u1"/></root>')), '<root xmlns="u1"><child xmlns:p="u1"/></root>'); +}, 'Check if start tag serialization drops element prefix if the namespace is same as inherited default namespace.'); + +test(function() { + const root = parse('<root xmlns:p1="u1"><child xmlns:p2="u1"/></root>'); + const child2 = root.ownerDocument.createElementNS('u1', 'child2'); + root.firstChild.appendChild(child2); + assert_equals(serialize(root), '<root xmlns:p1="u1"><child xmlns:p2="u1"><p2:child2/></child></root>'); +}, 'Check if start tag serialization finds an appropriate prefix.'); + +test(function() { + const root = (new Document()).createElementNS('uri1', 'p:root'); + root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2'); + assert_equals(serialize(root), '<ns1:root xmlns:ns1="uri1" xmlns:p="uri2"/>'); +}, 'Check if start tag serialization takes into account of its xmlns:* attributes'); + +test(function() { + const root = (new Document()).createElement('root'); + root.setAttributeNS(XMLNS_URI, 'xmlns:p', 'uri2'); + const child = root.ownerDocument.createElementNS('uri1', 'p:child'); + root.appendChild(child); + assert_equals(serialize(root), '<root xmlns:p="uri2"><p:child xmlns:p="uri1"/></root>'); +}, 'Check if start tag serialization applied the original prefix even if it is declared in an ancestor element.'); + +// https://github.com/w3c/DOM-Parsing/issues/52 +test(function() { + assert_equals(serialize(parse('<root xmlns:x="uri1"><table xmlns="uri1"></table></root>')), + '<root xmlns:x="uri1"><x:table xmlns="uri1"/></root>'); +}, 'Check if start tag serialization does NOT apply the default namespace if its namespace is declared in an ancestor.'); + +test(function() { + const root = parse('<root><child1/><child2/></root>'); + root.firstChild.setAttributeNS('uri1', 'attr1', 'value1'); + root.firstChild.setAttributeNS('uri2', 'attr2', 'value2'); + root.lastChild.setAttributeNS('uri3', 'attr3', 'value3'); + assert_equals(serialize(root), '<root><child1 xmlns:ns1="uri1" ns1:attr1="value1" xmlns:ns2="uri2" ns2:attr2="value2"/><child2 xmlns:ns3="uri3" ns3:attr3="value3"/></root>'); +}, 'Check if generated prefixes match to "ns${index}".'); + +// https://github.com/w3c/DOM-Parsing/issues/44 +// According to 'DOM Parsing and Serialization' draft as of 2018-12-11, +// 'generate a prefix' result can conflict with an existing xmlns:ns* declaration. +test(function() { + const root = parse('<root xmlns:ns2="uri2"><child xmlns:ns1="uri1"/></root>'); + root.firstChild.setAttributeNS('uri3', 'attr1', 'value1'); + assert_equals(serialize(root), '<root xmlns:ns2="uri2"><child xmlns:ns1="uri1" xmlns:ns1="uri3" ns1:attr1="value1"/></root>'); +}, 'Check if "ns1" is generated even if the element already has xmlns:ns1.'); + +test(function() { + const root = (new Document()).createElement('root'); + root.setAttributeNS('http://www.w3.org/1999/xlink', 'href', 'v'); + assert_equals(serialize(root), '<root xmlns:ns1="http://www.w3.org/1999/xlink" ns1:href="v"/>'); + + const root2 = (new Document()).createElement('root'); + root2.setAttributeNS('http://www.w3.org/1999/xlink', 'xl:type', 'v'); + assert_equals(serialize(root2), '<root xmlns:xl="http://www.w3.org/1999/xlink" xl:type="v"/>'); +}, 'Check if no special handling for XLink namespace unlike HTML serializer.'); + +test(function() { + var root = new DocumentFragment; + root.append(document.createElement('div')); + root.append(document.createElement('span')); + assert_equals(serialize(root), '<div xmlns="http://www.w3.org/1999/xhtml"></div><span xmlns="http://www.w3.org/1999/xhtml"></span>'); +}, 'Check if document fragment serializes.'); + + +</script> + </body> +</html> diff --git a/testing/web-platform/tests/domparsing/createContextualFragment.html b/testing/web-platform/tests/domparsing/createContextualFragment.html new file mode 100644 index 0000000000..170c0c464d --- /dev/null +++ b/testing/web-platform/tests/domparsing/createContextualFragment.html @@ -0,0 +1,179 @@ +<!doctype html> +<title>createContextualFragment() tests</title> +<div id=log></div> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +// We are not testing XML documents here, because apparently it's not clear +// what we want to happen there. We also aren't testing the HTML parser in any +// depth, just some basic sanity checks. + +// Exception-throwing +test(function() { + var range = document.createRange(); + range.detach(); + range.createContextualFragment(""); +}, "Must not throw INVALID_STATE_ERR for a detached node."); + +test(function() { + var range = document.createRange(); + assert_throws_js(TypeError, function() { + range.createContextualFragment(); + }); +}, "Must throw TypeError when calling without arguments"); + +test(function() { + // Simple test + var range = document.createRange(); + range.selectNodeContents(document.body); + + var fragment = "<p CLaSs=testclass> Hi! <p>Hi!"; + var expected = document.createDocumentFragment(); + var tmpNode = document.createElement("p"); + tmpNode.setAttribute("class", "testclass"); + tmpNode.appendChild(document.createTextNode(" Hi! ")); + expected.appendChild(tmpNode); + + tmpNode = document.createElement("p"); + tmpNode.appendChild(document.createTextNode("Hi!")); + expected.appendChild(tmpNode); + + var result = range.createContextualFragment(fragment); + assert_true(expected.isEqualNode(result), + "Unexpected result (collapsed Range)"); + + // Token test that the end node makes no difference + range.setEnd(document.body.getElementsByTagName("script")[0], 0); + result = range.createContextualFragment(fragment); + assert_true(expected.isEqualNode(result), + "Unexpected result (Range ends in <script>)"); +}, "Simple test with paragraphs"); + +test(function() { + // This test based on https://bugzilla.mozilla.org/show_bug.cgi?id=585819, + // from a real-world compat bug + var range = document.createRange(); + range.selectNodeContents(document.documentElement); + var fragment = "<span>Hello world</span>"; + var expected = document.createDocumentFragment(); + var tmpNode = document.createElement("span"); + tmpNode.appendChild(document.createTextNode("Hello world")); + expected.appendChild(tmpNode); + + var result = range.createContextualFragment(fragment); + assert_true(expected.isEqualNode(result), + "Unexpected result (collapsed Range)"); + + // Another token test that the end node makes no difference + range.setEnd(document.head, 0); + result = range.createContextualFragment(fragment); + assert_true(expected.isEqualNode(result), + "Unexpected result (Range ends in <head>)"); +}, "Don't auto-create <body> when applied to <html>"); + +// Scripts should be run if inserted (that's what the "Unmark all scripts +// . . ." line means, I'm told) +var passed = false; +test(function() { + assert_false(passed, "Sanity check"); + var range = document.createRange(); + range.selectNodeContents(document.documentElement); + var fragment = range.createContextualFragment("<script>passed = true</s" + "cript>"); + assert_false(passed, "Fragment created but not yet added to document, should not have run"); + document.body.appendChild(fragment); + assert_true(passed, "Fragment created and added to document, should run"); +}, "<script>s should be run when appended to the document (but not before)"); + +// Historical bugs in browsers; see https://github.com/whatwg/html/issues/2222 + +[ + // Void + "area", + "base", + "basefont", + "bgsound", + "br", + "col", + "embed", + "frame", + "hr", + "img", + "input", + "keygen", + "link", + "meta", + "param", + "source", + "track", + "wbr", + + // Historical + "menuitem", + "image" +].forEach(name => { + test(() => { + const range = document.createRange(); + const contextNode = document.createElement(name); + const selectedNode = document.createElement("div"); + contextNode.appendChild(selectedNode); + range.selectNode(selectedNode); + + range.createContextualFragment("some text"); + }, `createContextualFragment should work even when the context is <${name}>`); +}); + + +// Now that we've established basic sanity, let's do equivalence tests. Those +// are easier to write anyway. +function testEquivalence(element1, fragment1, element2, fragment2) { + var range1 = element1.ownerDocument.createRange(); + range1.selectNodeContents(element1); + var range2 = element2.ownerDocument.createRange(); + range2.selectNodeContents(element2); + + var result1 = range1.createContextualFragment(fragment1); + var result2 = range2.createContextualFragment(fragment2); + + assert_true(result1.isEqualNode(result2), "Results are supposed to be equivalent"); + + // Throw in partial ownerDocument tests on the side, since the algorithm + // does specify that and we don't want to completely not test it. + if (result1.firstChild != null) { + assert_equals(result1.firstChild.ownerDocument, element1.ownerDocument, + "ownerDocument must be set to that of the reference node"); + } + if (result2.firstChild != null) { + assert_equals(result2.firstChild.ownerDocument, element2.ownerDocument, + "ownerDocument must be set to that of the reference node"); + } +} + +var doc_fragment = document.createDocumentFragment(); +var comment = document.createComment("~o~"); +doc_fragment.appendChild(comment); + +var tests = [ + ["<html> and <body> must work the same, 1", document.documentElement, "<span>Hello world</span>", document.body, "<span>Hello world</span>"], + ["<html> and <body> must work the same, 2", document.documentElement, "<body><p>Hello world", document.body, "<body><p>Hello world"], + ["Implicit <body> creation", document.documentElement, "<body><p>", document.documentElement, "<p>"], + ["Namespace generally shouldn't matter", + document.createElementNS("http://fake-namespace", "div"), "<body><p><span>Foo", + document.createElement("div"), "<body><p><span>Foo"], + ["<html> in a different namespace shouldn't be special", + document.createElementNS("http://fake-namespace", "html"), "<body><p>", + document.createElement("div"), "<body><p>"], + ["SVG namespace shouldn't be special", + document.createElementNS("http://www.w3.org/2000/svg", "div"), "<body><p>", + document.createElement("div"), "<body><p>"], + ["null should be stringified", document.createElement("span"), null, document.createElement("span"), "null"], + ["undefined should be stringified", document.createElement("span"), undefined, document.createElement("span"), "undefined"], + ["Text nodes shouldn't be special", + document.createTextNode("?"), "<body><p>", + document.createElement("div"), "<body><p>"], + ["Non-Element parent should not be special", + comment, "<body><p>", + document.createElement("div"), "<body><p>"] +]; + +generate_tests(testEquivalence, tests); +</script> diff --git a/testing/web-platform/tests/domparsing/idlharness.window.js b/testing/web-platform/tests/domparsing/idlharness.window.js new file mode 100644 index 0000000000..f5f32b3bb5 --- /dev/null +++ b/testing/web-platform/tests/domparsing/idlharness.window.js @@ -0,0 +1,18 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +'use strict'; + +// https://w3c.github.io/DOM-Parsing/ + +idl_test( + ['DOM-Parsing'], + ['dom'], + idlArray => { + idlArray.add_objects({ + Element: ['document.createElement("div")'], + Range: ['new Range()'], + XMLSerializer: ['new XMLSerializer()'], + }) + } +); diff --git a/testing/web-platform/tests/domparsing/innerhtml-01.xhtml b/testing/web-platform/tests/domparsing/innerhtml-01.xhtml new file mode 100644 index 0000000000..08345ac58b --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-01.xhtml @@ -0,0 +1,28 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>innerHTML in XHTML: getting while the document is in an invalid state</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML"/> +<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/> +<link rel="help" href="http://www.whatwg.org/html5/#document.title"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +test(function() { + document.documentElement.appendChild(document.createElement("test:test")); + assert_throws_dom("INVALID_STATE_ERR", function() { + document.documentElement.innerHTML; + }, "getting element with \":\" in its local name"); +}); +test(function() { + document.title = "\f"; + assert_throws_dom("INVALID_STATE_ERR", function() { + document.getElementsByTagName("title")[0].innerHTML; + }, "Getting a Text node whose data contains characters that are not matched by the XML Char production"); +}); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/innerhtml-03.xhtml b/testing/web-platform/tests/domparsing/innerhtml-03.xhtml new file mode 100644 index 0000000000..313531e49c --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-03.xhtml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>innerHTML in XHTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="http://html5.org/specs/dom-parsing.html#dom-innerhtml"/> +<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script><![CDATA[ +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createElement("xmp")) + .appendChild(document.createElement("span")) + .appendChild(document.createTextNode("<")); + assert_equals(el.innerHTML, "<xmp xmlns=\"http://www.w3.org/1999/xhtml\"><span><<\/span><\/xmp>"); +}) +test(function() { + var el = document.createElement("xmp"); + el.appendChild(document.createElement("span")) + .appendChild(document.createTextNode("<")); + assert_equals(el.innerHTML, "<span xmlns=\"http://www.w3.org/1999/xhtml\"><<\/span>"); +}) +test(function() { + var el = document.createElement("xmp"); + el.appendChild(document.createTextNode("<")); + assert_equals(el.innerHTML, "<"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createElement("br")); + assert_equals(el.innerHTML, "<br xmlns=\"http://www.w3.org/1999/xhtml\" />"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "html:br")); + assert_equals(el.innerHTML, "<html:br xmlns:html=\"http://www.w3.org/1999/xhtml\" />"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createTextNode("<>\"'&")); + assert_equals(el.innerHTML, "<>\"'&"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createTextNode("<>"'&")); + assert_equals(el.innerHTML, "&lt;&gt;&quot;&apos;&amp;"); +}) +test(function() { + var el = document.createElement("div"); + el.appendChild(document.createTextNode("àו…\u00A0")); + assert_equals(el.innerHTML, "àו…\u00A0"); +}) +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/innerhtml-04.html b/testing/web-platform/tests/domparsing/innerhtml-04.html new file mode 100644 index 0000000000..32c921d235 --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-04.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<title>innerHTML in HTML</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +function testIsChild(p, c) { + assert_equals(p.firstChild, c); + assert_equals(c.parentNode, p); +} +test(function() { + var p = document.createElement('p'); + var b = p.appendChild(document.createElement('b')); + var t = b.appendChild(document.createTextNode("foo")); + testIsChild(p, b); + testIsChild(b, t); + assert_equals(t.data, "foo"); + p.innerHTML = ""; + testIsChild(b, t); + assert_equals(t.data, "foo"); +}, "innerHTML should leave the removed children alone.") +</script> diff --git a/testing/web-platform/tests/domparsing/innerhtml-05.xhtml b/testing/web-platform/tests/domparsing/innerhtml-05.xhtml new file mode 100644 index 0000000000..3afb681523 --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-05.xhtml @@ -0,0 +1,26 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> +<title>innerHTML in XHTML</title> +<link rel="author" title="Simon Pieters" href="mailto:simonp@opera.com"/> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"/> +<link rel="help" href="http://html5.org/specs/dom-parsing.html#dom-innerhtml"/> +<link rel="help" href="http://www.whatwg.org/html5/#xml-fragment-serialization-algorithm"/> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<iframe src="data:text/xml,<html xmlns='http://www.w3.org/1999/xhtml'><foo--/></html>"></iframe> +<script><![CDATA[ +var t = async_test(); +window.onload = t.step_func(function() { + var foo = window[0].document.documentElement.firstChild; + assert_throws_dom('SyntaxError', function() { + foo.innerHTML = 'x<\/foo--><\!--y'; + // This is ridiculous. + }); + t.done(); +}); +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/innerhtml-06.html b/testing/web-platform/tests/domparsing/innerhtml-06.html new file mode 100644 index 0000000000..81e9c57b5c --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-06.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<title>math in html: innerHTML</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<h1>math in html: innerHTML</h1> +<div id="log"></div> +<div style="display:none"> +<div id="d1"><math><mi>x</mi></math></div> +</div> +<script> +test(function() { + var math = document.getElementById("d1").firstChild; + assert_equals(math.innerHTML, "<mi>x</mi>"); +},"innerHTML defined on math."); +</script> diff --git a/testing/web-platform/tests/domparsing/innerhtml-07.html b/testing/web-platform/tests/domparsing/innerhtml-07.html new file mode 100644 index 0000000000..b48b421eff --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-07.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<title>innerHTML and string conversion</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var p = document.createElement("p"); + p.innerHTML = null; + assert_equals(p.innerHTML, ""); + assert_equals(p.textContent, ""); +}, "innerHTML and string conversion: null.") + +test(function() { + var p = document.createElement("p"); + p.innerHTML = undefined; + assert_equals(p.innerHTML, "undefined"); + assert_equals(p.textContent, "undefined"); +}, "innerHTML and string conversion: undefined.") + +test(function() { + var p = document.createElement("p"); + p.innerHTML = 42; + assert_equals(p.innerHTML, "42"); + assert_equals(p.textContent, "42"); +}, "innerHTML and string conversion: number.") + +test(function() { + var p = document.createElement("p"); + p.innerHTML = { + toString: function() { return "pass"; }, + valueOf: function() { return "fail"; } + }; + assert_equals(p.innerHTML, "pass"); + assert_equals(p.textContent, "pass"); +}, "innerHTML and string conversion: toString.") + +test(function() { + var p = document.createElement("p"); + p.innerHTML = { + toString: undefined, + valueOf: function() { return "pass"; } + }; + assert_equals(p.innerHTML, "pass"); + assert_equals(p.textContent, "pass"); +}, "innerHTML and string conversion: valueOf.") +</script> diff --git a/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html b/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html new file mode 100644 index 0000000000..7563d892d9 --- /dev/null +++ b/testing/web-platform/tests/domparsing/innerhtml-mxss.sub.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<head> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> + <div><a></a></div> + <script> + var whitespaces = [ + "1680", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", + "2008", "2009", "200a", "2028", "205f", "3000" + ]; + + for (var i = 0; i < whitespaces.length; i++) { + var container = document.querySelector('a').parentNode; + var entity = `&#x${whitespaces[i]};`; + var character = String.fromCharCode(parseInt(whitespaces[i], 16)); + var url = encodeURIComponent(character); + container.innerHTML = `<a href="${entity}javascript:alert(1)">Link</a>`; + + var a = document.querySelector('a'); + + test(_ => { + assert_equals( + container.innerHTML, + `<a href="${character}javascript:alert(1)">Link</a>`); + }, `innerHTML before setter: ${whitespaces[i]}`); + test(_ => { + assert_equals( + a.href, + `http://{{host}}:{{ports[http][0]}}/domparsing/${url}javascript:alert(1)`); + }, `href before setter: ${whitespaces[i]}`); + + a.parentNode.innerHTML += 'foo'; + a = document.querySelector('a'); + + test(_ => { + assert_equals( + container.innerHTML, + `<a href="${character}javascript:alert(1)">Link</a>foo`); + }, `innerHTML after setter: ${whitespaces[i]}`); + test(_ => { + assert_equals( + a.href, + `http://{{host}}:{{ports[http][0]}}/domparsing/${url}javascript:alert(1)`); + }, `href after setter: ${whitespaces[i]}`); + } + </script> +</body> diff --git a/testing/web-platform/tests/domparsing/insert-adjacent.html b/testing/web-platform/tests/domparsing/insert-adjacent.html new file mode 100644 index 0000000000..f43ec406e4 --- /dev/null +++ b/testing/web-platform/tests/domparsing/insert-adjacent.html @@ -0,0 +1,38 @@ +<!doctype html> +<title>insertAdjacentHTML</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<style> +#element { + display: none; +} +</style> + +<div id="element"></div> +<div id="log"></div> + +<script> +function wrap(text) { + return '<h3>' + text + '</h3>'; +} + +var possiblePositions = { + 'beforebegin': 'previousSibling' + , 'afterbegin': 'firstChild' + , 'beforeend': 'lastChild' + , 'afterend': 'nextSibling' +} + +var el = document.querySelector('#element'); + +Object.keys(possiblePositions).forEach(function(position) { + var html = wrap(position); + test(function() { + el.insertAdjacentHTML(position, html); + var heading = document.createElement('h3'); + heading.innerHTML = position; + assert_equals(el[possiblePositions[position]].nodeName, "H3"); + assert_equals(el[possiblePositions[position]].firstChild.nodeType, Node.TEXT_NODE); + }, 'insertAdjacentHTML(' + position + ', ' + html + ' )'); +}); +</script> diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml b/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml new file mode 100644 index 0000000000..f02f425c47 --- /dev/null +++ b/testing/web-platform/tests/domparsing/insert_adjacent_html-xhtml.xhtml @@ -0,0 +1,91 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>insertAdjacentHTML in HTML</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="insert_adjacent_html.js"></script> +</head> +<body> +<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div> +<script><![CDATA[ +var script_ran = false; + +function testPositions(node, testDesc) { + test(function() { + script_ran = false; + node.insertAdjacentHTML("beforeBegin", "\u003Cscript>script_ran = true;\u003C/script><i></i>"); + assert_equals(node.previousSibling.localName, "i", "Should have had <i> as previous sibling"); + assert_equals(node.previousSibling.previousSibling.localName, "script", "Should have had <script> as second previous child"); + assert_false(script_ran, "script should not have run"); + }, "beforeBegin " + node.id + " " + testDesc) + + test(function() { + script_ran = false; + node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>script_ran = true;\u003C/script>"); + assert_equals(node.firstChild.localName, "b", "Should have had <b> as first child"); + assert_equals(node.firstChild.nextSibling.localName, "script", "Should have had <script> as second child"); + assert_false(script_ran, "script should not have run"); + }, "Afterbegin " + node.id + " " + testDesc); + + test(function() { + script_ran = false; + node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>script_ran = true;\u003C/script><u></u>"); + assert_equals(node.lastChild.localName, "u", "Should have had <u> as last child"); + assert_equals(node.lastChild.previousSibling.localName, "script", "Should have had <script> as penultimate child"); + assert_false(script_ran, "script should not have run"); + }, "BeforeEnd " + node.id + " " + testDesc) + + test(function() { + script_ran = false; + node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>script_ran = true;\u003C/script>"); + assert_equals(node.nextSibling.localName, "a", "Should have had <a> as next sibling"); + assert_equals(node.nextSibling.nextSibling.localName, "script", "Should have had <script> as second next sibling"); + assert_false(script_ran, "script should not have run"); + }, "afterend " + node.id + " " + testDesc) +} + +var content = document.getElementById("content"); +testPositions(content, "without next sibling"); +testPositions(content, "again, with next sibling"); + +test(function() { + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("bar", "foo")}); + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegİn", "foo")}); + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegın", "foo")}); +}, "Should throw when inserting with invalid position string"); + +var parentElement = document.createElement("div"); +var child = document.createElement("div"); +child.id = "child"; + +testThrowingNoParent(child, "null"); +testThrowingNoParent(document.documentElement, "a document"); + +test(function() { + child.insertAdjacentHTML("afterBegin", "foo"); + child.insertAdjacentHTML("beforeend", "bar"); + assert_equals(child.textContent, "foobar"); + parentElement.appendChild(child); +}, "Inserting after being and before end should order things correctly"); + +testPositions(child, "node not in tree but has parent"); + +test(function() { + script_ran = false; + content.appendChild(parentElement); // must not run scripts + assert_false(script_ran, "script should not have run"); +}, "Should not run script when appending things which have descendant <script> inserted via insertAdjacentHTML"); + +var content2 = document.getElementById("content2"); +testPositions(content2, "without next sibling"); +testPositions(content2, "test again, now that there's a next sibling"); + +// XML-only: +test(function() { + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforeend", "<p>")}); +}); + +]]></script> +<div id="log"></div> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html.html b/testing/web-platform/tests/domparsing/insert_adjacent_html.html new file mode 100644 index 0000000000..d8b3874819 --- /dev/null +++ b/testing/web-platform/tests/domparsing/insert_adjacent_html.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>insertAdjacentHTML in HTML</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="insert_adjacent_html.js"></script> +</head> +<body> +<p id="display"></p><div id="content" style="display: none"></div><div id="content2" style="display: none"></div> +<script> +var script_ran = false; + +function testPositions(node, testDesc) { + test(function() { + script_ran = false; + node.insertAdjacentHTML("beforeBegin", "\u003Cscript>script_ran = true;\u003C/script><i></i>"); + assert_equals(node.previousSibling.localName, "i", "Should have had <i> as previous sibling"); + assert_equals(node.previousSibling.previousSibling.localName, "script", "Should have had <script> as second previous child"); + assert_false(script_ran, "script should not have run"); + }, "beforeBegin " + node.id + " " + testDesc) + + test(function() { + script_ran = false; + node.insertAdjacentHTML("Afterbegin", "<b></b>\u003Cscript>script_ran = true;\u003C/script>"); + assert_equals(node.firstChild.localName, "b", "Should have had <b> as first child"); + assert_equals(node.firstChild.nextSibling.localName, "script", "Should have had <script> as second child"); + assert_false(script_ran, "script should not have run"); + }, "Afterbegin " + node.id + " " + testDesc); + + test(function() { + script_ran = false; + node.insertAdjacentHTML("BeforeEnd", "\u003Cscript>script_ran = true;\u003C/script><u></u>"); + assert_equals(node.lastChild.localName, "u", "Should have had <u> as last child"); + assert_equals(node.lastChild.previousSibling.localName, "script", "Should have had <script> as penultimate child"); + assert_false(script_ran, "script should not have run"); + }, "BeforeEnd " + node.id + " " + testDesc) + + test(function() { + script_ran = false; + node.insertAdjacentHTML("afterend", "<a></a>\u003Cscript>script_ran = true;\u003C/script>"); + assert_equals(node.nextSibling.localName, "a", "Should have had <a> as next sibling"); + assert_equals(node.nextSibling.nextSibling.localName, "script", "Should have had <script> as second next sibling"); + assert_false(script_ran, "script should not have run"); + }, "afterend " + node.id + " " + testDesc) +} + +var content = document.getElementById("content"); +testPositions(content, "without next sibling"); +testPositions(content, "again, with next sibling"); + +test(function() { + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("bar", "foo")}); + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegİn", "foo")}); + assert_throws_dom("SYNTAX_ERR", function() {content.insertAdjacentHTML("beforebegın", "foo")}); +}, "Should throw when inserting with invalid position string"); + +var parentElement = document.createElement("div"); +var child = document.createElement("div"); +child.id = "child"; + +testThrowingNoParent(child, "null"); +testThrowingNoParent(document.documentElement, "a document"); + +test(function() { + child.insertAdjacentHTML("afterBegin", "foo"); + child.insertAdjacentHTML("beforeend", "bar"); + assert_equals(child.textContent, "foobar"); + parentElement.appendChild(child); +}, "Inserting after being and before end should order things correctly"); + +testPositions(child, "node not in tree but has parent"); + +test(function() { + script_ran = false; + content.appendChild(parentElement); // must not run scripts + assert_false(script_ran, "script should not have run"); +}, "Should not run script when appending things which have descendant <script> inserted via insertAdjacentHTML"); + +var content2 = document.getElementById("content2"); +testPositions(content2, "without next sibling"); +testPositions(content2, "test again, now that there's a next sibling"); + +// HTML only +test(function() { + document.body.insertAdjacentHTML("afterend", "<p>"); + document.head.insertAdjacentHTML("beforebegin", "<p>"); + assert_equals(document.getElementsByTagName("head").length, 1, "Should still have one head"); + assert_equals(document.getElementsByTagName("body").length, 1, "Should still have one body"); +}, "Inserting kids of the <html> element should not do weird things with implied <body>/<head> tags") +</script> +<div id="log"></div> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/insert_adjacent_html.js b/testing/web-platform/tests/domparsing/insert_adjacent_html.js new file mode 100644 index 0000000000..2980037433 --- /dev/null +++ b/testing/web-platform/tests/domparsing/insert_adjacent_html.js @@ -0,0 +1,33 @@ +function testThrowingNoParent(element, desc) { + test(function() { + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("afterend", "") } + ); + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("beforebegin", "") } + ); + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("afterend", "foo") } + ); + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("beforebegin", "foo") } + ); + }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (text)"); + test(function() { + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("afterend", "<!-- fail -->") } + ); + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("beforebegin", "<!-- fail -->") } + ); + }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (comments)"); + test(function() { + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("afterend", "<div></div>") } + ); + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", + function() { element.insertAdjacentHTML("beforebegin", "<div></div>") } + ); + }, "When the parent node is " + desc + ", insertAdjacentHTML should throw for beforebegin and afterend (elements)"); +} + diff --git a/testing/web-platform/tests/domparsing/outerhtml-01.html b/testing/web-platform/tests/domparsing/outerhtml-01.html new file mode 100644 index 0000000000..d9a38b7045 --- /dev/null +++ b/testing/web-platform/tests/domparsing/outerhtml-01.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<title>outerHTML: child of #document</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="http://html5.org/specs/dom-parsing.html#outerhtml"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + assert_throws_dom("NO_MODIFICATION_ALLOWED_ERR", function() { + document.documentElement.outerHTML = "<html><p>FAIL: Should have thrown an error<\/p><\/html>"; + }) +}); +</script> + diff --git a/testing/web-platform/tests/domparsing/outerhtml-02.html b/testing/web-platform/tests/domparsing/outerhtml-02.html new file mode 100644 index 0000000000..1ce5df03e4 --- /dev/null +++ b/testing/web-platform/tests/domparsing/outerhtml-02.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<title>outerHTML and string conversion</title> +<link rel="author" title="Ms2ger" href="mailto:ms2ger@gmail.com"> +<link rel="help" href="https://w3c.github.io/DOM-Parsing/#extensions-to-the-element-interface"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var div = document.createElement("div"); + var p = div.appendChild(document.createElement("p")); + p.outerHTML = null; + assert_equals(div.innerHTML, ""); + assert_equals(div.textContent, ""); +}, "outerHTML and string conversion: null.") + +test(function() { + var div = document.createElement("div"); + var p = div.appendChild(document.createElement("p")); + p.outerHTML = undefined; + assert_equals(div.innerHTML, "undefined"); + assert_equals(div.textContent, "undefined"); +}, "outerHTML and string conversion: undefined.") + +test(function() { + var div = document.createElement("div"); + var p = div.appendChild(document.createElement("p")); + p.outerHTML = 42; + assert_equals(div.innerHTML, "42"); + assert_equals(div.textContent, "42"); +}, "outerHTML and string conversion: number.") + +test(function() { + var div = document.createElement("div"); + var p = div.appendChild(document.createElement("p")); + p.outerHTML = { + toString: function() { return "pass"; }, + valueOf: function() { return "fail"; } + }; + assert_equals(div.innerHTML, "pass"); + assert_equals(div.textContent, "pass"); +}, "outerHTML and string conversion: toString.") + +test(function() { + var div = document.createElement("div"); + var p = div.appendChild(document.createElement("p")); + p.outerHTML = { + toString: undefined, + valueOf: function() { return "pass"; } + }; + assert_equals(div.innerHTML, "pass"); + assert_equals(div.textContent, "pass"); +}, "outerHTML and string conversion: valueOf.") +</script> diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html new file mode 100644 index 0000000000..9c4a1bd07a --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base-pushstate.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does DOMParser stuff with base and pushstates itself</title> +<base href="/fake/base-from-iframe"> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-iframe"); +</script> +<script src="/domparsing/resources/domparser-iframe.js"></script> diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html new file mode 100644 index 0000000000..e8a084b7dc --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-base.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does DOMParser stuff with base</title> +<base href="/fake/base-from-iframe"> + +<script src="/domparsing/resources/domparser-iframe.js"></script> diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html new file mode 100644 index 0000000000..b2821c6994 --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe-pushstate.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does DOMParser stuff and pushstates itself</title> + +<script> +"use strict"; +history.pushState(null, "", "/fake/push-state-from-iframe"); +</script> +<script src="/domparsing/resources/domparser-iframe.js"></script> diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe.html b/testing/web-platform/tests/domparsing/resources/domparser-iframe.html new file mode 100644 index 0000000000..710f141bb9 --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>An iframe that does DOMParser stuff</title> +<script src="/domparsing/resources/domparser-iframe.js"></script> diff --git a/testing/web-platform/tests/domparsing/resources/domparser-iframe.js b/testing/web-platform/tests/domparsing/resources/domparser-iframe.js new file mode 100644 index 0000000000..a62d2f293b --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-iframe.js @@ -0,0 +1,4 @@ +window.doParse = (html, mimeType) => { + const parser = new DOMParser(); + return parser.parseFromString(html, mimeType); +}; diff --git a/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js b/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js new file mode 100644 index 0000000000..7b02fab1c3 --- /dev/null +++ b/testing/web-platform/tests/domparsing/resources/domparser-url-tests.js @@ -0,0 +1,72 @@ +const loadPromise = new Promise(resolve => { window.resolveLoadPromise = resolve; }); + +function assertURL(doc, expectedURL) { + assert_equals(doc.URL, expectedURL, "document.URL"); + assert_equals(doc.documentURI, expectedURL, "document.documentURI"); + assert_equals(doc.baseURI, expectedURL, "document.baseURI"); +} + +const supportedTypes = [ + "text/html", + "text/xml", + "application/xml", + "application/xhtml+xml", + "image/svg+xml", +]; + +const invalidXML = `<span x:test="testing">1</span>`; +const inputs = { + valid: "<html></html>", + "invalid XML": invalidXML +}; + +for (const mimeType of supportedTypes) { + for (const [inputName, input] of Object.entries(inputs)) { + if (mimeType === "text/html" && input === invalidXML) { + continue; + } + + test(() => { + const parser = new DOMParser(); + const doc = parser.parseFromString(input, mimeType); + + assertURL(doc, document.URL); + }, `${mimeType} ${inputName}: created normally`); + + promise_test(async () => { + await loadPromise; + + const parser = new frames[0].DOMParser(); + const doc = parser.parseFromString(input, mimeType); + + assertURL(doc, frames[0].document.URL); + }, `${mimeType} ${inputName}: created using another iframe's DOMParser from this frame`); + + promise_test(async () => { + await loadPromise; + + const parser = new frames[0].DOMParser(); + const doc = frames[0].doParse(input, mimeType); + + assertURL(doc, frames[0].document.URL); + }, `${mimeType} ${inputName}: created using another iframe's DOMParser from that frame`); + + promise_test(async () => { + await loadPromise; + + const parser = new DOMParser(); + const doc = frames[0].DOMParser.prototype.parseFromString.call(parser, input, mimeType); + + assertURL(doc, document.URL); + }, `${mimeType} ${inputName}: created using a parser from this frame and the method from the iframe`); + + promise_test(async () => { + await loadPromise; + + const parser = new frames[0].DOMParser(); + const doc = DOMParser.prototype.parseFromString.call(parser, input, mimeType); + + assertURL(doc, frames[0].document.URL); + }, `${mimeType} ${inputName}: created using a parser from the iframe and the method from this frame`); + } +} diff --git a/testing/web-platform/tests/domparsing/style_attribute_html.html b/testing/web-platform/tests/domparsing/style_attribute_html.html new file mode 100644 index 0000000000..f7f057d2d8 --- /dev/null +++ b/testing/web-platform/tests/domparsing/style_attribute_html.html @@ -0,0 +1,52 @@ +<!doctype html> +<meta charset=utf-8> +<title>Style attribute in HTML</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> + +var div; +setup(function() { + var input = '<div style="color: red">Foo</div>'; + var doc = (new DOMParser()).parseFromString(input, 'text/html'); + div = doc.querySelector('div'); +}); + +test(function() { + var style = div.style; + assert_equals(style.cssText, 'color: red;'); + assert_equals(style.color, 'red'); + assert_equals(div.getAttribute("style"), 'color: red', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of initial style attribute'); + +test(function() { + var style = div.style; + div.setAttribute('style', 'color:: invalid'); + assert_equals(style.cssText, ''); + assert_equals(style.color, ''); + assert_equals(div.getAttribute('style'), 'color:: invalid', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of invalid style attribute'); + +test(function() { + var style = div.style; + div.setAttribute('style', 'color: green'); + assert_equals(style.cssText, 'color: green;'); + assert_equals(style.color, 'green'); + assert_equals(div.getAttribute('style'), 'color: green', + 'Value of style attribute should match the string value that was set'); +}, 'Parsing of style attribute'); + +test(function() { + var style = div.style; + style.backgroundColor = 'blue'; + assert_equals(style.cssText, 'color: green; background-color: blue;', + 'Should not drop the existing style'); + assert_equals(style.color, 'green', + 'Should not drop the existing style'); + assert_equals(div.getAttribute('style'), 'color: green; background-color: blue;', + 'Should update style attribute'); +}, 'Update style.backgroundColor'); + +</script> diff --git a/testing/web-platform/tests/domparsing/xml-serialization.xhtml b/testing/web-platform/tests/domparsing/xml-serialization.xhtml new file mode 100644 index 0000000000..852bbcc9fd --- /dev/null +++ b/testing/web-platform/tests/domparsing/xml-serialization.xhtml @@ -0,0 +1,103 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>XML serialization</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script><![CDATA[ +function serialize(node) { + var serializer = new XMLSerializer(); + return serializer.serializeToString(node); +} + +test(function() { + var dt = document.createComment("--"); + assert_equals(serialize(dt), '<!------>'); +}, "Comment: containing --"); + +test(function() { + var dt = document.createComment("- x"); + assert_equals(serialize(dt), '<!--- x-->'); +}, "Comment: starting with -"); + +test(function() { + var dt = document.createComment("x -"); + assert_equals(serialize(dt), '<!--x --->'); +}, "Comment: ending with -"); + +test(function() { + var dt = document.createComment("-->"); + assert_equals(serialize(dt), '<!---->-->'); +}, "Comment: containing -->"); + +test(function() { + var dt = document.implementation.createDocumentType("html", "", ""); + assert_equals(serialize(dt), '<!DOCTYPE html>'); +}, "DocumentType: empty public and system id"); + +test(function() { + var dt = document.implementation.createDocumentType("html", "a", ""); + assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC "a">'); +}, "DocumentType: empty system id"); + +test(function() { + var dt = document.implementation.createDocumentType("html", "", "a"); + assert_equals(serialize(dt), '<!DOCTYPE html SYSTEM "a">'); +}, "DocumentType: empty public id"); + +test(function() { + var dt = document.implementation.createDocumentType("html", "a", "b"); + assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC "a" "b">'); +}, "DocumentType: non-empty public and system id"); + +test(function() { + var dt = document.implementation.createDocumentType("html", "'", "'"); + assert_equals(serialize(dt), "<!DOCTYPE html PUBLIC \"'\" \"'\">"); +}, "DocumentType: 'APOSTROPHE' (U+0027)"); + +test(function() { + var dt = document.implementation.createDocumentType("html", '"', '"'); + assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC """ """>'); +}, "DocumentType: 'QUOTATION MARK' (U+0022)"); + +test(function() { + var dt = document.implementation.createDocumentType("html", '"\'', '\'"'); + assert_equals(serialize(dt), '<!DOCTYPE html PUBLIC ""\'" "\'"">'); +}, "DocumentType: 'APOSTROPHE' (U+0027) and 'QUOTATION MARK' (U+0022)"); + +test(function() { + var el = document.createElement("a"); + el.setAttribute("href", "\u3042\u3044\u3046 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"); + assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"\u3042\u3044\u3046 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>"); +}, "Element: href attributes are not percent-encoded"); + +test(function() { + var el = document.createElement("a"); + el.setAttribute("href", "?\u3042\u3044\u3046 !\"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"); + assert_equals(serialize(el), "<a xmlns=\"http://www.w3.org/1999/xhtml\" href=\"?\u3042\u3044\u3046 !"$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"></a>"); +}, "Element: query parts in href attributes are not percent-encoded"); + +test(function() { + var pi = document.createProcessingInstruction("a", ""); + assert_equals(serialize(pi), "<?a ?>"); +}, "ProcessingInstruction: empty data"); + +test(function() { + var pi = document.createProcessingInstruction("a", "b"); + assert_equals(serialize(pi), "<?a b?>"); +}, "ProcessingInstruction: non-empty data"); + +test(function() { + var pi = document.createProcessingInstruction("xml", "b"); + assert_equals(serialize(pi), "<?xml b?>"); +}, "ProcessingInstruction: target contains xml"); + +test(function() { + var pi = document.createProcessingInstruction("x:y", "b"); + assert_equals(serialize(pi), "<?x:y b?>"); +}, "ProcessingInstruction: target contains a 'COLON' (U+003A)"); +]]></script> +</body> +</html> diff --git a/testing/web-platform/tests/domparsing/xmldomparser.html b/testing/web-platform/tests/domparsing/xmldomparser.html new file mode 100644 index 0000000000..9dac65d305 --- /dev/null +++ b/testing/web-platform/tests/domparsing/xmldomparser.html @@ -0,0 +1,13 @@ +<!doctype html> +<meta charset="utf-8"> +<title>XML Dom Parse readyState Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + test(function () { + assert_equals( + (new DOMParser()).parseFromString("<html></html>", "text/xml").readyState, + "complete" + ); + }); +</script> diff --git a/testing/web-platform/tests/domxpath/001.html b/testing/web-platform/tests/domxpath/001.html new file mode 100644 index 0000000000..4931417af3 --- /dev/null +++ b/testing/web-platform/tests/domxpath/001.html @@ -0,0 +1,60 @@ +<!doctype html> +<meta charset="utf8"> +<title>XPath in text/html: elements</title> +<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="log"><span></span></div> +<div><span></span></div> +<dØdd></dØdd> +<svg> +<path /> +<path /> +</svg> + +<script> +function test_xpath_succeeds(path, expected, resolver) { + resolver = resolver ? resolver : null; + var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + actual = []; + for (var i=0;;i++) { + var node = res.snapshotItem(i); + if (node === null) { + break; + } + actual.push(node); + } + assert_array_equals(actual, expected); +} + +function test_xpath_throws(path, error_code, resolver) { + resolver = resolver ? resolver : null; + assert_throws_dom(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)}) +} + +function ns_resolver(x) { + map = {"html":"http://www.w3.org/1999/xhtml", + "svg":"http://www.w3.org/2000/svg", + "math":"http://www.w3.org/1998/Math/MathML"}; + var rv = map.hasOwnProperty(x) ? map[x] : null; + return rv; +} + +generate_tests(test_xpath_succeeds,[ + ["HTML elements no namespace prefix", "//div", document.getElementsByTagName("div")], + ["HTML elements namespace prefix", "//html:div", document.getElementsByTagName("div"), ns_resolver], + ["HTML elements mixed use of prefix", "//html:div/span", document.getElementsByTagName("span"), ns_resolver], + ["SVG elements no namespace prefix", "//path", []], + ["SVG elements namespace prefix", "//svg:path", document.getElementsByTagName("path"), ns_resolver], + ["HTML elements mixed case", "//DiV", document.getElementsByTagName("div")], + ["SVG elements mixed case selector", "//svg:PatH", [], ns_resolver], + ["Non-ascii HTML element", "//dØdd", document.getElementsByTagName("dØdd"), ns_resolver], + ["Non-ascii HTML element2", "//dødd", [], ns_resolver], + ["Non-ascii HTML element3", "//DØDD", document.getElementsByTagName("dØdd"), ns_resolver] +]) + +generate_tests(test_xpath_throws, [ + ["Throw with invalid prefix", "//invalid:path", "NAMESPACE_ERR"], +]) +</script> diff --git a/testing/web-platform/tests/domxpath/002.html b/testing/web-platform/tests/domxpath/002.html new file mode 100644 index 0000000000..c5c1fcc529 --- /dev/null +++ b/testing/web-platform/tests/domxpath/002.html @@ -0,0 +1,60 @@ +<!doctype html> +<meta charset="utf8"> +<title>XPath in text/html: attributes</title> +<link rel="help" href="http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#Interfaces"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="log" nonÄsciiAttribute><span></span></div> +<svg xmlns="http://www.w3.org/2000/svg", xmlns:xlink="http://www.w3.org/1999/xlink"> +<path id="a" refx /> +<path id="b" nonÄscii xlink:href /> +</svg> + +<script> +function test_xpath_succeeds(path, expected, resolver) { + resolver = resolver ? resolver : null; + var res = document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + actual = []; + for (var i=0;;i++) { + var node = res.snapshotItem(i); + if (node === null) { + break; + } + actual.push(node); + } + assert_array_equals(actual, expected); +} + +function test_xpath_throws(path, error_code, resolver) { + resolver = resolver ? resolver : null; + assert_throws_dom(error_code, function() {document.evaluate(path, document, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)}) +} + +function ns_resolver(x) { + map = {"html":"http://www.w3.org/1999/xhtml", + "svg":"http://www.w3.org/2000/svg", + "math":"http://www.w3.org/1998/Math/MathML", + "xlink":"http://www.w3.org/1999/xlink"}; + var rv = map.hasOwnProperty(x) ? map[x] : null; + return rv; +} + +generate_tests(test_xpath_succeeds,[ + ["Select html element based on attribute", "//div[@id='log']", [document.getElementById("log")]], + ["Select html element based on attribute mixed case", "//div[@Id='log']", [document.getElementById("log")]], + ["Select both HTML and SVG elements based on attribute", "//*[@id]", [document.getElementById("log")].concat(Array.prototype.slice.call(document.getElementsByTagName("path")))], + ["Select HTML element with non-ascii attribute 1", "//*[@nonÄsciiattribute]", [document.getElementById("log")]], + ["Select HTML element with non-ascii attribute 2", "//*[@nonäsciiattribute]", []], + ["Select HTML element with non-ascii attribute 3", "//*[@nonÄsciiAttribute]", [document.getElementById("log")]], + ["Select SVG element based on mixed case attribute", "//svg:path[@Id]", [], ns_resolver], + ["Select both HTML and SVG elements based on mixed case attribute", "//*[@Id]", [document.getElementById("log")]], + ["Select SVG elements with refX attribute", "//*[@refX]", [document.getElementById("a")]], + ["Select SVG elements with refX attribute incorrect case", "//*[@Refx]", []], + ["Select SVG elements with refX attribute lowercase", "//*[@refx]", []], + ["Select SVG element with non-ascii attribute 1", "//*[@nonÄscii]", [document.getElementById("b")]], + ["Select SVG element with non-ascii attribute 2", "//*[@nonäscii]", []], + ["xmlns attribute", "//*[@xmlns]", []], + ["svg element with XLink attribute", "//*[@xlink:href]", [document.getElementById("b")], ns_resolver] +]) +</script> diff --git a/testing/web-platform/tests/domxpath/META.yml b/testing/web-platform/tests/domxpath/META.yml new file mode 100644 index 0000000000..39abd8e706 --- /dev/null +++ b/testing/web-platform/tests/domxpath/META.yml @@ -0,0 +1,4 @@ +spec: https://www.w3.org/TR/DOM-Level-3-XPath/ +suggested_reviewers: + - zqzhang + - deniak diff --git a/testing/web-platform/tests/domxpath/README.md b/testing/web-platform/tests/domxpath/README.md new file mode 100644 index 0000000000..918997b164 --- /dev/null +++ b/testing/web-platform/tests/domxpath/README.md @@ -0,0 +1,9 @@ +# XPath + +This directory contains tests for [XPath](https://www.w3.org/TR/DOM-Level-3-XPath/). + +See [whatwg/dom#67](https://github.com/whatwg/dom/issues/67) for getting XPath +better specified. + +Because the XPath interfaces are defined in the DOM Standard, the idlharness.js +tests are in [/dom]([/dom) instead of here. diff --git a/testing/web-platform/tests/domxpath/booleans.html b/testing/web-platform/tests/domxpath/booleans.html new file mode 100644 index 0000000000..41522edf05 --- /dev/null +++ b/testing/web-platform/tests/domxpath/booleans.html @@ -0,0 +1,52 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#booleans"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_true(evaluateBoolean('(./span)[4] or ./br[2]', context)); +}, '"or" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_true(evaluateBoolean('count((./span)[3]) = count(./br[2])', context)); +}, '"=" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_false(evaluateBoolean('count((./span)[3]) != count(./br[2])', context)); +}, '"!=" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_true(evaluateBoolean('count((./span)[3]) < count(./br)', context)); +}, '"<" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_false(evaluateBoolean('count((./span)[3]) > count(./br[2])', context)); +}, '">" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_false(evaluateBoolean('count((./span)[3]) >= count(./br)', context)); +}, '">=" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_true(evaluateBoolean('count((./span)[3]) <= count(./br[2])', context)); +}, '"<=" operator depending on the context node'); + +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/document.tentative.html b/testing/web-platform/tests/domxpath/document.tentative.html new file mode 100644 index 0000000000..b75c0f0d66 --- /dev/null +++ b/testing/web-platform/tests/domxpath/document.tentative.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>XPath parent of documentElement</title> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<body> +<script> +test(function() { + var result = document.evaluate("..", // expression + document.documentElement, // context node + null, // resolver + XPathResult.ANY_TYPE, // type + null); // result + var matched = []; + var cur; + while ((cur = result.iterateNext()) !== null) { + matched.push(cur); + } + assert_array_equals(matched, [document]); + // Evaluate again, but reuse result from previous evaluation. + result = document.evaluate("..", // expression + document.documentElement, // context node + null, // resolver + XPathResult.ANY_TYPE, // type + result); // result + matched = []; + while ((cur = result.iterateNext()) !== null) { + matched.push(cur); + } + assert_array_equals(matched, [document]); +}); +</script> diff --git a/testing/web-platform/tests/domxpath/evaluator-constructor.html b/testing/web-platform/tests/domxpath/evaluator-constructor.html new file mode 100644 index 0000000000..8350ceb449 --- /dev/null +++ b/testing/web-platform/tests/domxpath/evaluator-constructor.html @@ -0,0 +1,16 @@ +<!doctype html> +<meta charset=utf-8> +<title>XPathEvaluator constructor</title> +<link rel=help href="http://wiki.whatwg.org/wiki/DOM_XPath"> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var x = new XPathEvaluator(); + assert_true(x instanceof XPathEvaluator); +}, "Constructor with 'new'"); +test(function() { + assert_throws_js(TypeError, "var x = XPathEvaluator()"); +}, "Constructor without 'new'"); +</script> diff --git a/testing/web-platform/tests/domxpath/fn-concat.html b/testing/web-platform/tests/domxpath/fn-concat.html new file mode 100644 index 0000000000..fe160966aa --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-concat.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-concat"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>foo</span><span>bar</span><b>ber</b>'; + assert_equals(evaluateString('concat((./span)[2], ./b)', context), 'barber'); +}, 'concat() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-contains.html b/testing/web-platform/tests/domxpath/fn-contains.html new file mode 100644 index 0000000000..a4d8bbfa7b --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-contains.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-contains"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>bar bar</span><span>bar<b>ber</b></span><b>bar</b>'; + assert_true(evaluateBoolean('contains((./span)[1], ./b)', context)); +}, 'contains() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-lang.html b/testing/web-platform/tests/domxpath/fn-lang.html new file mode 100644 index 0000000000..c7c102945d --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-lang.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-lang"> +<link rel="help" href="https://www.w3.org/TR/xpath-functions-31/#func-lang"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +// Set the context node to the first child of the root element, and evaluate +// the specified XPath expression. The test passes if +// - The first child element name is 'match' and XPath result is true, or +// - The first child element name is not 'match' and XPath result is false. +function testFirstChild(expression, xmlString) { + let doc = (new DOMParser()).parseFromString(xmlString, 'text/xml'); + test(() => { + let element = doc.documentElement.firstChild; + let result = doc.evaluate(expression, element, null, XPathResult.BOOLEAN_TYPE, null); + assert_equals(result.resultType, XPathResult.BOOLEAN_TYPE); + assert_equals(result.booleanValue, element.localName == 'match', element.outerHTML); + }, `${expression}: ${doc.documentElement.outerHTML}`); +} + +testFirstChild('lang("en")', '<root><match xml:lang="en"/></root>'); +testFirstChild('lang("en")', '<root><match xml:lang="EN"/></root>'); +testFirstChild('lang("en")', '<root><match xml:lang="en-us"/></root>'); +testFirstChild('lang("en")', '<root><unmatch/></root>'); + +// XPath 1.0 says: +// if the context node has no xml:lang attribute, by the value of the +// xml:lang attribute on the nearest ancestor of the context node that has +// an xml:lang attribute. +testFirstChild('lang("ja")', '<root xml:lang="ja"><match/></root>'); + +// XPath 1.0 says: +// if there is some suffix starting with - such that the attribute value is +// equal to the argument ignoring that suffix of the attribute value +testFirstChild('lang("ja")', '<root xml:lang="ja-jp"><unmatch xml:lang="ja_JP"/></root>'); + +// U+212A should match to ASCII 'k'. +// XPath 1.0 says: +// ... such that the attribute value is equal to the argument ignoring that suffix +// of the attribute value and ignoring case. +// XPath 3.1 says: +// ... true if and only if, based on a caseless default match as specified in +// section 3.13 of The Unicode Standard, +testFirstChild('lang("ko")', '<root><match xml:lang="Ko"/></root>'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-normalize-space.html b/testing/web-platform/tests/domxpath/fn-normalize-space.html new file mode 100644 index 0000000000..a9f33a0ee3 --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-normalize-space.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-normalize-space"> +<link rel="help" href="https://www.w3.org/TR/xpath-functions-31/#func-normalize-space"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<div id="target"> a <br> b</div> +<script> +function normalizeSpace(exp) { + return document.evaluate(`normalize-space("${exp}")`, document).stringValue; +} + +test(() => { + assert_equals(document.evaluate('normalize-space()', document.querySelector('#target')).stringValue, 'a b'); +}, 'normalize-space() without arguments'); + +test(() => { + assert_equals(normalizeSpace(' a \t b\r\nc '), 'a b c'); + + assert_equals(normalizeSpace('y\x0B\x0C\x0E\x0Fz'), 'y\x0b\x0c\x0e\x0fz'); + assert_equals(normalizeSpace('\xA0 \u3000'), '\xA0 \u3000'); +}, 'normalize-space() should handle only #x20, #x9, #xD, and #xA'); +</script> diff --git a/testing/web-platform/tests/domxpath/fn-starts-with.html b/testing/web-platform/tests/domxpath/fn-starts-with.html new file mode 100644 index 0000000000..99d2df7db6 --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-starts-with.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-starts-with"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>foo</span><span>bar<b>ber</b></span><b>bar</b>'; + assert_true(evaluateBoolean('starts-with((./span)[2], ./b)', context)); +}, 'starts-with() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-substring-after.html b/testing/web-platform/tests/domxpath/fn-substring-after.html new file mode 100644 index 0000000000..c290914d24 --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-substring-after.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring-after"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>^^^bar$$$</span><span>bar<b>^</b></span><b>bar</b>'; + assert_equals(evaluateString('substring-after((./span)[1], ./b)', context), '$$$'); +}, 'substring-after() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-substring-before.html b/testing/web-platform/tests/domxpath/fn-substring-before.html new file mode 100644 index 0000000000..69b3f1ef6e --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-substring-before.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring-before"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>^^^bar$$$</span><span>bar<b>$</b></span><b>bar</b>'; + assert_equals(evaluateString('substring-before((./span)[1], ./b)', context), '^^^'); +}, 'substring-before() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-substring.html b/testing/web-platform/tests/domxpath/fn-substring.html new file mode 100644 index 0000000000..3311a15061 --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-substring.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-substring"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>^^^bar$$$</span><span></span><br><br><br><br>'; + assert_equals(evaluateString('substring((./span)[1], count(./br))', context), 'bar$$$'); +}, 'substring() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/fn-translate.html b/testing/web-platform/tests/domxpath/fn-translate.html new file mode 100644 index 0000000000..ee1700d1b4 --- /dev/null +++ b/testing/web-platform/tests/domxpath/fn-translate.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#function-translate"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<body> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span>^^^bar$$$</span><span><b>^^^</b></span><b>bar</b><b>foo</b>'; + assert_equals(evaluateString('translate((./span)[1], (./b)[1], ./b[2])', context), '^^^foo$$$'); +}, 'translate() arguments depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/helpers.js b/testing/web-platform/tests/domxpath/helpers.js new file mode 100644 index 0000000000..0805bd682b --- /dev/null +++ b/testing/web-platform/tests/domxpath/helpers.js @@ -0,0 +1,14 @@ +function evaluateBoolean(expression, context) { + let doc = context.ownerDocument || context; + return doc.evaluate(expression, context, null, XPathResult.BOOLEAN_TYPE, null).booleanValue; +} + +function evaluateNumber(expression, context) { + let doc = context.ownerDocument || context; + return doc.evaluate(expression, context, null, XPathResult.NUMBER_TYPE, null).numberValue; +} + +function evaluateString(expression, context) { + let doc = context.ownerDocument || context; + return doc.evaluate(expression, context, null, XPathResult.STRING_TYPE, null).stringValue; +} diff --git a/testing/web-platform/tests/domxpath/lexical-structure.html b/testing/web-platform/tests/domxpath/lexical-structure.html new file mode 100644 index 0000000000..05961ab226 --- /dev/null +++ b/testing/web-platform/tests/domxpath/lexical-structure.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#exprlex"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +function parse(expression) { + document.evaluate(expression, document, null, XPathResult.ANY_TYPE, null); +} + +// https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-Literal +test(() => { + parse(' \'a"bc\' '); + parse(' "a\'bc" '); + + assert_throws_dom('SyntaxError', () => { parse(' \u2019xyz\u2019 '); }); +}, 'Literal: Only \' and " should be handled as literal quotes.'); + +// https://www.w3.org/TR/1999/REC-xpath-19991116/#NT-ExprWhitespace +test(() => { + parse(' \t\r\n.\r\n\t '); + + assert_throws_dom('SyntaxError', () => { parse('\x0B\x0C .'); }); + assert_throws_dom('SyntaxError', () => { parse('\x0E\x0F .'); }); + assert_throws_dom('SyntaxError', () => { parse('\u3000 .'); }); + assert_throws_dom('SyntaxError', () => { parse('\u2029 .'); }); +}, 'ExprWhitespace: Only #x20 #x9 #xD or #xA must be handled as a whitespace.'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/node-sets.html b/testing/web-platform/tests/domxpath/node-sets.html new file mode 100644 index 0000000000..a47314fb08 --- /dev/null +++ b/testing/web-platform/tests/domxpath/node-sets.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#node-sets"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +function nodesetToSet(result) { + const set = new Set(); + for (let node = result.iterateNext(); node; node = result.iterateNext()) { + set.add(node); + } + return set; +} + +test(() => { + const doc = document.implementation.createHTMLDocument(); + doc.documentElement.innerHTML = '<body><div></div></body>'; + const result = nodesetToSet(doc.evaluate('(.//div)[1]|.', doc.documentElement)); + assert_equals(result.size, 2); + assert_true(result.has(doc.documentElement)); + assert_true(result.has(doc.body.firstChild)); +}, '| operator should evaluate both sides of expressions with the same context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/numbers.html b/testing/web-platform/tests/domxpath/numbers.html new file mode 100644 index 0000000000..e847d6cd2e --- /dev/null +++ b/testing/web-platform/tests/domxpath/numbers.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#numbers"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="helpers.js"></script> +<div id="context"></div> +<script> +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_equals(evaluateNumber('count((./span)[1]) + count(./br)', context), 3); +}, '"+" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_equals(evaluateNumber('count((./span)[1]) - count(./br)', context), -1); +}, '"-" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_equals(evaluateNumber('count((./span)[1]) * count(./br)', context), 2); +}, '"*" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_equals(evaluateNumber('count((./span)[1]) div count(./br)', context), 0.5); +}, '"div" operator depending on the context node'); + +test(() => { + const context = document.querySelector('#context'); + context.innerHTML = '<span></span><span></span><span></span><br><br>'; + assert_equals(evaluateNumber('count((./span)[1]) mod count(./br)', context), 1); +}, '"mod" operator depending on the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/predicates.html b/testing/web-platform/tests/domxpath/predicates.html new file mode 100644 index 0000000000..1786740dbd --- /dev/null +++ b/testing/web-platform/tests/domxpath/predicates.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<link rel="help" href="https://www.w3.org/TR/1999/REC-xpath-19991116/#predicates"> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +function nodesetToSet(result) { + const set = new Set(); + for (let node = result.iterateNext(); node; node = result.iterateNext()) { + set.add(node); + } + return set; +} + +test(() => { + const doc = document.implementation.createHTMLDocument(); + doc.body.innerHTML = '<table></table>' + + '<table><tr><th><th><th><th></table>' + + '<table></table>'; + const result = nodesetToSet(doc.evaluate('(//table)[count((//table)[2]/descendant::th)-1]', doc.documentElement)); + assert_equals(result.size, 1); + assert_true(result.has(doc.body.lastChild)); +}, 'An expression in a predicate should not change the context node'); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/resolver-callback-interface-cross-realm.tentative.html b/testing/web-platform/tests/domxpath/resolver-callback-interface-cross-realm.tentative.html new file mode 100644 index 0000000000..17f7ea78c3 --- /dev/null +++ b/testing/web-platform/tests/domxpath/resolver-callback-interface-cross-realm.tentative.html @@ -0,0 +1,94 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cross-realm XPathNSResolver throws TypeError of its associated Realm</title> +<link rel="help" href="https://webidl.spec.whatwg.org/#ref-for-prepare-to-run-script"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe name="evaluateGlobalObject" src="resources/empty-document.html"></iframe> +<iframe name="resolverGlobalObject" src="resources/empty-document.html"></iframe> +<iframe name="lookupNamespaceURIGlobalObject" src="resources/empty-document.html"></iframe> +<iframe name="relevantGlobalObject" src="resources/empty-document.html"></iframe> +<iframe name="incumbentGlobalObject" src="resources/empty-document.html"></iframe> + +<script> +setup({ allow_uncaught_exception: true }); + +const expectedDOMExceptionType = "NAMESPACE_ERR"; + +test_onload(() => { + const resolver = new resolverGlobalObject.Object; + + assert_reports_exception(() => { + assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver)); + }); +}, "XPathNSResolver is cross-realm plain object without 'lookupNamespaceURI' property"); + +test_onload(() => { + const resolver = new resolverGlobalObject.Object; + resolver.lookupNamespaceURI = new lookupNamespaceURIGlobalObject.Object; + + assert_reports_exception(() => { + assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver)); + }); +}, "XPathNSResolver is cross-realm plain object with non-callable 'lookupNamespaceURI' property"); + +test_onload(() => { + const { proxy, revoke } = resolverGlobalObject.Proxy.revocable(new resolverGlobalObject.Object, {}); + revoke(); + + assert_reports_exception(() => { + assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(proxy)); + }); +}, "XPathNSResolver is cross-realm non-callable revoked Proxy"); + +test_onload(() => { + const { proxy, revoke } = resolverGlobalObject.Proxy.revocable(new resolverGlobalObject.Function, {}); + revoke(); + + assert_reports_exception(() => { + assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(proxy)); + }); +}, "XPathNSResolver is cross-realm callable revoked Proxy"); + +test_onload(() => { + const { proxy, revoke } = lookupNamespaceURIGlobalObject.Proxy.revocable(new lookupNamespaceURIGlobalObject.Function, {}); + revoke(); + + const resolver = new resolverGlobalObject.Object; + resolver.lookupNamespaceURI = proxy; + + assert_reports_exception(() => { + assert_throws_dom(expectedDOMExceptionType, evaluateGlobalObject.DOMException, bind_evaluate(resolver)); + }); +}, "XPathNSResolver is cross-realm plain object with revoked Proxy as 'lookupNamespaceURI' property"); + +function test_onload(fn, desc) { + async_test(t => { window.addEventListener("load", t.step_func_done(fn)); }, desc); +} + +function assert_reports_exception(fn) { + let error; + const onErrorHandler = event => { + error = event.error; + event.preventDefault(); + }; + + resolverGlobalObject.addEventListener("error", onErrorHandler); + fn(); + resolverGlobalObject.removeEventListener("error", onErrorHandler); + + assert_equals(typeof error, "object"); + assert_equals(error.constructor, evaluateGlobalObject.TypeError); +} + +function bind_evaluate(resolver) { + const boundEvaluate = new incumbentGlobalObject.Function("evaluate", "relevantDocument", "resolver", ` + evaluate.call(relevantDocument, "/foo:bar", relevantDocument.documentElement, resolver); + `); + + return () => { + boundEvaluate(evaluateGlobalObject.document.evaluate, relevantGlobalObject.document, resolver); + }; +} +</script> diff --git a/testing/web-platform/tests/domxpath/resolver-callback-interface.html b/testing/web-platform/tests/domxpath/resolver-callback-interface.html new file mode 100644 index 0000000000..b43695f4aa --- /dev/null +++ b/testing/web-platform/tests/domxpath/resolver-callback-interface.html @@ -0,0 +1,146 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>XPathNSResolver implements callback interface</title> +<link rel="help" href="https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator"> +<link rel="help" href="https://webidl.spec.whatwg.org/#call-a-user-objects-operation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/invalid_namespace_test.js"></script> +<div id=log></div> +<script> +"use strict"; + +test(() => { + let resolverCalls = 0; + document.evaluate("/foo:bar", document.documentElement, () => { + resolverCalls++; + return ""; + }); + + assert_equals(resolverCalls, 1); +}, "callable resolver"); + +test(() => { + let resolverCalls = 0; + const resolver = () => { + resolverCalls++; + return ""; + }; + + document.evaluate("/foo:bar", document.documentElement, resolver); + document.evaluate("/foo:bar", document.documentElement, resolver); + + assert_equals(resolverCalls, 2); +}, "callable resolver: result is not cached"); + +promise_test(t => { + const testError = { name: "test" }; + const resolver = () => { + throw testError; + }; + + return promise_rejects_exactly(t, testError, + invalid_namespace_test(t, resolver) + ); +}, "callable resolver: abrupt completion from Call"); + +test(() => { + let resolverCalls = 0; + const resolver = () => { + resolverCalls++; + return ""; + }; + + let resolverGets = 0; + Object.defineProperty(resolver, "lookupNamespaceURI", { + get() { + resolverGets++; + }, + }); + + document.evaluate("/foo:bar", document.documentElement, resolver); + + assert_equals(resolverCalls, 1); + assert_equals(resolverGets, 0); +}, "callable resolver: no 'lookupNamespaceURI' lookups"); + +test(() => { + let resolverCalls = 0; + document.evaluate("/foo:bar", document.documentElement, { + lookupNamespaceURI() { + resolverCalls++; + return ""; + }, + }); + + assert_equals(resolverCalls, 1); +}, "object resolver"); + +test(() => { + let thisValue, prefixArg; + const resolver = { + lookupNamespaceURI(prefix) { + thisValue = this; + prefixArg = prefix; + return ""; + }, + }; + + document.evaluate("/foo:bar", document.documentElement, resolver); + + assert_equals(thisValue, resolver); + assert_equals(prefixArg, "foo"); +}, "object resolver: this value and `prefix` argument"); + +test(() => { + let resolverCalls = 0; + const lookupNamespaceURI = () => { + resolverCalls++; + return ""; + }; + + let resolverGets = 0; + const resolver = { + get lookupNamespaceURI() { + resolverGets++; + return lookupNamespaceURI; + }, + }; + + document.evaluate("/foo:bar", document.documentElement, resolver); + document.evaluate("/foo:bar", document.documentElement, resolver); + + assert_equals(resolverCalls, 2); + assert_equals(resolverGets, 2); +}, "object resolver: 'lookupNamespaceURI' is not cached"); + +promise_test(t => { + const testError = { name: "test" }; + const resolver = { + get lookupNamespaceURI() { + throw testError; + }, + }; + + return promise_rejects_exactly(t, testError, + invalid_namespace_test(t, resolver) + ); +}, "object resolver: abrupt completion from Get"); + +promise_test(t => { + const resolver = { + lookupNamespaceURI: {}, + }; + + return promise_rejects_js(t, TypeError, + invalid_namespace_test(t, resolver) + ); +}, "object resolver: 'lookupNamespaceURI' is thruthy and not callable"); + +promise_test(t => { + return promise_rejects_js(t, TypeError, + invalid_namespace_test(t, {}) + ); +}, "object resolver: 'lookupNamespaceURI' is falsy and not callable"); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/resolver-non-string-result.html b/testing/web-platform/tests/domxpath/resolver-non-string-result.html new file mode 100644 index 0000000000..f8834301c4 --- /dev/null +++ b/testing/web-platform/tests/domxpath/resolver-non-string-result.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>XPathNSResolver non-string return value</title> +<link rel="help" href="https://www.w3.org/TR/DOM-Level-3-XPath/xpath.html#XPathEvaluator"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/invalid_namespace_test.js"></script> +<div id=log></div> +<script> +"use strict"; + +promise_test(t => { + return invalid_namespace_test(t, () => undefined); +}, "undefined"); + +promise_test(t => { + return invalid_namespace_test(t, () => null); +}, "null"); + +test(t => { + let resolverCalls = 0; + + document.evaluate("/foo:bar", document.documentElement, () => { + resolverCalls++; + return 0; + }); + + assert_equals(resolverCalls, 1); +}, "number"); + +test(t => { + let resolverCalls = 0; + + document.evaluate("/foo:bar", document.documentElement, () => { + resolverCalls++; + return false; + }); + + assert_equals(resolverCalls, 1); +}, "boolean"); + +promise_test(t => { + return promise_rejects_js(t, TypeError, + invalid_namespace_test(t, () => Symbol()) + ); +}, "symbol"); + +promise_test(t => { + const testError = { name: "test" }; + const resolverResult = { + toString: () => { throw testError; }, + valueOf: t.unreached_func("`valueOf` should not be called."), + }; + + return promise_rejects_exactly(t, testError, + invalid_namespace_test(t, () => resolverResult) + ); +}, "object coercion (abrupt completion)"); +</script> +</body> diff --git a/testing/web-platform/tests/domxpath/resources/empty-document.html b/testing/web-platform/tests/domxpath/resources/empty-document.html new file mode 100644 index 0000000000..b9cd130a07 --- /dev/null +++ b/testing/web-platform/tests/domxpath/resources/empty-document.html @@ -0,0 +1,3 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<body> diff --git a/testing/web-platform/tests/domxpath/resources/invalid_namespace_test.js b/testing/web-platform/tests/domxpath/resources/invalid_namespace_test.js new file mode 100644 index 0000000000..8b934eff4e --- /dev/null +++ b/testing/web-platform/tests/domxpath/resources/invalid_namespace_test.js @@ -0,0 +1,23 @@ +"use strict"; +setup({ allow_uncaught_exception: true }); + +const invalid_namespace_test = (t, resolver, resolverWindow = window) => { + const result = new Promise((resolve, reject) => { + const handler = event => { + reject(event.error); + }; + + resolverWindow.addEventListener("error", handler); + t.add_cleanup(() => { + resolverWindow.removeEventListener("error", handler); + }); + + t.step_timeout(resolve, 0); + }); + + assert_throws_dom("NAMESPACE_ERR", () => { + document.evaluate("/foo:bar", document.documentElement, resolver); + }); + + return result; +}; diff --git a/testing/web-platform/tests/domxpath/xml_xpath_runner.html b/testing/web-platform/tests/domxpath/xml_xpath_runner.html new file mode 100644 index 0000000000..03edf50515 --- /dev/null +++ b/testing/web-platform/tests/domxpath/xml_xpath_runner.html @@ -0,0 +1,59 @@ +<!doctype html> +<title>XPath tests</title> +<meta name="timeout" content="long"> +<script src='/resources/testharness.js'></script> +<script src='/resources/testharnessreport.js'></script> +<script> +setup({ explicit_done: true }); + +function find_child_element(context, element) { + for (var i = 0; i < context.childNodes.length; i++) { + var child = context.childNodes[i]; + if (child.nodeType === Node.ELEMENT_NODE && child.tagName === element) + return child; + } +} + +function xpath_test(test_el) { + /* note this func adopts the tree! */ + var new_doc = document.implementation.createDocument("", ""); + var xpath = find_child_element(test_el, "xpath"); + var result = find_child_element(test_el, "result"); + var namespace = find_child_element(result, "namespace"); + var localname = find_child_element(result, "localname"); + var nth = find_child_element(result, "nth"); + var tree = find_child_element(test_el, "tree"); + var actual_tree = new_doc.adoptNode(tree.firstElementChild); + new_doc.appendChild(actual_tree); + test(function() { + var result = new_doc.evaluate(xpath.textContent, // expression + actual_tree, // context node + new_doc.createNSResolver(actual_tree), // resolver + XPathResult.ANY_TYPE, // type + null); // result + var matched = []; + var cur; + while ((cur = result.iterateNext()) !== null) { + matched.push(cur); + } + assert_equals(matched.length, 1, "Should match one node"); + var similar = new_doc.getElementsByTagNameNS(namespace.textContent, + localname.textContent); + assert_equals(matched[0], similar[nth.textContent]); + }); +} + +var xhr = new XMLHttpRequest(); +xhr.open("GET", "xml_xpath_tests.xml"); +xhr.onload = function(e) { + var tests = xhr.responseXML.documentElement; + for (var i = 0; i < tests.childNodes.length; i++) { + var child = tests.childNodes[i]; + if (child.nodeType === Node.ELEMENT_NODE) { + xpath_test(child); + } + } + done(); +}; +xhr.send(); +</script> diff --git a/testing/web-platform/tests/domxpath/xml_xpath_tests.xml b/testing/web-platform/tests/domxpath/xml_xpath_tests.xml new file mode 100644 index 0000000000..91d6428f48 --- /dev/null +++ b/testing/web-platform/tests/domxpath/xml_xpath_tests.xml @@ -0,0 +1,34919 @@ +<!-- These tests check whether <xpath> matches the <tree>; they make + no statement as to *what* gets matched. New tests should be added + to the end of this document; there is no other form of ID for the + tests except for their order. --> + +<tests> + <test> + <xpath>//mu[@xml:id="id1"]//rho[@title][@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::rho[@object="this.nodeValue"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@object][@xml:lang="no-nb"][not(child::node())][following-sibling::alpha[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[starts-with(concat(@content,"-"),"_blank-")][not(following-sibling::*)]/iota[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::zeta[@insert][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::delta[contains(concat(@object,"$"),"se$")][preceding-sibling::*[position() = 1]]//mu[@attrib][@xml:lang="en-GB"]/omicron[contains(concat(@false,"$"),"lse$")][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id9"][not(following-sibling::*)]/rho[contains(concat(@attr,"$"),"100%$")][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::*[@xml:lang="en-US"][@xml:id="id10"][not(child::node())][following-sibling::alpha[contains(concat(@att,"$"),"rue$")][following-sibling::omicron[@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//omicron[contains(concat(@abort,"$"),"tt-value$")][@xml:lang="en"]/upsilon[starts-with(concat(@string,"-"),"100%-")][@xml:lang="no-nb"][@xml:id="id12"]]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <rho title="123456789" xml:lang="en-GB"/> + <rho object="this.nodeValue" xml:id="id2"> + <epsilon object="solid 1px green" xml:lang="no-nb"/> + <alpha xml:lang="no" xml:id="id3"/> + <phi content="_blank"> + <iota xml:lang="no" xml:id="id4"/> + <psi xml:lang="en" xml:id="id5"/> + <zeta insert="true" xml:lang="en-GB" xml:id="id6"> + <lambda xml:lang="en" xml:id="id7"/> + <delta object="false"> + <mu attrib="another attribute value" xml:lang="en-GB"> + <omicron false="false" xml:id="id8"/> + <beta xml:id="id9"> + <rho attr="100%"/> + <tau xml:lang="no"/> + <any xml:lang="en-US" xml:id="id10"/> + <alpha att="true"/> + <omicron xml:lang="no" xml:id="id11"> + <omicron abort="this-is-att-value" xml:lang="en"> + <upsilon string="100%" xml:lang="no-nb" xml:id="id12"> + <green>This text must be green</green> + </upsilon> + </omicron> + </omicron> + </beta> + </mu> + </delta> + </zeta> + </phi> + </rho> + </mu> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="no"][@xml:id="id1"]//iota[@attribute][@xml:id="id2"][not(following-sibling::*)]/phi[@object][@xml:id="id3"][not(following-sibling::*)]//pi[starts-with(concat(@number,"-"),"another attribute value-")][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:id="id4"][not(preceding-sibling::*)]/xi[@xml:id="id5"]/eta[@insert][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::nu[following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@desciption][@xml:id="id8"]/kappa[not(preceding-sibling::*)]/beta[starts-with(concat(@insert,"-"),"100%-")][not(child::node())][following-sibling::eta[starts-with(concat(@token,"-"),"content-")][not(following-sibling::*)]//pi[@and="_blank"][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id10"]/psi[starts-with(@and,"another attribut")][@xml:lang="en"][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@title="attribute"][following-sibling::eta[@or="solid 1px green"][@xml:id="id12"][following-sibling::lambda[@xml:lang="no"][@xml:id="id13"][following-sibling::theta[@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/epsilon[@object][@xml:id="id14"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="no" xml:id="id1"> + <iota attribute="this-is-att-value" xml:id="id2"> + <phi object="attribute-value" xml:id="id3"> + <pi number="another attribute value"> + <xi xml:id="id4"> + <xi xml:id="id5"> + <eta insert="another attribute value" xml:lang="en" xml:id="id6"/> + <omega xml:lang="no-nb" xml:id="id7"/> + <nu/> + <phi desciption="_blank" xml:id="id8"> + <kappa> + <beta insert="100%"/> + <eta token="content"> + <pi and="_blank" xml:lang="no" xml:id="id9"/> + <eta xml:id="id10"> + <psi and="another attribute value" xml:lang="en" xml:id="id11"/> + <omega title="attribute"/> + <eta or="solid 1px green" xml:id="id12"/> + <lambda xml:lang="no" xml:id="id13"/> + <theta xml:lang="nb"> + <epsilon object="123456789" xml:id="id14"> + <green>This text must be green</green> + </epsilon> + </theta> + </eta> + </eta> + </kappa> + </phi> + </xi> + </xi> + </pi> + </phi> + </iota> + </pi> + </tree> + </test> + <test> + <xpath>//pi[starts-with(@attribute,"attribute val")][@xml:lang="en-US"][@xml:id="id1"]/upsilon[starts-with(concat(@attribute,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]/epsilon[following-sibling::epsilon[contains(@attrib,"10")][preceding-sibling::*[position() = 1]][following-sibling::xi[preceding-sibling::*[position() = 2]]//lambda[@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::eta[@insert][preceding-sibling::*[position() = 1]][following-sibling::omega[@token][@xml:lang="nb"][not(child::node())][following-sibling::kappa[starts-with(concat(@object,"-"),"this.nodeValue-")][@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::xi[contains(@true,"e")][@xml:id="id5"][not(child::node())][following-sibling::phi[@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::nu[following-sibling::*[position()=1]][following-sibling::zeta[starts-with(concat(@object,"-"),"attribute-")]//kappa[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="nb"][following-sibling::theta[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::xi[contains(concat(@name,"$"),"789$")][@xml:lang="no"]/tau[@xml:lang="en"][not(preceding-sibling::*)]/beta[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi attribute="attribute value" xml:lang="en-US" xml:id="id1"> + <upsilon attribute="this.nodeValue"> + <xi xml:lang="no-nb" xml:id="id2"> + <epsilon/> + <epsilon attrib="100%"/> + <xi> + <lambda xml:lang="en" xml:id="id3"/> + <eta insert="false"/> + <omega token="content" xml:lang="nb"/> + <kappa object="this.nodeValue" xml:lang="no-nb" xml:id="id4"/> + <xi true="true" xml:id="id5"/> + <phi xml:lang="nb" xml:id="id6"/> + <nu/> + <zeta object="attribute"> + <kappa xml:lang="nb"/> + <chi xml:lang="nb"/> + <theta xml:lang="no"/> + <xi name="123456789" xml:lang="no"> + <tau xml:lang="en"> + <beta xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </beta> + </tau> + </xi> + </zeta> + </xi> + </xi> + </upsilon> + </pi> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]/xi[@src][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//eta[not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:id="id3"][not(child::node())][following-sibling::omega[starts-with(@name,"this.nodeVal")]//rho[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[contains(@attrib," gree")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[starts-with(concat(@insert,"-"),"100%-")][@xml:lang="no"][not(following-sibling::*)]/gamma[starts-with(@attrib,"attribu")][@xml:lang="en-GB"][not(child::node())][following-sibling::delta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::sigma[starts-with(concat(@number,"-"),"_blank-")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::omega[starts-with(concat(@false,"-"),"this-")][not(following-sibling::*)]/epsilon[starts-with(concat(@true,"-"),"attribute-")]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <xi src="_blank" xml:lang="nb" xml:id="id2"> + <eta> + <mu xml:id="id3"/> + <omega name="this.nodeValue"> + <rho/> + <nu attrib="solid 1px green"> + <lambda insert="100%" xml:lang="no"> + <gamma attrib="attribute" xml:lang="en-GB"/> + <delta xml:lang="en-US"/> + <sigma number="_blank"/> + <omega false="this-is-att-value"> + <epsilon true="attribute-value"> + <green>This text must be green</green> + </epsilon> + </omega> + </lambda> + </nu> + </omega> + </eta> + </xi> + </rho> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="no-nb"]//tau[@attr][not(preceding-sibling::*)]/alpha[@xml:lang="en-GB"][following-sibling::*[position()=6]][not(child::node())][following-sibling::phi[starts-with(@number,"attribute val")][preceding-sibling::*[position() = 1]][following-sibling::psi[preceding-sibling::*[position() = 2]][following-sibling::phi[not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id1"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::zeta[@number][@xml:id="id2"][preceding-sibling::*[position() = 5]][following-sibling::psi[@attrib][@xml:id="id3"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="no-nb"> + <tau attr="attribute value"> + <alpha xml:lang="en-GB"/> + <phi number="attribute value"/> + <psi/> + <phi/> + <psi xml:lang="no" xml:id="id1"/> + <zeta number="this-is-att-value" xml:id="id2"/> + <psi attrib="attribute value" xml:id="id3"> + <green>This text must be green</green> + </psi> + </tau> + </rho> + </tree> + </test> + <test> + <xpath>//sigma[@and][@xml:id="id1"]/beta[@name][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:id="id3"][not(following-sibling::*)]//beta[following-sibling::*[position()=3]][not(child::node())][following-sibling::theta[not(child::node())][following-sibling::eta[contains(concat(@object,"$"),"rue$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[contains(concat(@data,"$"),"ttribute-value$")][@xml:id="id4"][not(following-sibling::omicron)]/alpha[@xml:lang="no"][@xml:id="id5"][following-sibling::kappa[@token="content"][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>1</nth> + </result> + <tree> + <sigma and="_blank" xml:id="id1"> + <beta name="content" xml:lang="en" xml:id="id2"> + <tau xml:id="id3"> + <beta/> + <theta/> + <eta object="true"/> + <omicron data="attribute-value" xml:id="id4"> + <alpha xml:lang="no" xml:id="id5"/> + <kappa token="content" xml:lang="no" xml:id="id6"> + <green>This text must be green</green> + </kappa> + </omicron> + </tau> + </beta> + </sigma> + </tree> + </test> + <test> + <xpath>//lambda/kappa[contains(@false,"attribut")][@xml:id="id1"]/rho[starts-with(concat(@object,"-"),"false-")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::chi[@content][not(following-sibling::*)]/beta[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)]/psi[contains(concat(@and,"$"),"bute value$")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::alpha[starts-with(concat(@insert,"-"),"attribute-")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//kappa[@title][@xml:id="id6"][not(following-sibling::*)]//epsilon[contains(concat(@attrib,"$"),"e$")][@xml:id="id7"][not(child::node())][following-sibling::xi[@number][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//theta[@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:id="id11"][not(following-sibling::*)]/rho[starts-with(@delete,"c")][@xml:id="id12"][following-sibling::alpha[@name][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::phi[@abort][@xml:lang="nb"][@xml:id="id13"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <kappa false="attribute" xml:id="id1"> + <rho object="false" xml:id="id2"/> + <chi content="content"> + <beta xml:lang="no" xml:id="id3"> + <psi and="attribute value" xml:id="id4"/> + <alpha insert="attribute" xml:lang="no-nb" xml:id="id5"> + <kappa title="another attribute value" xml:id="id6"> + <epsilon attrib="true" xml:id="id7"/> + <xi number="true" xml:id="id8"/> + <omicron xml:id="id9"> + <theta xml:lang="no-nb" xml:id="id10"/> + <tau xml:lang="en"/> + <omega xml:id="id11"> + <rho delete="content" xml:id="id12"/> + <alpha name="true" xml:lang="no-nb"/> + <phi abort="100%" xml:lang="nb" xml:id="id13"> + <green>This text must be green</green> + </phi> + </omega> + </omicron> + </kappa> + </alpha> + </beta> + </chi> + </kappa> + </lambda> + </tree> + </test> + <test> + <xpath>//phi[@attr="100%"]//beta[contains(concat(@delete,"$"),"k$")][@xml:lang="en"][not(preceding-sibling::*)]/phi[not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:lang="en-GB"][not(following-sibling::*)]//kappa[following-sibling::nu[@name][following-sibling::*[position()=3]][following-sibling::*[@name][not(child::node())][following-sibling::sigma[starts-with(concat(@token,"-"),"another attribute value-")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::lambda[@xml:id="id1"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/rho[contains(concat(@class,"$"),"123456789$")][not(preceding-sibling::*)][following-sibling::epsilon[@xml:lang="nb"][@xml:id="id2"]/xi//beta[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[starts-with(@abort,"fa")][@xml:id="id4"][following-sibling::phi[@true][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::nu[@string="another attribute value"][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]/phi[contains(concat(@token,"$"),"1px green$")][not(preceding-sibling::*)]/theta[@xml:lang="no-nb"][not(following-sibling::*)]//lambda[@attr][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::lambda)]/*[following-sibling::*[position()=1]][following-sibling::psi[contains(concat(@desciption,"$"),"n$")][@xml:id="id7"][preceding-sibling::*[position() = 1]]//theta[contains(@src,"ue")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi attr="100%"> + <beta delete="_blank" xml:lang="en"> + <phi> + <iota xml:lang="en-GB"> + <kappa/> + <nu name="this-is-att-value"/> + <any name="this.nodeValue"/> + <sigma token="another attribute value"/> + <lambda xml:id="id1"> + <rho class="123456789"/> + <epsilon xml:lang="nb" xml:id="id2"> + <xi> + <beta xml:lang="en-US" xml:id="id3"/> + <epsilon abort="false" xml:id="id4"/> + <phi true="attribute-value" xml:id="id5"/> + <nu string="another attribute value" xml:lang="no" xml:id="id6"> + <phi token="solid 1px green"> + <theta xml:lang="no-nb"> + <lambda attr="100%"> + <any/> + <psi desciption="solid 1px green" xml:id="id7"> + <theta src="attribute value" xml:id="id8"> + <green>This text must be green</green> + </theta> + </psi> + </lambda> + </theta> + </phi> + </nu> + </xi> + </epsilon> + </lambda> + </iota> + </phi> + </beta> + </phi> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(@data,"tr")][@xml:lang="no"][@xml:id="id1"]//omicron[starts-with(concat(@class,"-"),"attribute value-")]/rho[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="no"][@xml:id="id2"]//omega[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[starts-with(@object,"conten")][preceding-sibling::*[position() = 2]][following-sibling::zeta[preceding-sibling::*[position() = 3]][following-sibling::omicron[@object][@xml:lang="en-GB"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::mu[contains(@delete,"_b")][@xml:lang="no"][@xml:id="id4"][following-sibling::pi[@xml:lang="no"][not(following-sibling::*)]/alpha[@desciption][@xml:lang="en-US"][not(child::node())][following-sibling::upsilon[contains(concat(@attribute,"$"),"eValue$")][@xml:lang="en-GB"][not(following-sibling::*)]/phi[starts-with(@title,"solid 1p")][@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)][not(preceding-sibling::phi)]/epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::alpha[@token][@xml:lang="en-US"][@xml:id="id6"][following-sibling::rho[@xml:id="id7"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <gamma data="true" xml:lang="no" xml:id="id1"> + <omicron class="attribute value"> + <rho xml:lang="no-nb"> + <rho xml:lang="no" xml:id="id2"> + <omega xml:lang="no-nb" xml:id="id3"/> + <theta xml:lang="no-nb"/> + <delta object="content"/> + <zeta/> + <omicron object="100%" xml:lang="en-GB"/> + <mu delete="_blank" xml:lang="no" xml:id="id4"/> + <pi xml:lang="no"> + <alpha desciption="100%" xml:lang="en-US"/> + <upsilon attribute="this.nodeValue" xml:lang="en-GB"> + <phi title="solid 1px green" xml:lang="en-US" xml:id="id5"> + <epsilon xml:lang="no-nb"/> + <alpha token="content" xml:lang="en-US" xml:id="id6"/> + <rho xml:id="id7"> + <green>This text must be green</green> + </rho> + </phi> + </upsilon> + </pi> + </rho> + </rho> + </omicron> + </gamma> + </tree> + </test> + <test> + <xpath>//mu/iota[starts-with(concat(@desciption,"-"),"attribute-")][not(child::node())][following-sibling::lambda[contains(concat(@or,"$"),"tribute-value$")][@xml:id="id1"][preceding-sibling::*[position() = 1]]//pi[starts-with(concat(@name,"-"),"false-")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::sigma[@name][not(child::node())][following-sibling::mu[following-sibling::zeta[@true][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][following-sibling::tau[starts-with(@abort,"_bl")][@xml:id="id4"][not(child::node())][following-sibling::delta[contains(@token,"soli")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 5]]//mu[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::nu[@att="attribute value"][@xml:id="id6"][preceding-sibling::*[position() = 1]]][position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <iota desciption="attribute-value"/> + <lambda or="attribute-value" xml:id="id1"> + <pi name="false" xml:id="id2"/> + <sigma name="another attribute value"/> + <mu/> + <zeta true="attribute-value" xml:lang="en-US" xml:id="id3"/> + <tau abort="_blank" xml:id="id4"/> + <delta token="solid 1px green" xml:lang="no-nb" xml:id="id5"> + <mu xml:lang="nb"/> + <nu att="attribute value" xml:id="id6"> + <green>This text must be green</green> + </nu> + </delta> + </lambda> + </mu> + </tree> + </test> + <test> + <xpath>//*[starts-with(concat(@attribute,"-"),"attribute-")][@xml:lang="nb"]/theta[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[not(following-sibling::*)]/phi[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]//pi[contains(concat(@attribute,"$"),"another attribute value$")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]//eta[starts-with(@desciption,"another attribu")][@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <any attribute="attribute" xml:lang="nb"> + <theta xml:lang="no" xml:id="id1"> + <zeta> + <phi xml:lang="no" xml:id="id2"> + <pi attribute="another attribute value" xml:lang="en-US" xml:id="id3"> + <eta desciption="another attribute value" xml:lang="no" xml:id="id4"> + <green>This text must be green</green> + </eta> + </pi> + </phi> + </zeta> + </theta> + </any> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(concat(@object,"-"),"100%-")][@xml:lang="en-GB"]//alpha[following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@content][@xml:id="id1"][preceding-sibling::*[position() = 1]]//upsilon[following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@class][not(child::node())][following-sibling::epsilon[@desciption][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//iota[@name="attribute-value"][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[contains(concat(@object,"$"),"nodeValue$")][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <omicron object="100%" xml:lang="en-GB"> + <alpha/> + <omega content="this.nodeValue" xml:id="id1"> + <upsilon/> + <epsilon class="false"/> + <epsilon desciption="attribute value" xml:lang="no-nb"> + <iota name="attribute-value" xml:lang="en-US"/> + <delta xml:lang="no-nb" xml:id="id2"> + <upsilon object="this.nodeValue"> + <alpha xml:lang="no"> + <green>This text must be green</green> + </alpha> + </upsilon> + </delta> + </epsilon> + </omega> + </omicron> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]//kappa[@xml:id="id2"][following-sibling::alpha[@xml:id="id3"]/nu[contains(@content,"%")][@xml:lang="en-GB"][following-sibling::*[position()=3]][not(child::node())][following-sibling::alpha[@object][@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:id="id5"][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 3]]//omicron[starts-with(concat(@desciption,"-"),"solid 1px green-")][@xml:lang="en-GB"][@xml:id="id6"]/epsilon[contains(@class,"ank")][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="nb"][following-sibling::kappa[@xml:lang="en-GB"][following-sibling::chi[starts-with(@att,"a")][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::tau[starts-with(concat(@data,"-"),"content-")][preceding-sibling::*[position() = 4]]/delta[contains(concat(@attr,"$"),"89$")][not(child::node())][following-sibling::rho[@xml:id="id9"][following-sibling::alpha[not(following-sibling::*)]//iota[not(following-sibling::*)]//eta/lambda[@xml:lang="en"][not(child::node())][following-sibling::epsilon[starts-with(@object,"t")][@xml:lang="no"][@xml:id="id10"][following-sibling::gamma[@or][@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 2]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <kappa xml:id="id2"/> + <alpha xml:id="id3"> + <nu content="100%" xml:lang="en-GB"/> + <alpha object="this-is-att-value" xml:lang="en-US" xml:id="id4"/> + <theta xml:id="id5"/> + <eta> + <omicron desciption="solid 1px green" xml:lang="en-GB" xml:id="id6"> + <epsilon class="_blank" xml:id="id7"/> + <rho xml:lang="nb"/> + <kappa xml:lang="en-GB"/> + <chi att="another attribute value" xml:id="id8"/> + <tau data="content"> + <delta attr="123456789"/> + <rho xml:id="id9"/> + <alpha> + <iota> + <eta> + <lambda xml:lang="en"/> + <epsilon object="true" xml:lang="no" xml:id="id10"/> + <gamma or="attribute-value" xml:lang="nb" xml:id="id11"> + <green>This text must be green</green> + </gamma> + </eta> + </iota> + </alpha> + </tau> + </omicron> + </eta> + </alpha> + </zeta> + </tree> + </test> + <test> + <xpath>//omega[starts-with(concat(@desciption,"-"),"attribute-")][@xml:lang="en"][@xml:id="id1"]/upsilon[@xml:id="id2"][not(preceding-sibling::*)]//kappa[@abort="this.nodeValue"][@xml:id="id3"][not(preceding-sibling::*)]//chi[@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]//phi[@xml:id="id5"][not(following-sibling::*)]/omega[contains(concat(@false,"$"),"te$")][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omega desciption="attribute-value" xml:lang="en" xml:id="id1"> + <upsilon xml:id="id2"> + <kappa abort="this.nodeValue" xml:id="id3"> + <chi xml:lang="no" xml:id="id4"> + <phi xml:id="id5"> + <omega false="attribute"> + <sigma xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </sigma> + </omega> + </phi> + </chi> + </kappa> + </upsilon> + </omega> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]//chi[starts-with(concat(@true,"-"),"content-")][following-sibling::upsilon[contains(@abort,"6789")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]//pi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id3"][preceding-sibling::*[position() = 1]]/gamma[not(preceding-sibling::*)][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <chi true="content"/> + <upsilon abort="123456789"> + <delta xml:lang="en" xml:id="id2"> + <pi xml:lang="no-nb"/> + <eta xml:id="id3"> + <gamma> + <green>This text must be green</green> + </gamma> + </eta> + </delta> + </upsilon> + </mu> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//theta[contains(concat(@number,"$"),"bute value$")][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@xml:id="id2"][not(preceding-sibling::*)]/theta[starts-with(concat(@abort,"-"),"solid 1px green-")][@xml:lang="en-US"][following-sibling::upsilon[starts-with(@number,"c")][@xml:lang="no-nb"][@xml:id="id3"]//zeta[starts-with(@attrib,"100")][@xml:lang="en-US"][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::eta[@xml:id="id4"]//theta[starts-with(concat(@name,"-"),"123456789-")][not(following-sibling::*)]/zeta[@xml:id="id5"]//rho[@xml:lang="no-nb"][@xml:id="id6"][not(child::node())][following-sibling::mu[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi//iota[@xml:lang="no"][@xml:id="id8"]/zeta[@xml:id="id9"][following-sibling::delta[@desciption][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::theta[starts-with(concat(@insert,"-"),"_blank-")][@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 2]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>1</nth> + </result> + <tree> + <psi xml:id="id1"> + <theta number="attribute value"> + <gamma xml:id="id2"> + <theta abort="solid 1px green" xml:lang="en-US"/> + <upsilon number="content" xml:lang="no-nb" xml:id="id3"> + <zeta attrib="100%" xml:lang="en-US"/> + <chi xml:lang="no-nb"/> + <eta xml:id="id4"> + <theta name="123456789"> + <zeta xml:id="id5"> + <rho xml:lang="no-nb" xml:id="id6"/> + <mu xml:lang="no" xml:id="id7"/> + <phi> + <iota xml:lang="no" xml:id="id8"> + <zeta xml:id="id9"/> + <delta desciption="123456789" xml:lang="nb"/> + <theta insert="_blank" xml:lang="no" xml:id="id10"> + <green>This text must be green</green> + </theta> + </iota> + </phi> + </zeta> + </theta> + </eta> + </upsilon> + </gamma> + </theta> + </psi> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@att,"-"),"solid 1px green-")][@xml:id="id1"]//lambda[@attribute][@xml:id="id2"][not(following-sibling::*)]//omicron[contains(concat(@abort,"$"),"e$")][not(child::node())][following-sibling::zeta[@xml:lang="nb"][preceding-sibling::*[position() = 1]]//sigma[starts-with(concat(@token,"-"),"this.nodeValue-")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]/phi[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@false="attribute value"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::eta[starts-with(@token,"123456789")][@xml:lang="no"][@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <zeta att="solid 1px green" xml:id="id1"> + <lambda attribute="another attribute value" xml:id="id2"> + <omicron abort="attribute value"/> + <zeta xml:lang="nb"> + <sigma token="this.nodeValue" xml:lang="en-US" xml:id="id3"> + <phi xml:lang="no" xml:id="id4"> + <nu false="attribute value" xml:id="id5"/> + <eta token="123456789" xml:lang="no" xml:id="id6"/> + <alpha> + <green>This text must be green</green> + </alpha> + </phi> + </sigma> + </zeta> + </lambda> + </zeta> + </tree> + </test> + <test> + <xpath>//delta//alpha[@xml:lang="no-nb"][not(preceding-sibling::*)]//tau[@object][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[contains(concat(@and,"$"),"00%$")][@xml:lang="nb"]//rho[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::eta[@xml:id="id2"]/rho[starts-with(@abort,"this-is-")][@xml:id="id3"][not(preceding-sibling::*)]/rho[not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:lang="no"][not(following-sibling::*)]//gamma[not(child::node())][following-sibling::omega[@attribute][@xml:lang="no-nb"][@xml:id="id4"]/kappa[@attrib][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id7"]//sigma[starts-with(@att,"123")][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::kappa[contains(@attr,"bute value")][@xml:lang="no-nb"][@xml:id="id9"][not(child::node())][following-sibling::alpha[@and="attribute value"][@xml:id="id10"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 3]][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id11"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::omicron[@xml:lang="no-nb"][@xml:id="id12"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <delta> + <alpha xml:lang="no-nb"> + <tau object="another attribute value"/> + <beta and="100%" xml:lang="nb"> + <rho xml:lang="en" xml:id="id1"/> + <eta xml:id="id2"> + <rho abort="this-is-att-value" xml:id="id3"> + <rho> + <iota xml:lang="no"> + <gamma/> + <omega attribute="attribute" xml:lang="no-nb" xml:id="id4"> + <kappa attrib="content" xml:lang="en-US"/> + <omicron xml:lang="en" xml:id="id5"/> + <lambda xml:lang="en-US" xml:id="id6"/> + <pi xml:lang="en" xml:id="id7"> + <sigma att="123456789" xml:id="id8"/> + <kappa attr="another attribute value" xml:lang="no-nb" xml:id="id9"/> + <alpha and="attribute value" xml:id="id10"/> + <lambda/> + <rho xml:lang="en-GB" xml:id="id11"/> + <omicron xml:lang="no-nb" xml:id="id12"> + <green>This text must be green</green> + </omicron> + </pi> + </omega> + </iota> + </rho> + </rho> + </eta> + </beta> + </alpha> + </delta> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="no"]/tau[contains(@data,"value")][@xml:lang="no"][not(child::node())][following-sibling::kappa[@att][not(following-sibling::*)]//delta[starts-with(@attrib,"100")][@xml:lang="en"][@xml:id="id1"]//omega[@xml:lang="en-GB"][@xml:id="id2"]/epsilon[@delete][following-sibling::sigma[@xml:id="id3"]/nu[starts-with(@token,"a")][not(preceding-sibling::*)]/rho[contains(concat(@delete,"$"),"00%$")][@xml:lang="no"][@xml:id="id4"]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="no"> + <tau data="attribute-value" xml:lang="no"/> + <kappa att="attribute"> + <delta attrib="100%" xml:lang="en" xml:id="id1"> + <omega xml:lang="en-GB" xml:id="id2"> + <epsilon delete="content"/> + <sigma xml:id="id3"> + <nu token="attribute value"> + <rho delete="100%" xml:lang="no" xml:id="id4"> + <green>This text must be green</green> + </rho> + </nu> + </sigma> + </omega> + </delta> + </kappa> + </mu> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@object,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id1"]//pi[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/eta[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::eta)]/rho[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi[@desciption]/epsilon[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@att="true"][following-sibling::psi[starts-with(@abort,"attribute")][@xml:id="id6"][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <zeta object="this.nodeValue" xml:lang="nb" xml:id="id1"> + <pi xml:lang="en-US" xml:id="id2"> + <eta xml:lang="nb"> + <rho xml:id="id3"/> + <pi desciption="attribute value"> + <epsilon xml:id="id4"> + <delta xml:lang="no-nb" xml:id="id5"/> + <epsilon att="true"/> + <psi abort="attribute-value" xml:id="id6"> + <green>This text must be green</green> + </psi> + </epsilon> + </pi> + </eta> + </pi> + </zeta> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(concat(@src,"-"),"this-")][@xml:id="id1"]/chi[@attrib][@xml:lang="nb"][following-sibling::eta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@xml:lang="no-nb"][not(following-sibling::*)]//kappa[@and][not(preceding-sibling::*)]//mu[@string][@xml:id="id3"][not(following-sibling::*)]//tau[@name][@xml:lang="en"][@xml:id="id4"][following-sibling::upsilon[not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <upsilon src="this-is-att-value" xml:id="id1"> + <chi attrib="attribute-value" xml:lang="nb"/> + <eta xml:id="id2"> + <phi xml:lang="no-nb"> + <kappa and="true"> + <mu string="100%" xml:id="id3"> + <tau name="attribute" xml:lang="en" xml:id="id4"/> + <upsilon> + <green>This text must be green</green> + </upsilon> + </mu> + </kappa> + </phi> + </eta> + </upsilon> + </tree> + </test> + <test> + <xpath>//*[starts-with(concat(@insert,"-"),"_blank-")]/alpha[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@token,"$"),"e-value$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[contains(@insert,"1")][not(child::node())][following-sibling::sigma[contains(@and,"_")][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::mu[not(child::node())][following-sibling::psi[following-sibling::kappa[not(following-sibling::*)]//beta//xi[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::kappa[@content][@xml:id="id3"][not(following-sibling::*)]/xi[@xml:lang="nb"][not(preceding-sibling::*)]//upsilon[contains(@content,"ri")][@xml:lang="nb"][not(following-sibling::*)]//psi[contains(@and,"te")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::iota[@attribute][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::lambda[starts-with(concat(@and,"-"),"123456789-")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::theta//beta[not(preceding-sibling::*)]//epsilon[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)]//zeta[starts-with(@insert,"content")][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <any insert="_blank"> + <alpha xml:lang="no-nb" xml:id="id1"/> + <sigma token="attribute-value"/> + <iota insert="100%"/> + <sigma and="_blank"/> + <beta xml:lang="en"/> + <mu/> + <psi/> + <kappa> + <beta> + <xi xml:lang="en-GB" xml:id="id2"/> + <kappa content="false" xml:id="id3"> + <xi xml:lang="nb"> + <upsilon content="attribute" xml:lang="nb"> + <psi and="attribute" xml:id="id4"/> + <iota attribute="solid 1px green"/> + <lambda and="123456789"/> + <theta> + <beta> + <epsilon xml:lang="en" xml:id="id5"> + <zeta insert="content"> + <green>This text must be green</green> + </zeta> + </epsilon> + </beta> + </theta> + </upsilon> + </xi> + </kappa> + </beta> + </kappa> + </any> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-GB"][@xml:id="id1"]/tau//phi[@title][@xml:id="id2"]/sigma[@xml:lang="no-nb"]//theta[@xml:id="id3"][not(preceding-sibling::*)]/tau[contains(concat(@title,"$"),"nother attribute value$")][@xml:lang="en"][not(following-sibling::*)]/phi[@attribute][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:lang="no"][@xml:id="id4"]/chi[@xml:lang="en-GB"][@xml:id="id5"][not(child::node())][following-sibling::tau[starts-with(@att,"false")][@xml:id="id6"][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 2]]/gamma[@attr][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en"][preceding-sibling::*[position() = 1]]/tau[contains(@and,"r")][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@token="false"][@xml:lang="no"][not(following-sibling::*)]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <chi xml:lang="en-GB" xml:id="id1"> + <tau> + <phi title="another attribute value" xml:id="id2"> + <sigma xml:lang="no-nb"> + <theta xml:id="id3"> + <tau title="another attribute value" xml:lang="en"> + <phi attribute="this.nodeValue"/> + <eta xml:lang="no"/> + <mu xml:lang="no" xml:id="id4"> + <chi xml:lang="en-GB" xml:id="id5"/> + <tau att="false" xml:id="id6"/> + <eta> + <gamma attr="true" xml:lang="no" xml:id="id7"/> + <upsilon xml:lang="en"> + <tau and="true"> + <chi token="false" xml:lang="no"> + <green>This text must be green</green> + </chi> + </tau> + </upsilon> + </eta> + </mu> + </tau> + </theta> + </sigma> + </phi> + </tau> + </chi> + </tree> + </test> + <test> + <xpath>//sigma[@title][@xml:id="id1"]/zeta[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@xml:id="id2"][following-sibling::psi[@att][@xml:lang="nb"][@xml:id="id3"]//alpha[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@title,"123456")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[@xml:id="id5"][following-sibling::*[position()=1]][not(preceding-sibling::any)][following-sibling::theta[preceding-sibling::*[position() = 3]][not(following-sibling::*)]//nu[contains(@desciption,"a")][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@object][preceding-sibling::*[position() = 1]]//iota[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id8"]//omega[@delete][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[following-sibling::*[position()=1]][following-sibling::omega[@number="solid 1px green"][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//rho[@string][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <sigma title="another attribute value" xml:id="id1"> + <zeta xml:lang="en"> + <nu xml:id="id2"/> + <psi att="this.nodeValue" xml:lang="nb" xml:id="id3"> + <alpha xml:lang="en-US" xml:id="id4"/> + <lambda title="123456789" xml:lang="en-US"/> + <any xml:id="id5"/> + <theta> + <nu desciption="false" xml:lang="en-US" xml:id="id6"/> + <omega object="100%"> + <iota xml:id="id7"/> + <eta xml:id="id8"> + <omega delete="true"/> + <xi/> + <omega number="solid 1px green" xml:lang="nb"> + <rho string="attribute-value" xml:lang="nb" xml:id="id9"> + <green>This text must be green</green> + </rho> + </omega> + </eta> + </omega> + </theta> + </psi> + </zeta> + </sigma> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="no-nb"][@xml:id="id1"]//theta[starts-with(@content,"fal")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[starts-with(@insert,"100")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::epsilon[@desciption="100%"][@xml:lang="en"][@xml:id="id5"]/upsilon//xi[contains(@abort,"nt")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)]//beta[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::gamma[preceding-sibling::*[position() = 1]]//kappa[@xml:lang="en-US"][following-sibling::gamma[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(@abort,"solid 1px g")]//gamma[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@object="solid 1px green"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@name="_blank"][@xml:lang="no-nb"]//nu[@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)]//sigma[@desciption][@xml:lang="nb"][following-sibling::beta[@xml:lang="en"][@xml:id="id10"][not(following-sibling::*)]/pi[contains(concat(@delete,"$"),"ue$")][not(preceding-sibling::*)][following-sibling::rho[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:lang="en"][preceding-sibling::*[position() = 2]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="no-nb" xml:id="id1"> + <theta content="false" xml:id="id2"/> + <beta insert="100%" xml:lang="nb" xml:id="id3"> + <theta xml:lang="no-nb"/> + <theta xml:lang="en-US" xml:id="id4"/> + <epsilon desciption="100%" xml:lang="en" xml:id="id5"> + <upsilon> + <xi abort="content" xml:lang="no-nb" xml:id="id6"> + <beta xml:lang="en-GB" xml:id="id7"/> + <gamma> + <kappa xml:lang="en-US"/> + <gamma xml:lang="no"/> + <delta abort="solid 1px green"> + <gamma xml:lang="no"> + <delta object="solid 1px green" xml:id="id8"/> + <pi name="_blank" xml:lang="no-nb"> + <nu xml:lang="en-GB" xml:id="id9"> + <sigma desciption="_blank" xml:lang="nb"/> + <beta xml:lang="en" xml:id="id10"> + <pi delete="true"/> + <rho/> + <mu xml:lang="en"> + <green>This text must be green</green> + </mu> + </beta> + </nu> + </pi> + </gamma> + </delta> + </gamma> + </xi> + </upsilon> + </epsilon> + </beta> + </any> + </tree> + </test> + <test> + <xpath>//rho[@content][@xml:lang="no-nb"][@xml:id="id1"]//alpha[@title="content"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][following-sibling::theta[@abort][@xml:lang="no"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][not(following-sibling::theta)][not(child::node())][following-sibling::pi[@attr="true"][@xml:lang="nb"]//eta[contains(concat(@attr,"$"),"false$")][@xml:lang="en-US"]//omega[@insert="solid 1px green"][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="en"]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <rho content="false" xml:lang="no-nb" xml:id="id1"> + <alpha title="content" xml:id="id2"/> + <zeta xml:lang="en-GB"/> + <omega xml:lang="en"/> + <psi xml:lang="no-nb"/> + <theta abort="attribute" xml:lang="no"/> + <pi attr="true" xml:lang="nb"> + <eta attr="false" xml:lang="en-US"> + <omega insert="solid 1px green" xml:lang="en-US" xml:id="id3"> + <gamma xml:lang="en"> + <green>This text must be green</green> + </gamma> + </omega> + </eta> + </pi> + </rho> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="nb"]/psi[contains(@object,"te")][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[contains(@number,"d 1p")][@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][not(preceding-sibling::chi)][not(preceding-sibling::chi or following-sibling::chi)][following-sibling::tau[@delete][@xml:lang="en-US"][not(following-sibling::*)]//phi[@token][@xml:id="id3"][not(preceding-sibling::*)]//xi[starts-with(concat(@att,"-"),"123456789-")][@xml:id="id4"][not(preceding-sibling::*)]//iota[@class="attribute-value"][not(preceding-sibling::*)]//rho[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[contains(@insert,"px green")][@xml:id="id5"][following-sibling::*[position()=3]][following-sibling::lambda[@token][@xml:lang="en-US"][not(child::node())][following-sibling::gamma[not(child::node())][following-sibling::mu[@xml:id="id6"]//omicron[contains(concat(@desciption,"$"),"his.nodeValue$")][@xml:id="id7"][not(preceding-sibling::*)]/sigma[starts-with(@attr,"at")][@xml:lang="en-US"][@xml:id="id8"][following-sibling::tau[contains(@true,"ute value")][@xml:lang="no-nb"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="nb"> + <psi object="attribute"/> + <kappa xml:id="id1"/> + <chi number="solid 1px green" xml:lang="en" xml:id="id2"/> + <tau delete="attribute-value" xml:lang="en-US"> + <phi token="attribute" xml:id="id3"> + <xi att="123456789" xml:id="id4"> + <iota class="attribute-value"> + <rho xml:lang="en-GB"/> + <chi insert="solid 1px green" xml:id="id5"/> + <lambda token="100%" xml:lang="en-US"/> + <gamma/> + <mu xml:id="id6"> + <omicron desciption="this.nodeValue" xml:id="id7"> + <sigma attr="attribute" xml:lang="en-US" xml:id="id8"/> + <tau true="attribute value" xml:lang="no-nb"> + <green>This text must be green</green> + </tau> + </omicron> + </mu> + </iota> + </xi> + </phi> + </tau> + </zeta> + </tree> + </test> + <test> + <xpath>//theta[@false][@xml:lang="no"][@xml:id="id1"]//zeta[@name][@xml:id="id2"][following-sibling::*[position()=2]][following-sibling::sigma[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@src][@xml:lang="en"][@xml:id="id4"]//theta[contains(concat(@src,"$"),"%$")][@xml:id="id5"][following-sibling::omicron[contains(@or,"ribute")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::xi[@true="another attribute value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//*[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@or][@xml:id="id8"][not(preceding-sibling::*)]//kappa[not(preceding-sibling::*)][following-sibling::phi[@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[starts-with(@delete,"this.")][@xml:id="id10"][following-sibling::omega[contains(@string,"on")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <theta false="attribute-value" xml:lang="no" xml:id="id1"> + <zeta name="solid 1px green" xml:id="id2"/> + <sigma xml:lang="en" xml:id="id3"/> + <pi src="false" xml:lang="en" xml:id="id4"> + <theta src="100%" xml:id="id5"/> + <omicron or="another attribute value" xml:lang="en-US" xml:id="id6"/> + <xi true="another attribute value"> + <any xml:id="id7"> + <sigma or="_blank" xml:id="id8"> + <kappa/> + <phi xml:id="id9"> + <lambda delete="this.nodeValue" xml:id="id10"/> + <omega string="content" xml:lang="en"> + <green>This text must be green</green> + </omega> + </phi> + </sigma> + </any> + </xi> + </pi> + </theta> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]//mu[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::alpha[@true][@xml:id="id3"][preceding-sibling::*[position() = 1]]//epsilon[contains(concat(@content,"$"),"e$")][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[starts-with(@data,"100")][not(preceding-sibling::*)]//pi[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[starts-with(concat(@attrib,"-"),"content-")][@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]/upsilon[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id6"][not(following-sibling::*)]//iota[not(preceding-sibling::*)][not(following-sibling::*)]/zeta[not(preceding-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <mu xml:lang="no-nb" xml:id="id2"/> + <alpha true="false" xml:id="id3"> + <epsilon content="false"> + <kappa data="100%"> + <pi xml:id="id4"/> + <alpha> + <lambda attrib="content" xml:lang="no" xml:id="id5"> + <upsilon xml:lang="en-US"/> + <gamma xml:lang="no-nb" xml:id="id6"> + <iota> + <zeta> + <green>This text must be green</green> + </zeta> + </iota> + </gamma> + </lambda> + </alpha> + </kappa> + </epsilon> + </alpha> + </zeta> + </tree> + </test> + <test> + <xpath>//tau[@abort][@xml:id="id1"]/rho[contains(concat(@true,"$"),"e$")][not(following-sibling::*)]//eta[not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:lang="no"]//tau[@xml:id="id2"]//iota[@xml:lang="no"][@xml:id="id3"][following-sibling::omega[@string][@xml:lang="no-nb"][following-sibling::theta[starts-with(@attr,"cont")][@xml:id="id4"][preceding-sibling::*[position() = 2]]/sigma[starts-with(@name,"this.nodeValue")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//rho[starts-with(@attrib,"cont")][@xml:lang="nb"][@xml:id="id6"][not(child::node())][following-sibling::pi[contains(concat(@token,"$"),"rue$")][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::omega[@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/*[@content][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::chi[@class][@xml:lang="no"][@xml:id="id10"]/alpha[@xml:lang="nb"][@xml:id="id11"][following-sibling::*[position()=4]][not(child::node())][following-sibling::upsilon[starts-with(concat(@name,"-"),"this-")][@xml:id="id12"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@delete][@xml:id="id13"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::xi[contains(concat(@true,"$"),"ank$")][not(child::node())][following-sibling::alpha[@xml:lang="en"][@xml:id="id14"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <tau abort="solid 1px green" xml:id="id1"> + <rho true="this-is-att-value"> + <eta/> + <alpha xml:lang="no"> + <tau xml:id="id2"> + <iota xml:lang="no" xml:id="id3"/> + <omega string="another attribute value" xml:lang="no-nb"/> + <theta attr="content" xml:id="id4"> + <sigma name="this.nodeValue" xml:lang="nb" xml:id="id5"> + <rho attrib="content" xml:lang="nb" xml:id="id6"/> + <pi token="true" xml:lang="en" xml:id="id7"/> + <xi xml:lang="en"/> + <omega xml:id="id8"> + <any content="solid 1px green" xml:lang="no" xml:id="id9"/> + <chi class="attribute value" xml:lang="no" xml:id="id10"> + <alpha xml:lang="nb" xml:id="id11"/> + <upsilon name="this-is-att-value" xml:id="id12"/> + <rho delete="100%" xml:id="id13"/> + <xi true="_blank"/> + <alpha xml:lang="en" xml:id="id14"> + <green>This text must be green</green> + </alpha> + </chi> + </omega> + </sigma> + </theta> + </tau> + </alpha> + </rho> + </tau> + </tree> + </test> + <test> + <xpath>//kappa[@string="another attribute value"]/alpha[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]/eta[@xml:lang="en-US"][following-sibling::*[@content][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 2]]/gamma[starts-with(@insert,"attr")][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <kappa string="another attribute value"> + <alpha xml:lang="en"/> + <theta xml:lang="en-US" xml:id="id1"> + <eta xml:lang="en-US"/> + <any content="true" xml:lang="no-nb" xml:id="id2"/> + <beta xml:lang="en-GB" xml:id="id3"> + <gamma insert="attribute" xml:id="id4"> + <green>This text must be green</green> + </gamma> + </beta> + </theta> + </kappa> + </tree> + </test> + <test> + <xpath>//*//alpha//beta[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::mu[contains(@false,"value")][@xml:lang="no-nb"][@xml:id="id1"][following-sibling::*[position()=3]][following-sibling::beta[@xml:lang="no-nb"][not(child::node())][following-sibling::iota[contains(@or,"e")][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 3]][following-sibling::xi[preceding-sibling::*[position() = 4]][not(following-sibling::*)]//delta[@xml:lang="no"]//upsilon[contains(concat(@token,"$"),"alue$")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::omega[@false][@xml:id="id4"][preceding-sibling::*[position() = 1]]/omega[starts-with(concat(@desciption,"-"),"_blank-")][@xml:id="id5"][not(following-sibling::*)]/sigma[@xml:id="id6"][not(preceding-sibling::*)]//lambda[following-sibling::theta[starts-with(@token,"_")][preceding-sibling::*[position() = 1]]//eta/tau[@false]//epsilon[contains(concat(@true,"$"),"ue$")][@xml:lang="nb"]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <any> + <alpha> + <beta xml:lang="en"/> + <mu false="attribute value" xml:lang="no-nb" xml:id="id1"/> + <beta xml:lang="no-nb"/> + <iota or="false" xml:lang="no" xml:id="id2"/> + <xi> + <delta xml:lang="no"> + <upsilon token="attribute-value" xml:id="id3"/> + <omega false="_blank" xml:id="id4"> + <omega desciption="_blank" xml:id="id5"> + <sigma xml:id="id6"> + <lambda/> + <theta token="_blank"> + <eta> + <tau false="attribute"> + <epsilon true="true" xml:lang="nb"> + <green>This text must be green</green> + </epsilon> + </tau> + </eta> + </theta> + </sigma> + </omega> + </omega> + </delta> + </xi> + </alpha> + </any> + </tree> + </test> + <test> + <xpath>//phi[@abort]//mu[@xml:lang="no-nb"][@xml:id="id1"]/xi[starts-with(@name,"att")][@xml:lang="no"][@xml:id="id2"]//beta[contains(@number,"l")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@string][@xml:id="id3"][not(following-sibling::*)]/pi[contains(concat(@false,"$"),"100%$")][@xml:lang="en-GB"]/omicron[@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[contains(concat(@attribute,"$"),"e$")][@xml:id="id5"][not(following-sibling::*)]//chi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::rho[@false="another attribute value"][not(following-sibling::*)]/beta[@xml:lang="no"][following-sibling::lambda[contains(concat(@name,"$"),"deValue$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@title="this-is-att-value"][@xml:id="id6"][not(preceding-sibling::*)]/kappa[@false="false"][@xml:id="id7"][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <phi abort="this-is-att-value"> + <mu xml:lang="no-nb" xml:id="id1"> + <xi name="attribute-value" xml:lang="no" xml:id="id2"> + <beta number="false" xml:lang="en"> + <phi string="100%" xml:id="id3"> + <pi false="100%" xml:lang="en-GB"> + <omicron xml:lang="en" xml:id="id4"/> + <zeta attribute="false" xml:id="id5"> + <chi xml:lang="en"/> + <rho false="another attribute value"> + <beta xml:lang="no"/> + <lambda name="this.nodeValue" xml:lang="en"> + <pi title="this-is-att-value" xml:id="id6"> + <kappa false="false" xml:id="id7"> + <green>This text must be green</green> + </kappa> + </pi> + </lambda> + </rho> + </zeta> + </pi> + </phi> + </beta> + </xi> + </mu> + </phi> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:id="id1"]//lambda[contains(@data,"alu")][@xml:lang="no-nb"][not(preceding-sibling::*)]//lambda[@xml:lang="nb"][not(child::node())][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[contains(concat(@abort,"$"),"t-value$")][not(following-sibling::*)]//alpha[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]//kappa[contains(concat(@string,"$"),"alue$")][@xml:lang="en-GB"][@xml:id="id4"]//lambda[contains(concat(@insert,"$")," value$")][not(preceding-sibling::*)][following-sibling::zeta[not(child::node())][following-sibling::psi[@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::tau[@title="another attribute value"][@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[not(following-sibling::*)]//gamma[contains(concat(@data,"$"),"23456789$")][@xml:id="id6"][not(following-sibling::*)]/mu[starts-with(@data,"solid 1px g")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@attr][@xml:lang="en-GB"][@xml:id="id7"][not(child::node())][following-sibling::lambda[@number][@xml:lang="nb"]//mu[contains(concat(@number,"$"),"t-value$")][@xml:lang="no"][not(child::node())][following-sibling::mu[@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[@data="attribute"][@xml:lang="no"][not(preceding-sibling::*)]/pi[not(following-sibling::*)]//lambda[starts-with(concat(@false,"-"),"this-")][@xml:lang="en"][@xml:id="id9"]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>1</nth> + </result> + <tree> + <epsilon xml:id="id1"> + <lambda data="attribute-value" xml:lang="no-nb"> + <lambda xml:lang="nb"/> + <upsilon xml:lang="en-US" xml:id="id2"> + <nu abort="this-is-att-value"> + <alpha xml:lang="en-US" xml:id="id3"> + <kappa string="attribute-value" xml:lang="en-GB" xml:id="id4"> + <lambda insert="attribute value"/> + <zeta/> + <psi xml:lang="nb" xml:id="id5"/> + <tau title="another attribute value" xml:lang="en-US"/> + <epsilon> + <gamma data="123456789" xml:id="id6"> + <mu data="solid 1px green"/> + <omicron attr="_blank" xml:lang="en-GB" xml:id="id7"/> + <lambda number="attribute" xml:lang="nb"> + <mu number="this-is-att-value" xml:lang="no"/> + <mu xml:id="id8"> + <xi data="attribute" xml:lang="no"> + <pi> + <lambda false="this-is-att-value" xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </lambda> + </pi> + </xi> + </mu> + </lambda> + </gamma> + </epsilon> + </kappa> + </alpha> + </nu> + </upsilon> + </lambda> + </epsilon> + </tree> + </test> + <test> + <xpath>//theta[@src]//*[contains(@desciption,"alue")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="en-US"][following-sibling::gamma[@string][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::psi[starts-with(concat(@delete,"-"),"attribute-")][following-sibling::nu[@or][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::iota[@number="false"][@xml:lang="no"][@xml:id="id4"]//eta[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::rho[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::rho)][following-sibling::omega[@xml:id="id7"][not(preceding-sibling::omega)][following-sibling::*[not(following-sibling::*)]//rho[@xml:lang="en-US"][@xml:id="id8"][following-sibling::xi[@xml:lang="no"][preceding-sibling::*[position() = 1]]/omicron[not(preceding-sibling::*)][not(following-sibling::*)]//tau[@xml:id="id9"]//omega[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <theta src="attribute"> + <any desciption="this.nodeValue" xml:id="id1"> + <phi xml:lang="en-US"/> + <gamma string="attribute value" xml:lang="en-GB" xml:id="id2"/> + <psi delete="attribute-value"/> + <nu or="100%" xml:lang="no-nb" xml:id="id3"/> + <iota number="false" xml:lang="no" xml:id="id4"> + <eta xml:id="id5"/> + <rho xml:lang="no" xml:id="id6"/> + <omega xml:id="id7"/> + <any> + <rho xml:lang="en-US" xml:id="id8"/> + <xi xml:lang="no"> + <omicron> + <tau xml:id="id9"> + <omega xml:lang="no-nb"> + <green>This text must be green</green> + </omega> + </tau> + </omicron> + </xi> + </any> + </iota> + </any> + </theta> + </tree> + </test> + <test> + <xpath>//chi[@number]/lambda[not(following-sibling::*)]/rho[@xml:lang="no"][not(following-sibling::*)]/mu[@xml:id="id1"][not(following-sibling::*)]/lambda[@xml:id="id2"][not(preceding-sibling::*)]//epsilon[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 1]]/lambda[starts-with(@abort,"th")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[contains(@false,"e v")][@xml:id="id6"][following-sibling::alpha[following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[contains(@delete,"te value")][@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]/xi[@xml:lang="no"][not(preceding-sibling::*)]/epsilon[contains(concat(@string,"$"),"ontent$")][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::delta[@token][@xml:lang="nb"][not(following-sibling::*)]//zeta[contains(@string,"alue")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <chi number="another attribute value"> + <lambda> + <rho xml:lang="no"> + <mu xml:id="id1"> + <lambda xml:id="id2"> + <epsilon xml:id="id3"/> + <any xml:id="id4"> + <lambda abort="this.nodeValue" xml:lang="en-GB" xml:id="id5"> + <epsilon false="attribute value" xml:id="id6"/> + <alpha/> + <beta delete="another attribute value" xml:lang="no-nb" xml:id="id7"> + <xi xml:lang="no"> + <epsilon string="content" xml:lang="en" xml:id="id8"/> + <delta token="solid 1px green" xml:lang="nb"> + <zeta string="attribute value" xml:lang="en"> + <green>This text must be green</green> + </zeta> + </delta> + </xi> + </beta> + </lambda> + </any> + </lambda> + </mu> + </rho> + </lambda> + </chi> + </tree> + </test> + <test> + <xpath>//nu[contains(@abort,"234567")]/delta[contains(concat(@token,"$"),"0%$")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[not(following-sibling::*)]//mu[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::mu[@abort][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]/omega[starts-with(@att,"12")][@xml:lang="en"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[starts-with(concat(@attribute,"-"),"this.nodeValue-")][@xml:id="id4"][not(following-sibling::*)]/rho[contains(@src,"100")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[not(preceding-sibling::*)]//chi[@string="attribute"][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <nu abort="123456789"> + <delta token="100%" xml:id="id1"> + <zeta> + <mu xml:lang="no"/> + <mu abort="true" xml:lang="nb" xml:id="id2"> + <omega att="123456789" xml:lang="en" xml:id="id3"/> + <sigma attribute="this.nodeValue" xml:id="id4"> + <rho src="100%" xml:lang="no"> + <tau> + <chi string="attribute" xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </chi> + </tau> + </rho> + </sigma> + </mu> + </zeta> + </delta> + </nu> + </tree> + </test> + <test> + <xpath>//alpha//zeta[@abort][not(preceding-sibling::*)][following-sibling::tau[@token][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]//tau[@true="another attribute value"]/theta[contains(concat(@delete,"$"),"attribute$")][@xml:lang="nb"][not(preceding-sibling::*)]/xi[contains(concat(@and,"$"),"Value$")][@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::omicron[@title][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id4"][not(child::node())][following-sibling::gamma[starts-with(@object,"_")][@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::theta[not(child::node())][following-sibling::kappa[@xml:id="id6"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::omicron[@title][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 6]]/phi[starts-with(concat(@src,"-"),"attribute-")][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@title="_blank"][@xml:lang="nb"][preceding-sibling::*[position() = 1]]//sigma[@xml:lang="en-GB"][@xml:id="id9"]/theta[starts-with(@insert,"this.node")][@xml:lang="en-US"][@xml:id="id10"]//chi//*[contains(@abort,"e")][@xml:id="id11"][not(child::node())][following-sibling::*[@xml:id="id12"][not(following-sibling::*)]/kappa[contains(concat(@data,"$"),"alue$")][not(following-sibling::*)]]]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha> + <zeta abort="attribute value"/> + <tau token="this-is-att-value" xml:id="id1"> + <chi xml:lang="en-GB" xml:id="id2"> + <tau true="another attribute value"> + <theta delete="attribute" xml:lang="nb"> + <xi and="this.nodeValue" xml:lang="en-GB" xml:id="id3"/> + <omicron title="content"/> + <epsilon xml:lang="en-US" xml:id="id4"/> + <gamma object="_blank" xml:lang="no" xml:id="id5"/> + <theta/> + <kappa xml:id="id6"/> + <omicron title="_blank" xml:lang="nb" xml:id="id7"> + <phi src="attribute-value" xml:id="id8"/> + <chi title="_blank" xml:lang="nb"> + <sigma xml:lang="en-GB" xml:id="id9"> + <theta insert="this.nodeValue" xml:lang="en-US" xml:id="id10"> + <chi> + <any abort="attribute value" xml:id="id11"/> + <any xml:id="id12"> + <kappa data="this.nodeValue"> + <green>This text must be green</green> + </kappa> + </any> + </chi> + </theta> + </sigma> + </chi> + </omicron> + </theta> + </tau> + </chi> + </tau> + </alpha> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en-GB"]/tau[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::epsilon[contains(@att,"ttribute-")][following-sibling::*[position()=3]][not(child::node())][following-sibling::pi[contains(concat(@desciption,"$"),"nt$")][not(child::node())][following-sibling::omicron[@object][@xml:id="id1"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[@false][not(following-sibling::*)]/alpha[@xml:lang="en-US"][not(following-sibling::*)]/phi[contains(@number,"lue")][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/delta[not(preceding-sibling::*)]/psi[starts-with(@desciption,"tru")][@xml:id="id4"][not(preceding-sibling::*)][not(preceding-sibling::psi or following-sibling::psi)]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en-GB"> + <tau xml:lang="en-US"/> + <epsilon att="attribute-value"/> + <pi desciption="content"/> + <omicron object="this-is-att-value" xml:id="id1"/> + <epsilon false="attribute-value"> + <alpha xml:lang="en-US"> + <phi number="attribute-value" xml:id="id2"/> + <delta xml:lang="no-nb" xml:id="id3"> + <delta> + <psi desciption="true" xml:id="id4"> + <green>This text must be green</green> + </psi> + </delta> + </delta> + </alpha> + </epsilon> + </omega> + </tree> + </test> + <test> + <xpath>//theta[contains(concat(@attrib,"$"),"lue$")][@xml:id="id1"]/phi[contains(@desciption,"on")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:lang="nb"]/tau[@string][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@token][@xml:id="id2"][not(following-sibling::*)][not(following-sibling::psi)]/tau[@xml:lang="en-US"][@xml:id="id3"]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>1</nth> + </result> + <tree> + <theta attrib="attribute value" xml:id="id1"> + <phi desciption="content" xml:lang="nb"> + <lambda xml:lang="nb"> + <tau string="false" xml:lang="en"> + <psi token="123456789" xml:id="id2"> + <tau xml:lang="en-US" xml:id="id3"> + <green>This text must be green</green> + </tau> + </psi> + </tau> + </lambda> + </phi> + </theta> + </tree> + </test> + <test> + <xpath>//epsilon[@src="123456789"]//alpha[not(preceding-sibling::*)]/delta[@xml:id="id1"][following-sibling::tau[@desciption][@xml:id="id2"][not(following-sibling::*)]/pi[contains(concat(@attribute,"$"),"ute value$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][@xml:id="id3"]/*[starts-with(concat(@object,"-"),"attribute value-")][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@xml:id="id5"][not(following-sibling::*)]//upsilon[@xml:id="id6"][following-sibling::gamma[starts-with(@true,"at")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]//delta[starts-with(@string,"t")][following-sibling::kappa[@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(concat(@desciption,"-"),"100%-")][preceding-sibling::*[position() = 2]]/mu[starts-with(@data,"another attribu")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::xi[contains(concat(@or,"$"),".nodeValue$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa[contains(concat(@attrib,"$")," value$")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[contains(concat(@desciption,"$"),"se$")]//theta[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <epsilon src="123456789"> + <alpha> + <delta xml:id="id1"/> + <tau desciption="_blank" xml:id="id2"> + <pi attribute="attribute value"/> + <iota xml:lang="no-nb" xml:id="id3"> + <any object="attribute value" xml:id="id4"/> + <delta xml:id="id5"> + <upsilon xml:id="id6"/> + <gamma true="attribute-value" xml:lang="no"/> + <xi xml:lang="no-nb"> + <delta string="true"/> + <kappa xml:id="id7"/> + <delta desciption="100%"> + <mu data="another attribute value" xml:lang="en-US"/> + <xi or="this.nodeValue"> + <kappa attrib="another attribute value"/> + <phi desciption="false"> + <theta xml:lang="no-nb" xml:id="id8"> + <green>This text must be green</green> + </theta> + </phi> + </xi> + </delta> + </xi> + </delta> + </iota> + </tau> + </alpha> + </epsilon> + </tree> + </test> + <test> + <xpath>//xi[starts-with(concat(@attribute,"-"),"attribute-")][@xml:lang="en"][@xml:id="id1"]/*[@xml:lang="no-nb"]/zeta[starts-with(@or,"attribute-va")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[starts-with(@data,"attribute")][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@string][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[not(following-sibling::*)]//epsilon[starts-with(concat(@true,"-"),"this-")][@xml:id="id3"][not(following-sibling::*)]/gamma[@desciption][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[@xml:lang="no"][not(child::node())][following-sibling::theta[@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::xi[@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::pi[not(child::node())][following-sibling::lambda[@class][preceding-sibling::*[position() = 4]]/lambda[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::sigma[contains(@object,"alse")][@xml:id="id8"]/delta[@xml:lang="nb"][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <xi attribute="attribute-value" xml:lang="en" xml:id="id1"> + <any xml:lang="no-nb"> + <zeta or="attribute-value" xml:lang="en" xml:id="id2"> + <theta data="attribute"> + <rho string="attribute" xml:lang="no-nb"> + <chi> + <epsilon true="this-is-att-value" xml:id="id3"> + <gamma desciption="100%"/> + <gamma xml:lang="no" xml:id="id4"> + <mu xml:lang="no"/> + <theta xml:id="id5"/> + <xi xml:id="id6"/> + <pi/> + <lambda class="attribute value"> + <lambda xml:id="id7"/> + <sigma object="false" xml:id="id8"> + <delta xml:lang="nb"> + <green>This text must be green</green> + </delta> + </sigma> + </lambda> + </gamma> + </epsilon> + </chi> + </rho> + </theta> + </zeta> + </any> + </xi> + </tree> + </test> + <test> + <xpath>//omicron[@insert]/gamma[@xml:id="id1"][not(child::node())][following-sibling::alpha[@abort="content"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//epsilon[contains(concat(@title,"$"),"his-is-att-value$")][not(child::node())][following-sibling::delta[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@src][@xml:lang="en-GB"][not(child::node())][following-sibling::*[@abort][@xml:lang="en"]/kappa[contains(@insert,"ont")][@xml:lang="no-nb"]/xi[starts-with(@data,"at")][@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[not(following-sibling::*)][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <omicron insert="false"> + <gamma xml:id="id1"/> + <alpha abort="content" xml:id="id2"> + <epsilon title="this-is-att-value"/> + <delta xml:id="id3"/> + <beta src="content" xml:lang="en-GB"/> + <any abort="content" xml:lang="en"> + <kappa insert="content" xml:lang="no-nb"> + <xi data="attribute value" xml:lang="nb"/> + <nu xml:lang="en-GB"> + <pi> + <green>This text must be green</green> + </pi> + </nu> + </kappa> + </any> + </alpha> + </omicron> + </tree> + </test> + <test> + <xpath>//eta/xi[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@content][not(preceding-sibling::*)]/phi[not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:id="id2"]//epsilon[contains(concat(@attr,"$")," 1px green$")][not(following-sibling::*)]//zeta[contains(concat(@true,"$"),"23456789$")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::zeta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:lang="no"][@xml:id="id4"][following-sibling::zeta[@xml:id="id5"][following-sibling::*[position()=4]][following-sibling::iota[@delete][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::chi[starts-with(concat(@title,"-"),"123456789-")][@xml:id="id7"][following-sibling::omicron[starts-with(@or,"attribute v")][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::rho[contains(@name,"e")][@xml:lang="no"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]/phi[@xml:lang="no-nb"][not(preceding-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <eta> + <xi xml:id="id1"> + <beta content="123456789"> + <phi> + <phi xml:id="id2"> + <epsilon attr="solid 1px green"> + <zeta true="123456789" xml:lang="no" xml:id="id3"/> + <zeta xml:lang="no-nb"> + <epsilon xml:lang="no" xml:id="id4"/> + <zeta xml:id="id5"/> + <iota delete="_blank" xml:id="id6"/> + <chi title="123456789" xml:id="id7"/> + <omicron or="attribute value"/> + <rho name="attribute value" xml:lang="no"> + <phi xml:lang="no-nb"> + <green>This text must be green</green> + </phi> + </rho> + </zeta> + </epsilon> + </phi> + </phi> + </beta> + </xi> + </eta> + </tree> + </test> + <test> + <xpath>//sigma[starts-with(@att,"th")][@xml:lang="no"][@xml:id="id1"]//sigma[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::rho[starts-with(concat(@true,"-"),"content-")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::rho[starts-with(concat(@insert,"-"),"solid 1px green-")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/zeta[@title][@xml:lang="nb"]/rho[@xml:lang="no-nb"][not(preceding-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>1</nth> + </result> + <tree> + <sigma att="this.nodeValue" xml:lang="no" xml:id="id1"> + <sigma xml:lang="no"/> + <rho true="content" xml:id="id2"/> + <rho insert="solid 1px green" xml:lang="no"> + <zeta title="true" xml:lang="nb"> + <rho xml:lang="no-nb"> + <green>This text must be green</green> + </rho> + </zeta> + </rho> + </sigma> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(@false,"attribute val")][@xml:id="id1"]//eta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::kappa[following-sibling::*[position()=3]][not(child::node())][following-sibling::kappa[@xml:id="id3"][following-sibling::*[position()=2]][following-sibling::rho[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@desciption="another attribute value"][@xml:lang="nb"][not(following-sibling::*)]/tau[@and][@xml:id="id5"][not(following-sibling::*)]//chi[@token][@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[contains(concat(@name,"$"),"-att-value$")]//tau[contains(concat(@and,"$"),"789$")][following-sibling::pi[contains(@data,"0")][@xml:lang="nb"][not(following-sibling::*)]//delta[@src="true"][@xml:lang="nb"]/psi[@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@xml:id="id8"][not(preceding-sibling::*)]/tau[@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)]//lambda[not(following-sibling::*)]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <zeta false="attribute value" xml:id="id1"> + <eta xml:id="id2"/> + <kappa/> + <kappa xml:id="id3"/> + <rho xml:lang="en-US" xml:id="id4"/> + <omicron desciption="another attribute value" xml:lang="nb"> + <tau and="this.nodeValue" xml:id="id5"> + <chi token="attribute value" xml:id="id6"/> + <mu name="this-is-att-value"> + <tau and="123456789"/> + <pi data="100%" xml:lang="nb"> + <delta src="true" xml:lang="nb"> + <psi xml:lang="nb" xml:id="id7"> + <eta xml:id="id8"> + <tau xml:lang="en" xml:id="id9"> + <lambda> + <green>This text must be green</green> + </lambda> + </tau> + </eta> + </psi> + </delta> + </pi> + </mu> + </tau> + </omicron> + </zeta> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-GB"]//chi[contains(@desciption,"e")][@xml:lang="no-nb"]//omega[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[not(following-sibling::*)]//nu[contains(concat(@attr,"$"),"alue$")][@xml:lang="en-US"][not(preceding-sibling::*)]//iota[@xml:lang="en-US"]//rho[not(preceding-sibling::*)][not(following-sibling::*)]/phi[following-sibling::lambda[starts-with(concat(@desciption,"-"),"attribute-")][@xml:lang="no"][@xml:id="id2"][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <phi xml:lang="en-GB"> + <chi desciption="attribute" xml:lang="no-nb"> + <omega xml:lang="nb" xml:id="id1"> + <nu> + <nu attr="another attribute value" xml:lang="en-US"> + <iota xml:lang="en-US"> + <rho> + <phi/> + <lambda desciption="attribute-value" xml:lang="no" xml:id="id2"> + <green>This text must be green</green> + </lambda> + </rho> + </iota> + </nu> + </nu> + </omega> + </chi> + </phi> + </tree> + </test> + <test> + <xpath>//beta[@data][@xml:lang="en-US"][@xml:id="id1"]/lambda[starts-with(concat(@attr,"-"),"_blank-")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::iota[contains(concat(@or,"$"),"er attribute value$")][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[contains(concat(@and,"$"),"e$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//epsilon[@or="123456789"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::epsilon[@attribute][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta[@content][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]/*[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[contains(concat(@attrib,"$"),"ent$")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <beta data="attribute" xml:lang="en-US" xml:id="id1"> + <lambda attr="_blank" xml:lang="en-US" xml:id="id2"/> + <iota or="another attribute value" xml:lang="en-GB" xml:id="id3"/> + <eta and="false" xml:lang="en-GB"> + <epsilon or="123456789" xml:id="id4"/> + <epsilon attribute="this-is-att-value"> + <zeta content="this.nodeValue" xml:lang="nb" xml:id="id5"> + <any xml:id="id6"/> + <gamma attrib="content" xml:id="id7"/> + <eta xml:id="id8"> + <green>This text must be green</green> + </eta> + </zeta> + </epsilon> + </eta> + </beta> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(concat(@data,"-"),"another attribute value-")][@xml:lang="en"]/xi[not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 1]][following-sibling::eta[starts-with(concat(@att,"-"),"this.nodeValue-")][@xml:id="id1"]//mu[@att][@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]//mu[@xml:lang="no"][not(following-sibling::*)]//chi[@xml:id="id3"]/lambda[contains(concat(@content,"$"),"ttribute value$")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::iota[contains(@name,"en")][preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <lambda data="another attribute value" xml:lang="en"> + <xi/> + <upsilon/> + <eta att="this.nodeValue" xml:id="id1"> + <mu att="true" xml:lang="en" xml:id="id2"> + <mu xml:lang="no"> + <chi xml:id="id3"> + <lambda content="another attribute value" xml:lang="no" xml:id="id4"/> + <iota name="solid 1px green"/> + <kappa xml:lang="no"> + <green>This text must be green</green> + </kappa> + </chi> + </mu> + </mu> + </eta> + </lambda> + </tree> + </test> + <test> + <xpath>//*[starts-with(@string,"another attribute va")][@xml:lang="en"][@xml:id="id1"]/gamma[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(concat(@token,"-"),"content-")][@xml:id="id3"]/rho[@true="attribute-value"][not(preceding-sibling::*)]/pi[@insert="123456789"][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::pi)]/chi[contains(concat(@delete,"$"),"content$")][@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::eta[@xml:lang="en"]/kappa[@xml:id="id5"]/delta[starts-with(@number,"a")][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::delta)]/epsilon[@abort][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::gamma[@xml:lang="en"][@xml:id="id7"][not(child::node())][following-sibling::delta[following-sibling::*[position()=2]][following-sibling::omega[starts-with(@or,"solid ")][@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 4]]/gamma[contains(@number,"e value")][@xml:lang="no"][@xml:id="id9"][not(child::node())][following-sibling::*[starts-with(@delete,"_")]/rho[@xml:lang="nb"][following-sibling::alpha[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:id="id10"][preceding-sibling::*[position() = 2]]//*[@xml:lang="en-GB"][not(following-sibling::*)]//zeta[@abort][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@attribute="123456789"][not(following-sibling::*)]//iota[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <any string="another attribute value" xml:lang="en" xml:id="id1"> + <gamma xml:lang="en-GB" xml:id="id2"/> + <upsilon token="content" xml:id="id3"> + <rho true="attribute-value"> + <pi insert="123456789" xml:lang="en-GB"> + <chi delete="content" xml:lang="nb" xml:id="id4"/> + <eta xml:lang="en"> + <kappa xml:id="id5"> + <delta number="attribute" xml:lang="en-US" xml:id="id6"> + <epsilon abort="false" xml:lang="en-US"/> + <gamma xml:lang="en" xml:id="id7"/> + <delta/> + <omega or="solid 1px green" xml:id="id8"/> + <theta> + <gamma number="attribute value" xml:lang="no" xml:id="id9"/> + <any delete="_blank"> + <rho xml:lang="nb"/> + <alpha xml:lang="en-GB"/> + <mu xml:id="id10"> + <any xml:lang="en-GB"> + <zeta abort="123456789" xml:lang="en-US"> + <eta attribute="123456789"> + <iota xml:lang="nb"> + <green>This text must be green</green> + </iota> + </eta> + </zeta> + </any> + </mu> + </any> + </theta> + </delta> + </kappa> + </eta> + </pi> + </rho> + </upsilon> + </any> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]/tau[@xml:id="id2"][not(child::node())][following-sibling::phi[starts-with(@insert,"attribute-v")][@xml:lang="en-US"][@xml:id="id3"][following-sibling::pi//upsilon[@xml:lang="en-GB"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@title][@xml:lang="en-US"]/eta[contains(concat(@abort,"$"),"alue$")][not(child::node())][following-sibling::alpha[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]/epsilon[@and="solid 1px green"][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::nu[@desciption][@xml:lang="nb"]/psi[@xml:id="id6"][not(following-sibling::*)]//omicron[not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:lang="no"][not(child::node())][following-sibling::mu[not(following-sibling::*)]/iota[contains(concat(@true,"$"),"attribute$")][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@attr][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:lang="en-US"][@xml:id="id8"]//*[not(preceding-sibling::*)][position() = 1]][position() = 1]]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <tau xml:id="id2"/> + <phi insert="attribute-value" xml:lang="en-US" xml:id="id3"/> + <pi> + <upsilon xml:lang="en-GB" xml:id="id4"/> + <psi title="false" xml:lang="en-US"> + <eta abort="attribute-value"/> + <alpha xml:lang="no-nb" xml:id="id5"> + <epsilon and="solid 1px green" xml:lang="no"/> + <nu desciption="attribute-value" xml:lang="nb"> + <psi xml:id="id6"> + <omicron/> + <eta xml:lang="no"/> + <mu> + <iota true="attribute"/> + <mu attr="false" xml:id="id7"/> + <nu xml:lang="en-US" xml:id="id8"> + <any> + <green>This text must be green</green> + </any> + </nu> + </mu> + </psi> + </nu> + </alpha> + </psi> + </pi> + </gamma> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]//kappa[@xml:id="id2"][not(child::node())][following-sibling::*[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]//lambda[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@att][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::psi[@content="_blank"][@xml:id="id7"]//kappa[starts-with(concat(@data,"-"),"this-")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <kappa xml:id="id2"/> + <any xml:lang="en" xml:id="id3"> + <lambda xml:id="id4"/> + <omega xml:lang="en-US" xml:id="id5"> + <xi att="_blank" xml:lang="en" xml:id="id6"/> + <psi content="_blank" xml:id="id7"> + <kappa data="this-is-att-value" xml:id="id8"> + <green>This text must be green</green> + </kappa> + </psi> + </omega> + </any> + </iota> + </tree> + </test> + <test> + <xpath>//tau[@data="solid 1px green"][@xml:lang="nb"][@xml:id="id1"]//zeta[@xml:lang="nb"][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][preceding-sibling::*[position() = 1]]/*[@content="this-is-att-value"][not(preceding-sibling::*)][following-sibling::sigma[starts-with(concat(@false,"-"),"content-")][@xml:lang="nb"][not(following-sibling::*)]//lambda[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::theta[@desciption="attribute"][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@and][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(concat(@data,"-"),"100%-")][not(following-sibling::*)]//eta[@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]//alpha[not(child::node())][following-sibling::omicron[starts-with(@content,"this.nodeVal")][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@object="123456789"][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]/eta[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@number,"this.")][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:id="id8"][preceding-sibling::*[position() = 2]]//iota/iota[@name][@xml:id="id9"][not(preceding-sibling::*)]/tau[following-sibling::chi[contains(@true,"e")][@xml:id="id10"][preceding-sibling::*[position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <tau data="solid 1px green" xml:lang="nb" xml:id="id1"> + <zeta xml:lang="nb"/> + <upsilon xml:lang="nb"> + <any content="this-is-att-value"/> + <sigma false="content" xml:lang="nb"> + <lambda xml:lang="nb" xml:id="id2"/> + <theta desciption="attribute" xml:lang="nb" xml:id="id3"> + <epsilon and="123456789"/> + <kappa data="100%"> + <eta xml:lang="nb" xml:id="id4"> + <alpha/> + <omicron content="this.nodeValue"/> + <iota object="123456789" xml:lang="en-GB"/> + <phi xml:lang="no" xml:id="id5"> + <eta xml:lang="nb" xml:id="id6"/> + <lambda number="this.nodeValue" xml:id="id7"/> + <lambda xml:id="id8"> + <iota> + <iota name="attribute value" xml:id="id9"> + <tau/> + <chi true="content" xml:id="id10"> + <green>This text must be green</green> + </chi> + </iota> + </iota> + </lambda> + </phi> + </eta> + </kappa> + </theta> + </sigma> + </upsilon> + </tau> + </tree> + </test> + <test> + <xpath>//epsilon[contains(@attrib,"e")][@xml:id="id1"]//eta[@true][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@or][@xml:id="id2"][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 2]]//psi[@number][@xml:lang="nb"][@xml:id="id3"][following-sibling::*[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]/gamma[@xml:id="id6"]/theta[not(preceding-sibling::*)][not(following-sibling::*)]/chi//lambda[@xml:lang="no-nb"]/gamma[@xml:lang="no"][@xml:id="id7"][not(child::node())][following-sibling::phi[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::gamma[contains(@false,".nodeValue")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 3]]//tau[@xml:lang="no-nb"][@xml:id="id9"][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <epsilon attrib="false" xml:id="id1"> + <eta true="_blank"/> + <eta or="true" xml:id="id2"/> + <sigma> + <psi number="this.nodeValue" xml:lang="nb" xml:id="id3"/> + <any xml:lang="no" xml:id="id4"> + <zeta xml:lang="en" xml:id="id5"> + <gamma xml:id="id6"> + <theta> + <chi> + <lambda xml:lang="no-nb"> + <gamma xml:lang="no" xml:id="id7"/> + <phi xml:lang="nb" xml:id="id8"/> + <gamma false="this.nodeValue" xml:lang="en"/> + <iota> + <tau xml:lang="no-nb" xml:id="id9"/> + <chi xml:lang="no-nb"> + <green>This text must be green</green> + </chi> + </iota> + </lambda> + </chi> + </theta> + </gamma> + </zeta> + </any> + </sigma> + </epsilon> + </tree> + </test> + <test> + <xpath>//pi[@string="100%"][@xml:lang="en"]/chi[@xml:lang="en"][@xml:id="id1"]/xi[contains(concat(@content,"$"),"se$")][not(preceding-sibling::*)]//alpha[contains(@title," ")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::rho[@xml:id="id3"][not(following-sibling::*)]/delta[@name="attribute value"][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[contains(concat(@delete,"$"),"e$")][@xml:lang="nb"][not(child::node())][following-sibling::epsilon[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::epsilon)]/alpha[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::psi[starts-with(concat(@attribute,"-"),"this.nodeValue-")][@xml:id="id5"][preceding-sibling::*[position() = 1]]//tau[starts-with(@title,"_blan")][not(following-sibling::*)]/*[@delete][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::psi[contains(@or,"nother attribute ")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::pi[following-sibling::nu[starts-with(concat(@object,"-"),"solid 1px green-")][@xml:id="id7"][preceding-sibling::*[position() = 3]][following-sibling::kappa[contains(@content,"attribute va")][@xml:id="id8"][not(child::node())][following-sibling::delta[@xml:lang="no"][not(following-sibling::*)]//phi[@and="attribute-value"][@xml:lang="no-nb"][not(child::node())][following-sibling::theta[contains(@att,"nk")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[starts-with(@object,"attr")][not(child::node())][following-sibling::mu[@xml:lang="nb"][not(following-sibling::*)]/phi[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@xml:lang="en-GB"][@xml:id="id11"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <pi string="100%" xml:lang="en"> + <chi xml:lang="en" xml:id="id1"> + <xi content="false"> + <alpha title="attribute value" xml:lang="nb" xml:id="id2"/> + <rho xml:id="id3"> + <delta name="attribute value" xml:lang="en"> + <lambda delete="attribute" xml:lang="nb"/> + <epsilon xml:lang="no" xml:id="id4"> + <alpha xml:lang="en-US"/> + <psi attribute="this.nodeValue" xml:id="id5"> + <tau title="_blank"> + <any delete="attribute-value" xml:id="id6"/> + <psi or="another attribute value"/> + <pi/> + <nu object="solid 1px green" xml:id="id7"/> + <kappa content="attribute value" xml:id="id8"/> + <delta xml:lang="no"> + <phi and="attribute-value" xml:lang="no-nb"/> + <theta att="_blank" xml:lang="nb"/> + <beta object="attribute"/> + <mu xml:lang="nb"> + <phi xml:id="id9"> + <zeta xml:lang="nb" xml:id="id10"> + <xi xml:lang="en-GB" xml:id="id11"> + <green>This text must be green</green> + </xi> + </zeta> + </phi> + </mu> + </delta> + </tau> + </psi> + </epsilon> + </delta> + </rho> + </xi> + </chi> + </pi> + </tree> + </test> + <test> + <xpath>//tau/xi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@insert][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@token][not(following-sibling::*)]/tau[@xml:id="id1"]//zeta[contains(@insert,"100")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[not(child::node())][following-sibling::alpha[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <tau> + <xi xml:lang="en-GB"/> + <eta insert="false"/> + <theta token="true"> + <tau xml:id="id1"> + <zeta insert="100%" xml:lang="nb"/> + <beta/> + <alpha xml:lang="en-US"> + <green>This text must be green</green> + </alpha> + </tau> + </theta> + </tau> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@number,"_bla")][@xml:lang="en"]/tau[@xml:id="id1"][not(preceding-sibling::*)]/eta[contains(@src,"deValue")][@xml:lang="en"][following-sibling::gamma[contains(concat(@false,"$"),"100%$")][@xml:id="id2"][following-sibling::alpha[not(following-sibling::*)]/nu[starts-with(concat(@data,"-"),"this-")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[starts-with(@att,"attrib")][preceding-sibling::*[position() = 1]][following-sibling::pi[contains(@att,"a")][preceding-sibling::*[position() = 2]][following-sibling::*[@false][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::psi[starts-with(@and,"another attribu")][@xml:id="id4"][not(preceding-sibling::psi)]//epsilon[starts-with(concat(@insert,"-"),"attribute-")][@xml:id="id5"][following-sibling::omega[@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[@attribute][@xml:id="id7"][not(child::node())][following-sibling::nu[@xml:lang="en"]//omicron[@att][@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@insert][@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::alpha[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::lambda[@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::nu[not(following-sibling::*)]//xi[@xml:lang="en"][@xml:id="id10"][following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[contains(concat(@data,"$"),"false$")][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@xml:lang="en"][not(child::node())][following-sibling::theta[@delete="attribute"][@xml:id="id12"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <omega number="_blank" xml:lang="en"> + <tau xml:id="id1"> + <eta src="this.nodeValue" xml:lang="en"/> + <gamma false="100%" xml:id="id2"/> + <alpha> + <nu data="this-is-att-value" xml:lang="en-US"/> + <delta att="attribute"/> + <pi att="attribute value"/> + <any false="_blank" xml:lang="no-nb" xml:id="id3"/> + <psi and="another attribute value" xml:id="id4"> + <epsilon insert="attribute" xml:id="id5"/> + <omega xml:lang="en" xml:id="id6"> + <theta attribute="another attribute value" xml:id="id7"/> + <nu xml:lang="en"> + <omicron att="solid 1px green" xml:lang="en-US" xml:id="id8"> + <omega insert="false" xml:lang="no"/> + <alpha xml:lang="nb"/> + <lambda xml:id="id9"/> + <nu> + <xi xml:lang="en" xml:id="id10"/> + <tau data="false" xml:id="id11"/> + <zeta xml:lang="en"/> + <theta delete="attribute" xml:id="id12"> + <green>This text must be green</green> + </theta> + </nu> + </omicron> + </nu> + </omega> + </psi> + </alpha> + </tau> + </omega> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]//rho[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id3"][not(following-sibling::*)]//chi[@string][not(following-sibling::chi)][not(child::node())][following-sibling::epsilon[contains(concat(@abort,"$"),"value$")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::theta[@data="solid 1px green"][@xml:id="id5"]//omega[starts-with(@true,"this.n")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)][not(preceding-sibling::omega or following-sibling::omega)]/theta[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(concat(@attribute,"$"),"bute value$")][@xml:lang="en-GB"][following-sibling::kappa[@src][@xml:lang="nb"][@xml:id="id8"]/iota[@xml:id="id9"][not(following-sibling::*)]/upsilon[starts-with(@insert,"fal")][@xml:lang="no"][@xml:id="id10"]//phi[not(following-sibling::*)]/lambda[not(following-sibling::*)]//chi[@data][@xml:lang="no-nb"][not(child::node())][following-sibling::theta[@xml:id="id11"][not(following-sibling::*)]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <rho xml:lang="nb" xml:id="id2"/> + <iota xml:id="id3"> + <chi string="attribute value"/> + <epsilon abort="attribute value" xml:id="id4"/> + <theta data="solid 1px green" xml:id="id5"> + <omega true="this.nodeValue" xml:lang="nb" xml:id="id6"> + <theta xml:id="id7"/> + <eta attribute="attribute value" xml:lang="en-GB"/> + <kappa src="content" xml:lang="nb" xml:id="id8"> + <iota xml:id="id9"> + <upsilon insert="false" xml:lang="no" xml:id="id10"> + <phi> + <lambda> + <chi data="attribute-value" xml:lang="no-nb"/> + <theta xml:id="id11"> + <green>This text must be green</green> + </theta> + </lambda> + </phi> + </upsilon> + </iota> + </kappa> + </omega> + </theta> + </iota> + </gamma> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no-nb"]//chi[@name="this.nodeValue"][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@delete][@xml:lang="en-US"][@xml:id="id1"][not(child::node())][following-sibling::kappa[@true][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/*[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::sigma[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::nu[@xml:id="id5"][preceding-sibling::*[position() = 2]]//delta[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(@desciption,"true")][@xml:lang="no-nb"][@xml:id="id7"]/omega[starts-with(concat(@abort,"-"),"123456789-")][@xml:id="id8"]//tau[starts-with(concat(@src,"-"),"false-")][@xml:lang="nb"][@xml:id="id9"][not(following-sibling::*)]//lambda[contains(concat(@or,"$"),"een$")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(@attribute,"ls")][@xml:lang="no-nb"][following-sibling::chi[@class][@xml:id="id10"][not(following-sibling::*)]//lambda[@string][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::psi[following-sibling::upsilon[@xml:id="id11"][not(following-sibling::*)]/chi[starts-with(@src,"123456")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::theta[preceding-sibling::*[position() = 1]][following-sibling::epsilon[contains(@number,"ribute value")][preceding-sibling::*[position() = 2]][not(preceding-sibling::epsilon or following-sibling::epsilon)][following-sibling::kappa[@xml:lang="nb"]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no-nb"> + <chi name="this.nodeValue" xml:lang="en"> + <rho delete="solid 1px green" xml:lang="en-US" xml:id="id1"/> + <kappa true="solid 1px green" xml:lang="no" xml:id="id2"> + <any xml:lang="no-nb" xml:id="id3"/> + <sigma xml:lang="no" xml:id="id4"/> + <nu xml:id="id5"> + <delta xml:id="id6"/> + <sigma desciption="true" xml:lang="no-nb" xml:id="id7"> + <omega abort="123456789" xml:id="id8"> + <tau src="false" xml:lang="nb" xml:id="id9"> + <lambda or="solid 1px green"/> + <omicron attribute="false" xml:lang="no-nb"/> + <chi class="this.nodeValue" xml:id="id10"> + <lambda string="attribute-value"/> + <mu xml:lang="no"/> + <psi/> + <upsilon xml:id="id11"> + <chi src="123456789" xml:lang="en"/> + <theta/> + <epsilon number="attribute value"/> + <kappa xml:lang="nb"> + <green>This text must be green</green> + </kappa> + </upsilon> + </chi> + </tau> + </omega> + </sigma> + </nu> + </kappa> + </chi> + </tau> + </tree> + </test> + <test> + <xpath>//epsilon[contains(@attribute,"als")][@xml:id="id1"]/omicron[@xml:id="id2"]/mu[starts-with(@title,"another att")][@xml:lang="nb"][@xml:id="id3"][following-sibling::kappa[@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::psi[starts-with(@number,"this-is-at")][@xml:lang="en"][preceding-sibling::*[position() = 2]]//*[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:id="id5"][not(preceding-sibling::*)]/rho[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[@xml:id="id6"]/lambda[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)]/chi[@xml:lang="nb"][@xml:id="id8"][not(following-sibling::chi)][not(child::node())][following-sibling::theta[contains(concat(@class,"$"),"ue$")][@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 2]]//pi[starts-with(concat(@data,"-"),"attribute-")][not(preceding-sibling::*)][not(preceding-sibling::pi)][not(child::node())][following-sibling::nu[@att][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <epsilon attribute="false" xml:id="id1"> + <omicron xml:id="id2"> + <mu title="another attribute value" xml:lang="nb" xml:id="id3"/> + <kappa xml:lang="no-nb"/> + <psi number="this-is-att-value" xml:lang="en"> + <any xml:lang="no" xml:id="id4"> + <sigma xml:id="id5"> + <rho/> + <tau xml:id="id6"> + <lambda xml:lang="no" xml:id="id7"> + <chi xml:lang="nb" xml:id="id8"/> + <theta class="true" xml:lang="en-GB" xml:id="id9"/> + <zeta> + <pi data="attribute"/> + <nu att="this-is-att-value"> + <green>This text must be green</green> + </nu> + </zeta> + </lambda> + </tau> + </sigma> + </any> + </psi> + </omicron> + </epsilon> + </tree> + </test> + <test> + <xpath>//gamma//upsilon[not(child::node())][following-sibling::nu[@xml:id="id1"][not(child::node())][following-sibling::eta[starts-with(concat(@att,"-"),"another attribute value-")][preceding-sibling::*[position() = 2]]//sigma[not(preceding-sibling::*)]//lambda[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[@xml:id="id3"][following-sibling::mu[contains(@title,"tt-valu")][@xml:id="id4"][not(following-sibling::*)]/sigma[contains(@title,"ibute")]/theta[contains(@true," value")][not(following-sibling::*)]/gamma[position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <gamma> + <upsilon/> + <nu xml:id="id1"/> + <eta att="another attribute value"> + <sigma> + <lambda xml:lang="en-US" xml:id="id2"/> + <rho xml:id="id3"/> + <mu title="this-is-att-value" xml:id="id4"> + <sigma title="attribute-value"> + <theta true="attribute value"> + <gamma> + <green>This text must be green</green> + </gamma> + </theta> + </sigma> + </mu> + </sigma> + </eta> + </gamma> + </tree> + </test> + <test> + <xpath>//eta[@xml:id="id1"]//gamma[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[not(child::node())][following-sibling::lambda[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::xi[starts-with(concat(@delete,"-"),"this-")][preceding-sibling::*[position() = 2]]//psi[contains(@desciption,"tribute")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]/tau[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omega[@content="true"][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[contains(concat(@number,"$"),"lse$")][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-US"][@xml:id="id8"]//pi[not(following-sibling::*)]//pi[contains(@title,"t")][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[not(preceding-sibling::*)]/gamma[contains(@name,"ntent")][not(child::node())][following-sibling::theta[@string][@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[not(following-sibling::*)]//alpha[contains(@src,"x gree")][@xml:lang="nb"]//delta[@xml:lang="en-US"][not(child::node())][following-sibling::upsilon[contains(@delete,"k")][@xml:lang="nb"][@xml:id="id11"][following-sibling::*[position()=1]][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id12"]/upsilon[starts-with(@delete,"this-is-att-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:id="id13"][following-sibling::*[position()=1]][following-sibling::omega[starts-with(concat(@class,"-"),"true-")][@xml:lang="no"][@xml:id="id14"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:id="id1"> + <gamma xml:lang="en" xml:id="id2"> + <chi/> + <lambda xml:id="id3"/> + <xi delete="this-is-att-value"> + <psi desciption="attribute" xml:lang="en-US" xml:id="id4"> + <tau xml:id="id5"/> + <omega content="true" xml:lang="no-nb" xml:id="id6"/> + <phi xml:lang="en-US" xml:id="id7"> + <mu number="false"/> + <nu xml:lang="en-US" xml:id="id8"> + <pi> + <pi title="content" xml:lang="no" xml:id="id9"> + <alpha> + <gamma name="content"/> + <theta string="solid 1px green" xml:lang="en" xml:id="id10"> + <omega> + <alpha src="solid 1px green" xml:lang="nb"> + <delta xml:lang="en-US"/> + <upsilon delete="_blank" xml:lang="nb" xml:id="id11"/> + <omicron xml:lang="en-GB" xml:id="id12"> + <upsilon delete="this-is-att-value" xml:lang="en-GB"> + <kappa xml:id="id13"/> + <omega class="true" xml:lang="no" xml:id="id14"> + <green>This text must be green</green> + </omega> + </upsilon> + </omicron> + </alpha> + </omega> + </theta> + </alpha> + </pi> + </pi> + </nu> + </phi> + </psi> + </xi> + </gamma> + </eta> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]/zeta[contains(concat(@and,"$"),"n$")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::gamma[@xml:lang="en-US"][@xml:id="id3"][not(child::node())][following-sibling::psi[@xml:lang="en"][not(child::node())][following-sibling::iota[@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::zeta[starts-with(@number,"attr")][@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//gamma[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(concat(@attrib,"$"),"3456789$")][@xml:id="id5"][preceding-sibling::*[position() = 1]]//omega[starts-with(@content,"c")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:lang="no-nb"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[starts-with(@attribute,"att")][@xml:lang="nb"]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <zeta and="solid 1px green" xml:lang="no-nb" xml:id="id2"/> + <gamma xml:lang="en-US" xml:id="id3"/> + <psi xml:lang="en"/> + <iota xml:id="id4"/> + <zeta number="attribute" xml:lang="en-GB"/> + <beta xml:lang="en"> + <gamma xml:lang="en"/> + <omega attrib="123456789" xml:id="id5"> + <omega content="content" xml:id="id6"> + <upsilon xml:lang="no-nb" xml:id="id7"> + <gamma attribute="attribute-value" xml:lang="nb"> + <green>This text must be green</green> + </gamma> + </upsilon> + </omega> + </omega> + </beta> + </pi> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/chi[contains(concat(@class,"$"),"k$")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[@xml:lang="nb"][not(preceding-sibling::*)]/mu[contains(@number,"ute")][@xml:lang="en-US"][not(following-sibling::*)]/kappa[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[starts-with(concat(@number,"-"),"attribute value-")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/iota[starts-with(concat(@number,"-"),"true-")][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id4"][following-sibling::upsilon[@xml:id="id5"][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <chi class="_blank" xml:lang="no" xml:id="id2"/> + <any> + <mu xml:lang="nb"> + <mu number="attribute" xml:lang="en-US"> + <kappa xml:lang="en-US"/> + <gamma number="attribute value" xml:lang="en" xml:id="id3"> + <iota number="true"/> + <rho xml:lang="en-GB" xml:id="id4"/> + <upsilon xml:id="id5"> + <green>This text must be green</green> + </upsilon> + </gamma> + </mu> + </mu> + </any> + </nu> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@attribute,"-"),"true-")][@xml:id="id1"]/chi[starts-with(concat(@or,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//beta[@content][@xml:id="id4"]//upsilon[@delete][@xml:id="id5"][not(following-sibling::*)]/rho[contains(@desciption,"tru")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]//nu[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::pi[@title][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omega[starts-with(@number,"123")][@xml:lang="no-nb"][@xml:id="id9"][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id10"]/sigma[@xml:lang="en-US"][@xml:id="id11"][following-sibling::omicron[@xml:lang="nb"][@xml:id="id12"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[starts-with(concat(@or,"-"),"123456789-")][@xml:id="id13"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <delta attribute="true" xml:id="id1"> + <chi or="this.nodeValue" xml:lang="nb" xml:id="id2"/> + <theta xml:lang="en-US"/> + <nu xml:lang="no-nb" xml:id="id3"> + <beta content="attribute-value" xml:id="id4"> + <upsilon delete="100%" xml:id="id5"> + <rho desciption="true" xml:lang="nb" xml:id="id6"> + <nu xml:lang="no-nb"/> + <pi title="false" xml:id="id7"/> + <omicron xml:lang="en-US"/> + <rho xml:lang="no-nb" xml:id="id8"/> + <omega number="123456789" xml:lang="no-nb" xml:id="id9"/> + <upsilon xml:lang="no-nb" xml:id="id10"> + <sigma xml:lang="en-US" xml:id="id11"/> + <omicron xml:lang="nb" xml:id="id12"/> + <tau or="123456789" xml:id="id13"> + <green>This text must be green</green> + </tau> + </upsilon> + </rho> + </upsilon> + </beta> + </nu> + </delta> + </tree> + </test> + <test> + <xpath>//epsilon[@object="attribute"][@xml:id="id1"]/mu[starts-with(@att,"1")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu//lambda[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@attrib][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::*[position()=3]][following-sibling::omicron[starts-with(concat(@title,"-"),"_blank-")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::omicron)][not(child::node())][following-sibling::upsilon[starts-with(concat(@number,"-"),"_blank-")][@xml:lang="en"][not(child::node())][following-sibling::iota[starts-with(concat(@delete,"-"),"100%-")][@xml:lang="no-nb"][@xml:id="id7"]/psi[not(following-sibling::*)]//iota[starts-with(@att,"this-is-att-valu")][@xml:id="id8"][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon object="attribute" xml:id="id1"> + <mu att="100%" xml:id="id2"> + <phi xml:id="id3"/> + <phi xml:id="id4"> + <nu> + <lambda xml:lang="no" xml:id="id5"/> + <tau attrib="true" xml:lang="en-GB" xml:id="id6"/> + <omicron title="_blank" xml:lang="en-US"/> + <upsilon number="_blank" xml:lang="en"/> + <iota delete="100%" xml:lang="no-nb" xml:id="id7"> + <psi> + <iota att="this-is-att-value" xml:id="id8"> + <green>This text must be green</green> + </iota> + </psi> + </iota> + </nu> + </phi> + </mu> + </epsilon> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(concat(@title,"-"),"content-")][@xml:id="id1"]/zeta[starts-with(concat(@att,"-"),"content-")][@xml:lang="en"]/psi[@att][@xml:lang="no"][not(following-sibling::*)][not(preceding-sibling::psi)]/xi[@or="attribute value"][not(child::node())][following-sibling::upsilon[not(following-sibling::*)]//alpha[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::xi[contains(@false,"fa")][@xml:lang="en"][following-sibling::*[position()=4]][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::iota[contains(concat(@object,"$")," attribute value$")][@xml:id="id2"][following-sibling::lambda[starts-with(concat(@title,"-"),"this-")][@xml:lang="no-nb"][@xml:id="id3"][not(child::node())][following-sibling::omicron[@xml:lang="en"][preceding-sibling::*[position() = 5]]/alpha[@data="123456789"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@data="solid 1px green"][@xml:lang="en-GB"]//delta[following-sibling::*[position()=1]][following-sibling::lambda[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:lang="en-US"]/sigma[starts-with(@name,"12")][@xml:lang="en-GB"]/phi[contains(concat(@attrib,"$"),"100%$")]//zeta[@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <omicron title="content" xml:id="id1"> + <zeta att="content" xml:lang="en"> + <psi att="solid 1px green" xml:lang="no"> + <xi or="attribute value"/> + <upsilon> + <alpha xml:lang="en-GB"/> + <xi false="false" xml:lang="en"/> + <xi xml:lang="en-GB"/> + <iota object="another attribute value" xml:id="id2"/> + <lambda title="this-is-att-value" xml:lang="no-nb" xml:id="id3"/> + <omicron xml:lang="en"> + <alpha data="123456789" xml:id="id4"> + <rho data="solid 1px green" xml:lang="en-GB"> + <delta/> + <lambda desciption="this.nodeValue" xml:lang="en-US"> + <sigma name="123456789" xml:lang="en-GB"> + <phi attrib="100%"> + <zeta xml:lang="en-GB"> + <green>This text must be green</green> + </zeta> + </phi> + </sigma> + </lambda> + </rho> + </alpha> + </omicron> + </upsilon> + </psi> + </zeta> + </omicron> + </tree> + </test> + <test> + <xpath>//chi[starts-with(concat(@object,"-"),"solid 1px green-")][@xml:lang="en-US"]/xi[contains(@string,"onte")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::iota[@insert="true"][preceding-sibling::*[position() = 1]]/mu[@number="another attribute value"][@xml:lang="nb"][not(child::node())][following-sibling::omicron[@or="this-is-att-value"][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]/eta[contains(@desciption,"deValue")][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 1]]/upsilon[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[@data="solid 1px green"][@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/*[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::lambda[starts-with(@attr,"1234")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]]//zeta[starts-with(concat(@string,"-"),"content-")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <chi object="solid 1px green" xml:lang="en-US"> + <xi string="content" xml:lang="nb"/> + <iota insert="true"> + <mu number="another attribute value" xml:lang="nb"/> + <omicron or="this-is-att-value" xml:lang="no-nb" xml:id="id1"> + <eta desciption="this.nodeValue"/> + <upsilon> + <upsilon/> + <epsilon data="solid 1px green" xml:lang="en-GB" xml:id="id2"> + <any xml:lang="en-GB" xml:id="id3"/> + <lambda attr="123456789" xml:lang="no" xml:id="id4"> + <zeta string="content"> + <green>This text must be green</green> + </zeta> + </lambda> + </epsilon> + </upsilon> + </omicron> + </iota> + </chi> + </tree> + </test> + <test> + <xpath>//epsilon[@data="true"]//lambda[starts-with(@attrib,"false")][@xml:lang="nb"][following-sibling::*[@xml:lang="no"][not(following-sibling::*)]/eta[contains(concat(@delete,"$"),"ribute value$")][@xml:lang="en-US"][@xml:id="id1"]/xi[@title][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id2"]//omicron[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@false="this.nodeValue"][following-sibling::mu[not(child::node())][following-sibling::*[starts-with(concat(@false,"-"),"another attribute value-")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::beta[starts-with(@content,"so")][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@att][@xml:id="id4"][not(following-sibling::*)][position() = 1]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <epsilon data="true"> + <lambda attrib="false" xml:lang="nb"/> + <any xml:lang="no"> + <eta delete="another attribute value" xml:lang="en-US" xml:id="id1"> + <xi title="false"/> + <upsilon xml:lang="no-nb" xml:id="id2"> + <omicron xml:id="id3"/> + <xi false="this.nodeValue"/> + <mu/> + <any false="another attribute value"/> + <beta content="solid 1px green"/> + <alpha att="123456789" xml:id="id4"> + <green>This text must be green</green> + </alpha> + </upsilon> + </eta> + </any> + </epsilon> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="en"][@xml:id="id1"]/*[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/omega[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[starts-with(@data,"thi")][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@false][following-sibling::*[position()=1]][not(preceding-sibling::eta)][following-sibling::theta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]]/iota[not(preceding-sibling::*)]//epsilon[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="en" xml:id="id1"> + <any xml:lang="en-US" xml:id="id2"> + <omega xml:lang="nb"> + <tau data="this-is-att-value"> + <epsilon xml:lang="en-US"/> + <eta false="this-is-att-value"/> + <theta xml:lang="no" xml:id="id3"> + <iota> + <epsilon xml:id="id4"> + <green>This text must be green</green> + </epsilon> + </iota> + </theta> + </tau> + </omega> + </any> + </rho> + </tree> + </test> + <test> + <xpath>//eta[contains(@token,"bla")][@xml:lang="no"][@xml:id="id1"]/tau[@attribute="another attribute value"][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@abort="this-is-att-value"][@xml:lang="en-US"][not(child::node())][following-sibling::delta[starts-with(concat(@title,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@token][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=4]][not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=3]][following-sibling::xi[@xml:lang="no"][@xml:id="id6"][following-sibling::beta[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::kappa[contains(concat(@desciption,"$"),"alse$")][@xml:id="id7"][not(following-sibling::*)]/kappa[not(following-sibling::*)]//theta[@xml:id="id8"][not(child::node())][following-sibling::omicron[@data][following-sibling::psi[@xml:lang="nb"][not(following-sibling::*)]//rho[contains(@token,"t")][@xml:lang="nb"][not(following-sibling::*)][not(preceding-sibling::rho)]//omega[@xml:lang="en-GB"][@xml:id="id9"][not(following-sibling::*)]/eta[starts-with(@false,"t")][@xml:lang="en-GB"]/eta[@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)]//omicron[@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <eta token="_blank" xml:lang="no" xml:id="id1"> + <tau attribute="another attribute value" xml:lang="no-nb" xml:id="id2"> + <kappa abort="this-is-att-value" xml:lang="en-US"/> + <delta title="this.nodeValue" xml:lang="nb" xml:id="id3"> + <any token="content" xml:lang="no-nb" xml:id="id4"/> + <theta xml:lang="en" xml:id="id5"/> + <xi xml:lang="no" xml:id="id6"/> + <beta xml:lang="no"/> + <kappa desciption="false" xml:id="id7"> + <kappa> + <theta xml:id="id8"/> + <omicron data="_blank"/> + <psi xml:lang="nb"> + <rho token="true" xml:lang="nb"> + <omega xml:lang="en-GB" xml:id="id9"> + <eta false="true" xml:lang="en-GB"> + <eta xml:lang="en-US" xml:id="id10"> + <omicron xml:id="id11"> + <green>This text must be green</green> + </omicron> + </eta> + </eta> + </omega> + </rho> + </psi> + </kappa> + </kappa> + </delta> + </tau> + </eta> + </tree> + </test> + <test> + <xpath>//chi[@attrib="content"][@xml:id="id1"]/nu[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="nb"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[@xml:id="id4"]//beta[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::lambda[contains(concat(@name,"$"),"his-is-att-value$")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[contains(concat(@att,"$"),"deValue$")][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <chi attrib="content" xml:id="id1"> + <nu xml:lang="no" xml:id="id2"/> + <gamma xml:lang="nb" xml:id="id3"/> + <sigma xml:id="id4"> + <beta xml:lang="en-GB"/> + <lambda name="this-is-att-value" xml:lang="en-US" xml:id="id5"/> + <sigma att="this.nodeValue" xml:lang="no" xml:id="id6"> + <green>This text must be green</green> + </sigma> + </sigma> + </chi> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="en-US"][@xml:id="id1"]//omega[@xml:lang="no"][@xml:id="id2"]//*[@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]//sigma[@name][@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]/pi[starts-with(@token,"attribute-va")][@xml:lang="no-nb"][not(preceding-sibling::*)]/epsilon[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::sigma[@true][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[starts-with(@attr,"_bla")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::theta[@xml:lang="en"][@xml:id="id6"]//eta[@name][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@name][@xml:lang="nb"][following-sibling::*[position()=3]][following-sibling::eta[@title][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::lambda[@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::pi[@xml:id="id9"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/omicron[not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:lang="no-nb"][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id10"][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="en-US" xml:id="id1"> + <omega xml:lang="no" xml:id="id2"> + <any xml:lang="en-GB" xml:id="id3"> + <sigma name="attribute-value" xml:lang="en" xml:id="id4"> + <pi token="attribute-value" xml:lang="no-nb"> + <epsilon xml:lang="en"/> + <sigma true="100%" xml:id="id5"/> + <theta attr="_blank" xml:lang="nb"/> + <theta xml:lang="en" xml:id="id6"> + <eta name="attribute" xml:lang="en" xml:id="id7"/> + <lambda name="123456789" xml:lang="nb"/> + <eta title="solid 1px green" xml:lang="nb"/> + <lambda xml:id="id8"/> + <pi xml:id="id9"> + <omicron> + <psi xml:lang="no-nb"/> + <delta xml:lang="no-nb" xml:id="id10"/> + <sigma xml:lang="en-GB"> + <green>This text must be green</green> + </sigma> + </omicron> + </pi> + </theta> + </pi> + </sigma> + </any> + </omega> + </lambda> + </tree> + </test> + <test> + <xpath>//eta[contains(@attrib,"lue")][@xml:id="id1"]/phi[@data][@xml:lang="en-GB"][following-sibling::omicron[contains(@attribute,"-att-val")][not(following-sibling::*)]/kappa[contains(@data,"t")][not(preceding-sibling::*)][following-sibling::nu[@title][following-sibling::*[position()=3]][following-sibling::delta[@xml:id="id2"][not(preceding-sibling::delta)][following-sibling::*[@xml:id="id3"][preceding-sibling::*[position() = 3]][following-sibling::xi[starts-with(concat(@delete,"-"),"another attribute value-")][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/theta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(@att,"tribu")][@xml:lang="no"][@xml:id="id6"][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@content][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@number][@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <eta attrib="this-is-att-value" xml:id="id1"> + <phi data="true" xml:lang="en-GB"/> + <omicron attribute="this-is-att-value"> + <kappa data="content"/> + <nu title="_blank"/> + <delta xml:id="id2"/> + <any xml:id="id3"/> + <xi delete="another attribute value" xml:id="id4"> + <theta xml:lang="en-GB" xml:id="id5"> + <rho att="another attribute value" xml:lang="no" xml:id="id6"/> + <omicron> + <psi content="123456789" xml:lang="nb" xml:id="id7"> + <sigma number="false" xml:lang="nb" xml:id="id8"> + <green>This text must be green</green> + </sigma> + </psi> + </omicron> + </theta> + </xi> + </omicron> + </eta> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no-nb"][@xml:id="id1"]//tau[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::psi[@xml:id="id3"][preceding-sibling::*[position() = 1]]//xi[contains(concat(@false,"$"),"alse$")][@xml:id="id4"][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[not(preceding-sibling::*)]/alpha[@xml:id="id5"]/phi[@att][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::upsilon[@and][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no-nb" xml:id="id1"> + <tau xml:lang="nb" xml:id="id2"/> + <psi xml:id="id3"> + <xi false="false" xml:id="id4"/> + <kappa> + <lambda> + <alpha xml:id="id5"> + <phi att="_blank"/> + <gamma/> + <upsilon and="this.nodeValue" xml:id="id6"> + <omega xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </omega> + </upsilon> + </alpha> + </lambda> + </kappa> + </psi> + </beta> + </tree> + </test> + <test> + <xpath>//mu[@class]//pi[starts-with(concat(@delete,"-"),"true-")][not(following-sibling::*)]/omicron[contains(concat(@insert,"$"),"456789$")][@xml:lang="en-GB"][not(child::node())][following-sibling::lambda[@object][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]/delta[@or="_blank"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(concat(@true,"-"),"100%-")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[contains(@name,"ttribut")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)]/kappa[contains(concat(@token,"$"),"attribute$")][@xml:lang="no-nb"][not(following-sibling::*)]/pi[@false][@xml:id="id4"][following-sibling::phi[@and][@xml:id="id5"][not(following-sibling::*)]/rho[starts-with(concat(@false,"-"),"attribute-")][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:id="id6"][not(following-sibling::*)]//lambda[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@name][@xml:lang="nb"][@xml:id="id8"][following-sibling::*[position()=3]][not(child::node())][following-sibling::lambda[@xml:lang="en"][@xml:id="id9"][not(child::node())][following-sibling::alpha[starts-with(@delete,"a")][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="no"][@xml:id="id10"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <mu class="attribute-value"> + <pi delete="true"> + <omicron insert="123456789" xml:lang="en-GB"/> + <lambda object="false" xml:lang="no-nb" xml:id="id1"> + <delta or="_blank"> + <zeta true="100%" xml:id="id2"> + <tau name="attribute value" xml:lang="nb" xml:id="id3"> + <kappa token="attribute" xml:lang="no-nb"> + <pi false="solid 1px green" xml:id="id4"/> + <phi and="attribute" xml:id="id5"> + <rho false="attribute"/> + <gamma xml:id="id6"> + <lambda xml:id="id7"> + <phi name="attribute-value" xml:lang="nb" xml:id="id8"/> + <lambda xml:lang="en" xml:id="id9"/> + <alpha delete="attribute value" xml:lang="en"/> + <xi xml:lang="no" xml:id="id10"> + <green>This text must be green</green> + </xi> + </lambda> + </gamma> + </phi> + </kappa> + </tau> + </zeta> + </delta> + </lambda> + </pi> + </mu> + </tree> + </test> + <test> + <xpath>//nu[@attribute][@xml:lang="en"]//xi[contains(@object,"e")][@xml:lang="no"][@xml:id="id1"][following-sibling::*[position()=5]][not(child::node())][following-sibling::psi[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::pi[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega[starts-with(@name,"false")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::upsilon[@xml:lang="nb"][@xml:id="id4"][following-sibling::sigma[@true][@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]/xi[@src][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]//*[@attrib][@xml:id="id7"][not(child::node())][following-sibling::psi[starts-with(@attribute,"tr")][@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]/rho[@xml:id="id9"]/omicron[@desciption][@xml:lang="en"][not(preceding-sibling::omicron)][following-sibling::xi[not(following-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <nu attribute="_blank" xml:lang="en"> + <xi object="attribute-value" xml:lang="no" xml:id="id1"/> + <psi xml:lang="nb" xml:id="id2"/> + <pi xml:lang="en-US" xml:id="id3"/> + <omega name="false" xml:lang="en-GB"/> + <upsilon xml:lang="nb" xml:id="id4"/> + <sigma true="true" xml:lang="en-US" xml:id="id5"> + <xi src="true" xml:lang="no" xml:id="id6"> + <any attrib="another attribute value" xml:id="id7"/> + <psi attribute="true" xml:lang="en-GB" xml:id="id8"> + <rho xml:id="id9"> + <omicron desciption="100%" xml:lang="en"/> + <xi> + <green>This text must be green</green> + </xi> + </rho> + </psi> + </xi> + </sigma> + </nu> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//gamma[@token][@xml:lang="no"][@xml:id="id2"][following-sibling::*[position()=3]][following-sibling::tau[@xml:lang="en-GB"][following-sibling::*[position()=2]][following-sibling::xi[@xml:id="id3"][not(child::node())][following-sibling::xi[@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//upsilon[@xml:id="id5"][not(preceding-sibling::*)]/omega[contains(concat(@true,"$"),"0%$")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::nu[preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[@number="100%"][@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]/upsilon[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(@desciption,"t")][@xml:lang="en-US"][@xml:id="id9"]/*]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <gamma token="attribute" xml:lang="no" xml:id="id2"/> + <tau xml:lang="en-GB"/> + <xi xml:id="id3"/> + <xi xml:id="id4"> + <upsilon xml:id="id5"> + <omega true="100%" xml:lang="en-GB" xml:id="id6"/> + <nu/> + <omega xml:lang="en"/> + <iota number="100%" xml:lang="en" xml:id="id7"> + <upsilon xml:lang="en-GB" xml:id="id8"> + <beta desciption="true" xml:lang="en-US" xml:id="id9"> + <any> + <green>This text must be green</green> + </any> + </beta> + </upsilon> + </iota> + </upsilon> + </xi> + </chi> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="en"]//tau[contains(concat(@true,"$"),"attribute value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(preceding-sibling::tau)]/omega[@false="attribute value"][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)]//phi[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::rho[contains(concat(@att,"$"),"lank$")][not(following-sibling::*)]/eta[@xml:id="id2"][following-sibling::*[position()=3]][following-sibling::omicron[starts-with(concat(@att,"-"),"false-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::rho[@xml:id="id3"][following-sibling::delta[@xml:lang="en"][not(preceding-sibling::delta)]//omega[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/rho/alpha[following-sibling::*[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::sigma[@abort][@xml:id="id5"][not(following-sibling::*)]/omicron[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::chi[@xml:id="id7"][not(child::node())][following-sibling::iota[starts-with(concat(@true,"-"),"solid 1px green-")][@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::kappa[@xml:id="id9"]/nu[@and][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::iota[@or][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[@xml:lang="no"][following-sibling::gamma[@att="this.nodeValue"][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="en"> + <tau true="another attribute value" xml:lang="no-nb"> + <omega false="attribute value" xml:lang="nb" xml:id="id1"> + <phi xml:lang="nb"/> + <rho att="_blank"> + <eta xml:id="id2"/> + <omicron att="false" xml:lang="en"/> + <rho xml:id="id3"/> + <delta xml:lang="en"> + <omega xml:lang="en-US" xml:id="id4"> + <rho> + <alpha/> + <any/> + <sigma abort="content" xml:id="id5"> + <omicron xml:id="id6"/> + <phi xml:lang="en"/> + <chi xml:id="id7"/> + <iota true="solid 1px green" xml:id="id8"/> + <kappa xml:id="id9"> + <nu and="_blank" xml:id="id10"/> + <iota or="false" xml:lang="en-US"> + <iota xml:lang="no"/> + <gamma att="this.nodeValue" xml:lang="no"> + <green>This text must be green</green> + </gamma> + </iota> + </kappa> + </sigma> + </rho> + </omega> + </delta> + </rho> + </omega> + </tau> + </nu> + </tree> + </test> + <test> + <xpath>//upsilon[contains(@insert,"true")][@xml:lang="no"]//delta[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[starts-with(concat(@string,"-"),"this.nodeValue-")][@xml:id="id2"][not(child::node())][following-sibling::iota[@desciption][@xml:id="id3"][not(child::node())][following-sibling::psi[@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho/zeta[@xml:id="id5"][not(child::node())][following-sibling::beta[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <upsilon insert="true" xml:lang="no"> + <delta and="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <omicron string="this.nodeValue" xml:id="id2"/> + <iota desciption="attribute value" xml:id="id3"/> + <psi xml:lang="nb" xml:id="id4"/> + <rho> + <zeta xml:id="id5"/> + <beta xml:id="id6"> + <green>This text must be green</green> + </beta> + </rho> + </delta> + </upsilon> + </tree> + </test> + <test> + <xpath>//psi[@abort][@xml:lang="en"]/beta[starts-with(concat(@attribute,"-"),"123456789-")][@xml:id="id1"]/tau[@attr]/beta[@name][following-sibling::phi[contains(concat(@object,"$"),"lse$")][@xml:id="id2"][not(following-sibling::*)]/psi[starts-with(@abort,"f")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@number][@xml:lang="en-US"]/rho[starts-with(concat(@desciption,"-"),"_blank-")][@xml:id="id3"]/omicron[@att][@xml:lang="nb"][@xml:id="id4"][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>1</nth> + </result> + <tree> + <psi abort="solid 1px green" xml:lang="en"> + <beta attribute="123456789" xml:id="id1"> + <tau attr="false"> + <beta name="another attribute value"/> + <phi object="false" xml:id="id2"> + <psi abort="false" xml:lang="en-GB"/> + <omicron number="another attribute value" xml:lang="en-US"> + <rho desciption="_blank" xml:id="id3"> + <omicron att="solid 1px green" xml:lang="nb" xml:id="id4"> + <green>This text must be green</green> + </omicron> + </rho> + </omicron> + </phi> + </tau> + </beta> + </psi> + </tree> + </test> + <test> + <xpath>//lambda[contains(@src,"attribute-valu")][@xml:id="id1"]//upsilon[@xml:lang="en-US"][not(child::node())][following-sibling::nu[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(preceding-sibling::nu or following-sibling::nu)][not(preceding-sibling::nu)][following-sibling::lambda[@data][@xml:id="id3"][not(following-sibling::*)]//theta[@string="attribute"][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[not(child::node())][following-sibling::pi[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@class="attribute"][@xml:lang="nb"][preceding-sibling::*[position() = 3]]/lambda[starts-with(concat(@title,"-"),"this.nodeValue-")][@xml:lang="no-nb"][@xml:id="id6"][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::phi[contains(@title,"ue")][@xml:lang="en"][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@attr="100%"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::kappa[starts-with(@delete,"1234")][@xml:lang="no-nb"][not(following-sibling::*)]//gamma[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id8"][following-sibling::sigma[@or][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <lambda src="attribute-value" xml:id="id1"> + <upsilon xml:lang="en-US"/> + <nu xml:lang="no" xml:id="id2"/> + <lambda data="_blank" xml:id="id3"> + <theta string="attribute" xml:lang="en" xml:id="id4"/> + <alpha/> + <pi xml:lang="en-US" xml:id="id5"/> + <rho class="attribute" xml:lang="nb"> + <lambda title="this.nodeValue" xml:lang="no-nb" xml:id="id6"/> + <xi/> + <iota xml:lang="nb" xml:id="id7"/> + <phi title="attribute-value" xml:lang="en"/> + <omicron attr="100%"/> + <kappa delete="123456789" xml:lang="no-nb"> + <gamma xml:lang="no"/> + <gamma xml:lang="no-nb" xml:id="id8"/> + <sigma or="content" xml:lang="nb"> + <green>This text must be green</green> + </sigma> + </kappa> + </rho> + </lambda> + </lambda> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]//pi[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]//phi[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id4"][preceding-sibling::*[position() = 1]]/sigma[contains(concat(@delete,"$"),"x green$")][following-sibling::kappa[contains(@true,"ibute val")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@title][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <phi xml:id="id1"> + <pi xml:lang="no" xml:id="id2"> + <phi xml:id="id3"/> + <upsilon xml:id="id4"> + <sigma delete="solid 1px green"/> + <kappa true="another attribute value" xml:id="id5"/> + <alpha title="attribute value"> + <green>This text must be green</green> + </alpha> + </upsilon> + </pi> + </phi> + </tree> + </test> + <test> + <xpath>//omicron[@src="this-is-att-value"][@xml:lang="no"]/upsilon[@and="attribute-value"][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[contains(concat(@or,"$"),"nodeValue$")][@xml:id="id1"][not(following-sibling::*)]/pi[@attrib][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:lang="no"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[@xml:id="id4"][not(child::node())][following-sibling::delta[@attr][@xml:lang="nb"]//mu[not(preceding-sibling::*)][not(following-sibling::*)]//*[@insert="123456789"][@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)][not(preceding-sibling::lambda)]/chi[@xml:lang="no-nb"][not(preceding-sibling::*)]//nu[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omicron src="this-is-att-value" xml:lang="no"> + <upsilon and="attribute-value" xml:lang="no"/> + <iota or="this.nodeValue" xml:id="id1"> + <pi attrib="attribute value" xml:id="id2"/> + <alpha xml:lang="no" xml:id="id3"/> + <chi xml:id="id4"/> + <delta attr="attribute value" xml:lang="nb"> + <mu> + <any insert="123456789" xml:lang="nb" xml:id="id5"/> + <lambda xml:lang="en-GB" xml:id="id6"> + <chi xml:lang="no-nb"> + <nu xml:lang="en" xml:id="id7"> + <green>This text must be green</green> + </nu> + </chi> + </lambda> + </mu> + </delta> + </iota> + </omicron> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@src,"$"),"e$")][@xml:lang="no"][@xml:id="id1"]//omicron[@xml:id="id2"][not(child::node())][following-sibling::nu[contains(@number,"lid 1px gre")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[@xml:id="id4"][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 3]]/pi[starts-with(@desciption,"another attribute va")][@xml:id="id5"]//omega[@false][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <iota src="true" xml:lang="no" xml:id="id1"> + <omicron xml:id="id2"/> + <nu number="solid 1px green" xml:id="id3"/> + <mu xml:id="id4"/> + <gamma> + <pi desciption="another attribute value" xml:id="id5"> + <omega false="123456789"> + <green>This text must be green</green> + </omega> + </pi> + </gamma> + </iota> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no"]/nu[contains(concat(@class,"$"),"ontent$")][@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[not(child::node())][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(preceding-sibling::delta)][following-sibling::theta[@xml:id="id3"][preceding-sibling::*[position() = 3]]//omicron[@desciption][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(@content,"fa")][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][not(child::node())][following-sibling::tau[contains(@delete,"value")][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::tau[@xml:lang="nb"][@xml:id="id5"]//iota[not(preceding-sibling::*)]/omicron[contains(@and,"ue")][@xml:lang="no"][@xml:id="id6"]/mu[contains(concat(@insert,"$"),"lue$")][@xml:id="id7"][not(preceding-sibling::*)]/phi[contains(@desciption,"0%")][@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/omega[@xml:lang="no"][@xml:id="id9"][following-sibling::epsilon[@attr][@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]]//tau[@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="en-US"][not(preceding-sibling::*)]/rho[not(child::node())][following-sibling::zeta[contains(concat(@true,"$"),"en$")][@xml:id="id12"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(@attr,"solid 1px")][@xml:id="id13"][preceding-sibling::*[position() = 2]]//xi[@xml:lang="no-nb"][@xml:id="id14"][not(following-sibling::*)]/phi[not(preceding-sibling::*)]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no"> + <nu class="content" xml:lang="en" xml:id="id1"/> + <xi/> + <delta xml:id="id2"/> + <theta xml:id="id3"> + <omicron desciption="100%"> + <beta content="false"/> + <kappa xml:lang="no-nb"/> + <tau delete="this-is-att-value" xml:id="id4"/> + <tau xml:lang="nb" xml:id="id5"> + <iota> + <omicron and="attribute-value" xml:lang="no" xml:id="id6"> + <mu insert="this.nodeValue" xml:id="id7"> + <phi desciption="100%" xml:lang="nb" xml:id="id8"/> + <gamma xml:lang="en-US"> + <omega xml:lang="no" xml:id="id9"/> + <epsilon attr="attribute value" xml:lang="nb" xml:id="id10"> + <tau xml:lang="nb" xml:id="id11"> + <psi false="123456789" xml:lang="en-US"> + <rho/> + <zeta true="solid 1px green" xml:id="id12"/> + <delta attr="solid 1px green" xml:id="id13"> + <xi xml:lang="no-nb" xml:id="id14"> + <phi> + <green>This text must be green</green> + </phi> + </xi> + </delta> + </psi> + </tau> + </epsilon> + </gamma> + </mu> + </omicron> + </iota> + </tau> + </omicron> + </theta> + </kappa> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="no-nb"][@xml:id="id1"]//psi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/omicron[@data][@xml:lang="en-GB"][not(preceding-sibling::*)]/*[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@abort][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:lang="en-US"][not(following-sibling::*)]/*[starts-with(@and,"fals")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="no-nb" xml:id="id1"> + <psi xml:lang="en-GB"/> + <omicron xml:lang="en-US"> + <omicron data="false" xml:lang="en-GB"> + <any xml:lang="en-GB"> + <xi abort="attribute" xml:lang="en-GB" xml:id="id2"> + <any xml:lang="en-US"> + <any and="false" xml:lang="no-nb" xml:id="id3"> + <green>This text must be green</green> + </any> + </any> + </xi> + </any> + </omicron> + </omicron> + </omicron> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no-nb"]//omicron[@xml:id="id1"][not(preceding-sibling::*)]//omega[@class="_blank"]/xi[contains(@and,"ue")][@xml:lang="no"][@xml:id="id2"]//pi[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@attrib][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::omega[@content][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[contains(concat(@abort,"$"),"ontent$")][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::psi[contains(concat(@or,"$"),"te-value$")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@class][@xml:id="id6"]//phi[@xml:lang="nb"][not(preceding-sibling::*)]//delta[contains(@att,"00%")][@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no-nb"> + <omicron xml:id="id1"> + <omega class="_blank"> + <xi and="attribute value" xml:lang="no" xml:id="id2"> + <pi xml:id="id3"> + <delta attrib="123456789" xml:lang="en"/> + <omega content="solid 1px green"/> + <alpha abort="content" xml:lang="en-GB" xml:id="id4"/> + <psi or="attribute-value" xml:lang="no-nb" xml:id="id5"/> + <omicron class="false" xml:id="id6"> + <phi xml:lang="nb"> + <delta att="100%" xml:id="id7"> + <green>This text must be green</green> + </delta> + </phi> + </omicron> + </pi> + </xi> + </omega> + </omicron> + </psi> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]/zeta[@xml:lang="en-US"][not(preceding-sibling::*)]/nu[starts-with(@title,"con")][@xml:id="id2"][not(following-sibling::*)]//phi[starts-with(concat(@and,"-"),"true-")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="nb"]//psi[@xml:lang="no-nb"][@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <kappa xml:id="id1"> + <zeta xml:lang="en-US"> + <nu title="content" xml:id="id2"> + <phi and="true" xml:lang="en" xml:id="id3"> + <phi xml:id="id4"/> + <lambda xml:lang="nb"> + <psi xml:lang="no-nb" xml:id="id5"/> + <beta xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </beta> + </lambda> + </phi> + </nu> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-US"]//psi[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:lang="no"][not(preceding-sibling::*)]//omicron[@attr="true"][@xml:lang="nb"][following-sibling::epsilon[@delete][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::tau[not(following-sibling::*)]/phi[following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[starts-with(concat(@true,"-"),"attribute value-")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/xi[not(preceding-sibling::*)][not(child::node())][following-sibling::rho[contains(@content,"tribute value")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[@xml:id="id4"][following-sibling::gamma[not(following-sibling::*)]//theta[@xml:id="id5"]/xi[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::pi[starts-with(concat(@abort,"-"),"this-")][@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[preceding-sibling::*[position() = 2]]//kappa[starts-with(concat(@token,"-"),"100%-")][@xml:lang="en-US"][not(child::node())][following-sibling::iota[starts-with(concat(@abort,"-"),"123456789-")][@xml:id="id8"][preceding-sibling::*[position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-US"> + <psi xml:id="id1"> + <tau xml:lang="no"> + <omicron attr="true" xml:lang="nb"/> + <epsilon delete="content"/> + <theta xml:lang="en-US" xml:id="id2"/> + <tau> + <phi/> + <beta true="attribute value" xml:id="id3"/> + <pi xml:lang="en-US"> + <xi/> + <rho content="another attribute value"/> + <chi xml:id="id4"/> + <gamma> + <theta xml:id="id5"> + <xi xml:lang="en-US" xml:id="id6"/> + <pi abort="this-is-att-value" xml:lang="no" xml:id="id7"/> + <delta> + <kappa token="100%" xml:lang="en-US"/> + <iota abort="123456789" xml:id="id8"> + <green>This text must be green</green> + </iota> + </delta> + </theta> + </gamma> + </pi> + </tau> + </tau> + </psi> + </any> + </tree> + </test> + <test> + <xpath>//omega[@data="100%"][@xml:lang="en"][@xml:id="id1"]/alpha[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(preceding-sibling::alpha)][following-sibling::xi[starts-with(concat(@and,"-"),"attribute-")][@xml:id="id3"][following-sibling::*[position()=4]][not(child::node())][following-sibling::psi[@desciption][following-sibling::*[position()=3]][not(child::node())][following-sibling::xi[not(child::node())][following-sibling::*[contains(@desciption,"nten")][@xml:id="id4"][not(child::node())][following-sibling::pi[@xml:lang="en-US"][not(following-sibling::*)]/lambda[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@and="this-is-att-value"][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]//phi[@xml:lang="no"][not(child::node())][following-sibling::xi[contains(concat(@and,"$"),"nk$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <omega data="100%" xml:lang="en" xml:id="id1"> + <alpha xml:lang="no" xml:id="id2"/> + <xi and="attribute" xml:id="id3"/> + <psi desciption="100%"/> + <xi/> + <any desciption="content" xml:id="id4"/> + <pi xml:lang="en-US"> + <lambda xml:id="id5"> + <pi and="this-is-att-value" xml:lang="en" xml:id="id6"> + <phi xml:lang="no"/> + <xi and="_blank" xml:lang="en-US"> + <green>This text must be green</green> + </xi> + </pi> + </lambda> + </pi> + </omega> + </tree> + </test> + <test> + <xpath>//beta[@attribute][@xml:lang="no"]/*[@xml:lang="en-GB"][not(preceding-sibling::*)]//rho[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="en"]//xi[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id3"]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <beta attribute="false" xml:lang="no"> + <any xml:lang="en-GB"> + <rho xml:lang="no"> + <iota> + <kappa xml:lang="en-GB" xml:id="id1"> + <rho xml:lang="en"> + <xi xml:id="id2"/> + <sigma xml:lang="en-US" xml:id="id3"> + <green>This text must be green</green> + </sigma> + </rho> + </kappa> + </iota> + </rho> + </any> + </beta> + </tree> + </test> + <test> + <xpath>//beta[starts-with(@attr,"attribu")]/xi[contains(@number,"id 1px ")][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[contains(@attrib,"e")][@xml:id="id1"][not(following-sibling::*)]//zeta[starts-with(@desciption,"t")][@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]/nu[starts-with(@desciption,"fals")][not(preceding-sibling::*)][not(following-sibling::*)]/rho[starts-with(@or,"another attribut")][@xml:lang="no"][@xml:id="id3"][following-sibling::omicron[@xml:lang="nb"]//omega[@xml:lang="no"][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <beta attr="attribute-value"> + <xi number="solid 1px green"/> + <pi attrib="true" xml:id="id1"> + <zeta desciption="this-is-att-value" xml:lang="en" xml:id="id2"> + <nu desciption="false"> + <rho or="another attribute value" xml:lang="no" xml:id="id3"/> + <omicron xml:lang="nb"> + <omega xml:lang="no"> + <green>This text must be green</green> + </omega> + </omicron> + </nu> + </zeta> + </pi> + </beta> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/pi[starts-with(@abort,"1")][@xml:lang="no"][@xml:id="id2"][following-sibling::eta[starts-with(@att,"1")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[contains(@delete,"e")][@xml:lang="en-US"][not(preceding-sibling::*)]//beta[@xml:id="id3"][not(preceding-sibling::*)]/omega[starts-with(concat(@false,"-"),"100%-")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[starts-with(@attr,"attribute-v")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]/eta[@true="this-is-att-value"][@xml:lang="no-nb"][@xml:id="id6"]/sigma[@true="attribute value"][@xml:lang="no"][@xml:id="id7"][not(following-sibling::*)]/omega[not(preceding-sibling::*)]/alpha[contains(concat(@content,"$")," attribute value$")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@number][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::epsilon[following-sibling::epsilon[@xml:lang="en-GB"]/psi[@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[not(preceding-sibling::*)][following-sibling::iota[not(child::node())][following-sibling::phi[@xml:id="id11"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/epsilon[@xml:id="id12"][not(following-sibling::*)]/pi[@xml:id="id13"][not(preceding-sibling::*)]//*[@xml:lang="en-GB"][@xml:id="id14"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(concat(@token,"-"),"content-")][@xml:lang="no-nb"][@xml:id="id15"]/tau[@object][@xml:id="id16"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <pi abort="123456789" xml:lang="no" xml:id="id2"/> + <eta att="123456789" xml:lang="no"> + <tau delete="true" xml:lang="en-US"> + <beta xml:id="id3"> + <omega false="100%" xml:lang="en" xml:id="id4"> + <phi xml:lang="nb"/> + <gamma attr="attribute-value" xml:lang="no-nb" xml:id="id5"> + <eta true="this-is-att-value" xml:lang="no-nb" xml:id="id6"> + <sigma true="attribute value" xml:lang="no" xml:id="id7"> + <omega> + <alpha content="another attribute value" xml:id="id8"> + <beta number="attribute" xml:lang="en" xml:id="id9"/> + <epsilon/> + <epsilon xml:lang="en-GB"> + <psi xml:id="id10"> + <chi/> + <iota/> + <phi xml:id="id11"> + <epsilon xml:id="id12"> + <pi xml:id="id13"> + <any xml:lang="en-GB" xml:id="id14"/> + <kappa token="content" xml:lang="no-nb" xml:id="id15"> + <tau object="attribute-value" xml:id="id16"> + <green>This text must be green</green> + </tau> + </kappa> + </pi> + </epsilon> + </phi> + </psi> + </epsilon> + </alpha> + </omega> + </sigma> + </eta> + </gamma> + </omega> + </beta> + </tau> + </eta> + </nu> + </tree> + </test> + <test> + <xpath>//iota[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:id="id1"]/psi[starts-with(concat(@attribute,"-"),"another attribute value-")][@xml:id="id2"]/mu[@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@attr][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="no"][not(child::node())][following-sibling::iota[contains(@insert,"lid 1")][not(following-sibling::*)]/beta[@xml:id="id5"][not(preceding-sibling::*)]/beta[@string="true"][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::epsilon[contains(concat(@src,"$"),"ribute value$")][@xml:lang="en-US"][@xml:id="id6"]//omega[@xml:lang="en-US"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <iota desciption="this.nodeValue" xml:id="id1"> + <psi attribute="another attribute value" xml:id="id2"> + <mu xml:lang="en" xml:id="id3"> + <kappa attr="attribute-value" xml:lang="no" xml:id="id4"/> + <xi xml:lang="no"/> + <iota insert="solid 1px green"> + <beta xml:id="id5"> + <beta string="true" xml:lang="en-GB"/> + <epsilon src="another attribute value" xml:lang="en-US" xml:id="id6"> + <omega xml:lang="en-US"> + <green>This text must be green</green> + </omega> + </epsilon> + </beta> + </iota> + </mu> + </psi> + </iota> + </tree> + </test> + <test> + <xpath>//omicron[@string][@xml:id="id1"]/nu[starts-with(@false,"co")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::theta//pi[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::nu[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@attribute][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(preceding-sibling::alpha)][following-sibling::lambda[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::psi[@attrib][@xml:lang="en"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]]]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <omicron string="false" xml:id="id1"> + <nu false="content" xml:lang="nb"/> + <theta> + <pi xml:lang="nb" xml:id="id2"/> + <nu xml:lang="no"/> + <alpha attribute="attribute" xml:lang="nb"/> + <lambda xml:lang="en-GB"/> + <psi attrib="false" xml:lang="en"> + <green>This text must be green</green> + </psi> + </theta> + </omicron> + </tree> + </test> + <test> + <xpath>//gamma[@string][@xml:lang="en"]//tau[@token][@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]//zeta[starts-with(@object,"conten")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@true][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 2]]//iota[@string="123456789"]//epsilon[starts-with(@att,"this.nodeValu")][@xml:lang="en-GB"][@xml:id="id5"][not(child::node())][following-sibling::upsilon[@xml:id="id6"][preceding-sibling::*[position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <gamma string="this.nodeValue" xml:lang="en"> + <tau token="_blank" xml:lang="no-nb" xml:id="id1"> + <zeta object="content" xml:lang="no-nb" xml:id="id2"/> + <epsilon true="content" xml:lang="no-nb" xml:id="id3"/> + <any xml:id="id4"> + <iota string="123456789"> + <epsilon att="this.nodeValue" xml:lang="en-GB" xml:id="id5"/> + <upsilon xml:id="id6"> + <green>This text must be green</green> + </upsilon> + </iota> + </any> + </tau> + </gamma> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no-nb"][@xml:id="id1"]/nu[@attribute][@xml:lang="no"][@xml:id="id2"]//eta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[contains(@class,"ntent")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//rho[starts-with(concat(@or,"-"),"false-")][following-sibling::kappa[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::gamma[not(child::node())][following-sibling::xi[@object][not(child::node())][following-sibling::iota[@string][preceding-sibling::*[position() = 4]][not(preceding-sibling::iota)][following-sibling::upsilon[@desciption]//lambda[contains(concat(@string,"$")," value$")][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@attr][@xml:lang="en-GB"][@xml:id="id5"][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no-nb" xml:id="id1"> + <nu attribute="this.nodeValue" xml:lang="no" xml:id="id2"> + <eta xml:lang="no"> + <omicron class="content" xml:lang="no-nb" xml:id="id3"> + <rho or="false"/> + <kappa xml:lang="en" xml:id="id4"/> + <gamma/> + <xi object="true"/> + <iota string="solid 1px green"/> + <upsilon desciption="false"> + <lambda string="attribute value"/> + <pi attr="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </pi> + </upsilon> + </omicron> + </eta> + </nu> + </psi> + </tree> + </test> + <test> + <xpath>//kappa[@attr="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id1"]/omega[@xml:id="id2"][not(preceding-sibling::*)]/zeta[@xml:lang="nb"][@xml:id="id3"]/mu[@xml:lang="en-GB"][not(following-sibling::*)]//eta[@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::beta[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[@xml:lang="nb"][@xml:id="id6"][not(child::node())][following-sibling::alpha[starts-with(@false,"solid 1px ")][@xml:lang="nb"][@xml:id="id7"][not(child::node())][following-sibling::omega[contains(@src,"attribute")][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::mu[preceding-sibling::*[position() = 5]][following-sibling::*[position()=1]][following-sibling::epsilon[contains(concat(@delete,"$"),"en$")][@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]/xi[contains(@and,"00%")][@xml:lang="nb"][not(following-sibling::*)]//tau[@xml:lang="nb"]/alpha[starts-with(@name,"solid 1px gr")][@xml:lang="no"][not(preceding-sibling::*)]//pi[@xml:lang="no-nb"][not(following-sibling::*)]/kappa[@xml:lang="en"][@xml:id="id9"]/beta[@xml:id="id10"][not(following-sibling::*)]//omega[starts-with(@number,"con")][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[starts-with(@object,"attribute valu")][@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@attr="attribute value"][@xml:lang="no"][@xml:id="id12"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <kappa attr="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <omega xml:id="id2"> + <zeta xml:lang="nb" xml:id="id3"> + <mu xml:lang="en-GB"> + <eta xml:lang="nb" xml:id="id4"/> + <beta xml:lang="nb" xml:id="id5"/> + <eta xml:lang="nb" xml:id="id6"/> + <alpha false="solid 1px green" xml:lang="nb" xml:id="id7"/> + <omega src="attribute value" xml:lang="no-nb"/> + <mu/> + <epsilon delete="solid 1px green" xml:lang="en-US" xml:id="id8"> + <xi and="100%" xml:lang="nb"> + <tau xml:lang="nb"> + <alpha name="solid 1px green" xml:lang="no"> + <pi xml:lang="no-nb"> + <kappa xml:lang="en" xml:id="id9"> + <beta xml:id="id10"> + <omega number="content" xml:id="id11"> + <omicron object="attribute value" xml:lang="nb"/> + <alpha attr="attribute value" xml:lang="no" xml:id="id12"> + <green>This text must be green</green> + </alpha> + </omega> + </beta> + </kappa> + </pi> + </alpha> + </tau> + </xi> + </epsilon> + </mu> + </zeta> + </omega> + </kappa> + </tree> + </test> + <test> + <xpath>//kappa[contains(concat(@attr,"$"),"e-value$")][@xml:lang="en-US"][@xml:id="id1"]/mu[@xml:lang="no-nb"][@xml:id="id2"][following-sibling::alpha[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="nb"][not(following-sibling::*)]/alpha[starts-with(@desciption,"_")][@xml:lang="en"][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@xml:lang="nb"][not(child::node())][following-sibling::tau[contains(@attrib,"fal")][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <kappa attr="attribute-value" xml:lang="en-US" xml:id="id1"> + <mu xml:lang="no-nb" xml:id="id2"/> + <alpha xml:lang="no-nb"/> + <nu xml:lang="nb"> + <alpha desciption="_blank" xml:lang="en"/> + <iota xml:lang="nb"/> + <tau attrib="false" xml:lang="no-nb"/> + <any xml:lang="en-GB"> + <green>This text must be green</green> + </any> + </nu> + </kappa> + </tree> + </test> + <test> + <xpath>//beta[@data][@xml:lang="no-nb"][@xml:id="id1"]//tau[not(preceding-sibling::*)]//*[not(preceding-sibling::*)][not(child::node())][following-sibling::eta[starts-with(@name,"solid 1px gr")][following-sibling::pi[starts-with(@token,"attribute val")][@xml:lang="en"][not(following-sibling::*)][not(following-sibling::pi)]//tau[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::psi[@attribute][@xml:lang="en"]/*[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::theta[@string="this.nodeValue"][@xml:id="id4"][not(child::node())][following-sibling::upsilon[@delete][@xml:id="id5"][preceding-sibling::*[position() = 2]]/lambda[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <beta data="_blank" xml:lang="no-nb" xml:id="id1"> + <tau> + <any/> + <eta name="solid 1px green"/> + <pi token="attribute value" xml:lang="en"> + <tau xml:lang="nb" xml:id="id2"/> + <psi attribute="true" xml:lang="en"> + <any xml:id="id3"/> + <theta string="this.nodeValue" xml:id="id4"/> + <upsilon delete="another attribute value" xml:id="id5"> + <lambda xml:id="id6"> + <green>This text must be green</green> + </lambda> + </upsilon> + </psi> + </pi> + </tau> + </beta> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//psi[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(preceding-sibling::psi or following-sibling::psi)]/omega[@data][following-sibling::pi[@xml:id="id3"][following-sibling::omega[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[@attrib][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::gamma[starts-with(concat(@class,"-"),"content-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//omicron[@attrib][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::theta[contains(concat(@insert,"$"),"ent$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[contains(@attribute,"t-value")][@xml:id="id5"][preceding-sibling::*[position() = 2]]/iota[@xml:id="id6"][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <psi xml:lang="no-nb" xml:id="id2"> + <omega data="attribute-value"/> + <pi xml:id="id3"/> + <omega xml:id="id4"/> + <delta attrib="true"/> + <gamma class="content" xml:lang="no-nb"> + <omicron attrib="false" xml:lang="nb"/> + <theta insert="content"/> + <chi attribute="this-is-att-value" xml:id="id5"> + <iota xml:id="id6"> + <green>This text must be green</green> + </iota> + </chi> + </gamma> + </psi> + </psi> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@att,"10")][@xml:lang="no"][@xml:id="id1"]/eta[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[starts-with(concat(@object,"-"),"this-")][@xml:id="id2"][following-sibling::*[position()=2]][following-sibling::upsilon[@xml:lang="no-nb"][not(child::node())][following-sibling::lambda[contains(@string,"te value")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 3]]//omega[starts-with(@data,"solid 1px")][@xml:id="id4"][not(child::node())][following-sibling::phi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="nb"][not(following-sibling::*)]//omega[contains(@number,"onten")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <omega att="100%" xml:lang="no" xml:id="id1"> + <eta xml:lang="en-US"/> + <phi object="this-is-att-value" xml:id="id2"/> + <upsilon xml:lang="no-nb"/> + <lambda string="attribute value" xml:lang="en" xml:id="id3"> + <omega data="solid 1px green" xml:id="id4"/> + <phi xml:id="id5"/> + <nu xml:lang="nb"> + <omega number="content"> + <green>This text must be green</green> + </omega> + </nu> + </lambda> + </omega> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no"]/alpha[@token][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="en"][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="no"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(preceding-sibling::kappa or following-sibling::kappa)]//chi[contains(@title,"e")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@object][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/mu[@xml:lang="en"][following-sibling::sigma[starts-with(concat(@delete,"-"),"100%-")][@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::nu[@xml:id="id5"][not(following-sibling::*)]//beta[contains(concat(@data,"$")," attribute value$")][not(child::node())][following-sibling::chi[@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//eta[@xml:id="id7"][not(following-sibling::*)]/pi[@xml:id="id8"][not(following-sibling::*)]//phi[@xml:lang="no-nb"][@xml:id="id9"][following-sibling::gamma[starts-with(@attrib,"conten")][preceding-sibling::*[position() = 1]]//delta[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no"> + <alpha token="attribute-value" xml:lang="no"> + <rho xml:lang="en"/> + <sigma xml:lang="en-GB"> + <epsilon xml:lang="nb"/> + <kappa xml:lang="no" xml:id="id1"> + <chi title="true" xml:lang="en-GB" xml:id="id2"/> + <upsilon object="this.nodeValue" xml:lang="no-nb" xml:id="id3"> + <rho xml:lang="en" xml:id="id4"> + <mu xml:lang="en"/> + <sigma delete="100%" xml:lang="nb"/> + <nu xml:id="id5"> + <beta data="another attribute value"/> + <chi xml:lang="en-US" xml:id="id6"> + <eta xml:id="id7"> + <pi xml:id="id8"> + <phi xml:lang="no-nb" xml:id="id9"/> + <gamma attrib="content"> + <delta xml:lang="en-GB"/> + <omicron xml:lang="en-GB"> + <green>This text must be green</green> + </omicron> + </gamma> + </pi> + </eta> + </chi> + </nu> + </rho> + </upsilon> + </kappa> + </sigma> + </alpha> + </psi> + </tree> + </test> + <test> + <xpath>//pi[@src="this.nodeValue"][@xml:lang="nb"]/lambda[starts-with(concat(@and,"-"),"this-")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]/eta[not(child::node())][following-sibling::gamma[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="en"]//delta[@content][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 1]][following-sibling::gamma[@xml:lang="no"][not(following-sibling::*)]//gamma[starts-with(concat(@true,"-"),"123456789-")][not(preceding-sibling::*)][not(following-sibling::*)]/*[starts-with(concat(@insert,"-"),"123456789-")]//alpha[contains(concat(@false,"$"),"%$")][@xml:lang="no"][@xml:id="id2"]//chi[not(following-sibling::chi)]/phi[@xml:lang="nb"][not(preceding-sibling::*)]//upsilon[@xml:id="id3"][not(child::node())][following-sibling::mu[not(following-sibling::*)]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <pi src="this.nodeValue" xml:lang="nb"> + <lambda and="this-is-att-value" xml:id="id1"/> + <psi xml:lang="en-GB"> + <eta/> + <gamma token="attribute-value" xml:lang="en"> + <delta content="solid 1px green"/> + <kappa/> + <gamma xml:lang="no"> + <gamma true="123456789"> + <any insert="123456789"> + <alpha false="100%" xml:lang="no" xml:id="id2"> + <chi> + <phi xml:lang="nb"> + <upsilon xml:id="id3"/> + <mu> + <green>This text must be green</green> + </mu> + </phi> + </chi> + </alpha> + </any> + </gamma> + </gamma> + </gamma> + </psi> + </pi> + </tree> + </test> + <test> + <xpath>//xi[contains(@insert,"00%")][@xml:lang="en-GB"][@xml:id="id1"]//mu[@false][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(concat(@delete,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@content][not(following-sibling::*)]/tau[not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id3"][not(following-sibling::*)]//mu[contains(concat(@src,"$"),"px green$")][@xml:lang="en-US"][not(child::node())][following-sibling::phi[@or][not(following-sibling::*)]/chi[starts-with(concat(@data,"-"),"false-")][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[@xml:id="id4"][following-sibling::iota[@xml:id="id5"][not(following-sibling::*)]//tau[starts-with(concat(@data,"-"),"content-")][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="en"][not(following-sibling::*)]//phi[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]/psi[not(preceding-sibling::*)][not(following-sibling::*)]/kappa[contains(concat(@attribute,"$"),"false$")][@xml:lang="en"][not(following-sibling::*)]/epsilon[contains(concat(@src,"$"),"e$")][@xml:lang="en"][@xml:id="id7"]//tau[@insert][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[@xml:id="id8"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <xi insert="100%" xml:lang="en-GB" xml:id="id1"> + <mu false="solid 1px green"/> + <kappa delete="attribute" xml:lang="en-GB" xml:id="id2"/> + <nu content="this-is-att-value"> + <tau/> + <alpha xml:id="id3"> + <mu src="solid 1px green" xml:lang="en-US"/> + <phi or="100%"> + <chi data="false"/> + <nu xml:id="id4"/> + <iota xml:id="id5"> + <tau data="content"/> + <delta xml:lang="en"> + <phi xml:lang="en" xml:id="id6"> + <psi> + <kappa attribute="false" xml:lang="en"> + <epsilon src="true" xml:lang="en" xml:id="id7"> + <tau insert="attribute value"/> + <xi xml:id="id8"> + <green>This text must be green</green> + </xi> + </epsilon> + </kappa> + </psi> + </phi> + </delta> + </iota> + </phi> + </alpha> + </nu> + </xi> + </tree> + </test> + <test> + <xpath>//beta[contains(@attrib,"ue")]/nu[contains(@title,"fals")][@xml:id="id1"][not(preceding-sibling::*)]/rho[@insert][@xml:id="id2"][not(preceding-sibling::*)]/kappa[not(following-sibling::*)]//upsilon[@and][@xml:id="id3"][not(preceding-sibling::*)]//chi[not(preceding-sibling::*)][following-sibling::delta[preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <beta attrib="this.nodeValue"> + <nu title="false" xml:id="id1"> + <rho insert="this.nodeValue" xml:id="id2"> + <kappa> + <upsilon and="solid 1px green" xml:id="id3"> + <chi/> + <delta> + <green>This text must be green</green> + </delta> + </upsilon> + </kappa> + </rho> + </nu> + </beta> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="en"][@xml:id="id1"]/delta[@and][@xml:lang="en"]/omicron[@xml:lang="no"][following-sibling::iota[contains(@number,"t")][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::beta[contains(concat(@number,"$"),"k$")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[not(preceding-sibling::*)]/omicron[contains(@class,"lue")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)]//omicron[not(preceding-sibling::*)]/omicron[@class="this-is-att-value"][@xml:id="id4"]/epsilon[starts-with(@false,"this.node")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[starts-with(@desciption,"co")][@xml:lang="no-nb"]/mu[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(concat(@name,"-"),"true-")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[@xml:id="id8"][not(child::node())][following-sibling::theta[@xml:lang="no"][not(child::node())][following-sibling::pi[contains(concat(@data,"$"),"lue$")][@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//*[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="en"][not(child::node())][following-sibling::psi[@xml:lang="en-US"][not(following-sibling::*)]/lambda[@xml:lang="en-GB"][@xml:id="id10"][position() = 1]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="en" xml:id="id1"> + <delta and="_blank" xml:lang="en"> + <omicron xml:lang="no"/> + <iota number="content" xml:lang="nb" xml:id="id2"/> + <beta number="_blank" xml:lang="no"> + <phi> + <omicron class="this.nodeValue" xml:lang="no-nb" xml:id="id3"> + <omicron> + <omicron class="this-is-att-value" xml:id="id4"> + <epsilon false="this.nodeValue" xml:id="id5"> + <xi desciption="content" xml:lang="no-nb"> + <mu xml:lang="en-GB"> + <xi xml:lang="en-US" xml:id="id6"/> + <upsilon name="true" xml:id="id7"> + <tau xml:id="id8"/> + <theta xml:lang="no"/> + <pi data="this.nodeValue" xml:lang="en" xml:id="id9"> + <any xml:lang="nb"/> + <phi xml:lang="en"/> + <psi xml:lang="en-US"> + <lambda xml:lang="en-GB" xml:id="id10"> + <green>This text must be green</green> + </lambda> + </psi> + </pi> + </upsilon> + </mu> + </xi> + </epsilon> + </omicron> + </omicron> + </omicron> + </phi> + </beta> + </delta> + </zeta> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]//kappa[starts-with(concat(@att,"-"),"123456789-")][@xml:lang="no"][not(following-sibling::*)]//epsilon[@number][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//beta[contains(@desciption,"6789")][@xml:lang="no"][@xml:id="id4"][not(following-sibling::beta)][not(child::node())][following-sibling::delta[@name][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//phi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[starts-with(@false,"a")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::psi[contains(concat(@number,"$"),"%$")][@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <kappa att="123456789" xml:lang="no"> + <epsilon number="content" xml:lang="no" xml:id="id2"> + <zeta xml:lang="no" xml:id="id3"> + <beta desciption="123456789" xml:lang="no" xml:id="id4"/> + <delta name="attribute" xml:lang="en-US" xml:id="id5"> + <phi xml:lang="no-nb"/> + <eta false="attribute" xml:lang="no"/> + <psi number="100%" xml:lang="en"> + <green>This text must be green</green> + </psi> + </delta> + </zeta> + </epsilon> + </kappa> + </phi> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@false,"$"),"t-value$")][@xml:lang="en-GB"][@xml:id="id1"]//*[@xml:lang="en"][not(child::node())][following-sibling::rho[@false][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 2]][following-sibling::omicron[@token="attribute"][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//zeta[@content][@xml:lang="nb"]/phi[@attrib][@xml:id="id3"]/nu[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::omega[starts-with(concat(@number,"-"),"solid 1px green-")][@xml:lang="en-US"][@xml:id="id6"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <beta false="this-is-att-value" xml:lang="en-GB" xml:id="id1"> + <any xml:lang="en"/> + <rho false="solid 1px green"/> + <omega/> + <omicron token="attribute" xml:lang="no-nb" xml:id="id2"> + <zeta content="solid 1px green" xml:lang="nb"> + <phi attrib="attribute" xml:id="id3"> + <nu/> + <any xml:id="id4"> + <rho/> + <sigma xml:lang="no-nb" xml:id="id5"/> + <omega number="solid 1px green" xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </omega> + </any> + </phi> + </zeta> + </omicron> + </beta> + </tree> + </test> + <test> + <xpath>//*/delta[@xml:lang="en-GB"][not(preceding-sibling::*)]//lambda[not(preceding-sibling::*)]//lambda[@abort][@xml:lang="no"][@xml:id="id1"][following-sibling::*[position()=8]][not(child::node())][following-sibling::phi[following-sibling::*[position()=7]][following-sibling::psi[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[starts-with(concat(@attribute,"-"),"this-")][@xml:lang="en"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::upsilon[contains(concat(@att,"$"),"t$")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=4]][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=3]][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 6]][not(preceding-sibling::pi or following-sibling::pi)][not(child::node())][following-sibling::alpha[contains(concat(@attr,"$"),"456789$")][@xml:lang="no"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::beta[contains(@data,"an")][@xml:lang="en-US"]/rho[@att][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[contains(concat(@class,"$"),"another attribute value$")][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>1</nth> + </result> + <tree> + <any> + <delta xml:lang="en-GB"> + <lambda> + <lambda abort="this.nodeValue" xml:lang="no" xml:id="id1"/> + <phi/> + <psi xml:id="id2"/> + <upsilon attribute="this-is-att-value" xml:lang="en"/> + <upsilon att="content" xml:lang="no" xml:id="id3"/> + <rho xml:lang="en-GB" xml:id="id4"/> + <pi xml:id="id5"/> + <alpha attr="123456789" xml:lang="no" xml:id="id6"/> + <beta data="_blank" xml:lang="en-US"> + <rho att="100%" xml:lang="nb" xml:id="id7"> + <tau class="another attribute value" xml:id="id8"/> + <omega xml:id="id9"/> + <lambda xml:lang="no"> + <green>This text must be green</green> + </lambda> + </rho> + </beta> + </lambda> + </delta> + </any> + </tree> + </test> + <test> + <xpath>//theta[contains(concat(@attr,"$"),"ue$")]/zeta[@xml:lang="en-US"][not(preceding-sibling::*)]/rho[starts-with(concat(@insert,"-"),"attribute value-")][@xml:lang="nb"][@xml:id="id1"]/theta[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="en"]/alpha[contains(@att,"hi")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="nb"][preceding-sibling::*[position() = 1]]//chi[@attrib="another attribute value"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::psi[starts-with(@number,"_blank")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[not(preceding-sibling::*)][following-sibling::gamma[@true][@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>1</nth> + </result> + <tree> + <theta attr="true"> + <zeta xml:lang="en-US"> + <rho insert="attribute value" xml:lang="nb" xml:id="id1"> + <theta and="this.nodeValue" xml:lang="en"/> + <xi xml:lang="en"> + <alpha att="this-is-att-value" xml:id="id2"/> + <chi xml:lang="nb"> + <chi attrib="another attribute value" xml:id="id3"/> + <psi number="_blank"> + <epsilon/> + <gamma true="this-is-att-value" xml:lang="en-GB"> + <green>This text must be green</green> + </gamma> + </psi> + </chi> + </xi> + </rho> + </zeta> + </theta> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no"][@xml:id="id1"]//nu//omicron[not(preceding-sibling::*)][following-sibling::beta[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@string][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[contains(@src,"s")][@xml:lang="no-nb"][following-sibling::nu[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::gamma[@xml:lang="en-US"][@xml:id="id5"]/omega[contains(concat(@abort,"$"),"eValue$")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[not(child::node())][following-sibling::alpha[starts-with(@name,"this.n")][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::tau[@xml:id="id8"][not(following-sibling::*)]//lambda[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[starts-with(concat(@true,"-"),"attribute value-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id10"]]]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no" xml:id="id1"> + <nu> + <omicron/> + <beta xml:lang="no" xml:id="id2"> + <chi string="123456789" xml:id="id3"/> + <tau src="false" xml:lang="no-nb"/> + <nu xml:lang="no" xml:id="id4"/> + <gamma xml:lang="en-US" xml:id="id5"> + <omega abort="this.nodeValue" xml:id="id6"> + <psi/> + <alpha name="this.nodeValue" xml:id="id7"/> + <tau xml:id="id8"> + <lambda xml:id="id9"/> + <omicron true="attribute value" xml:lang="en"/> + <phi xml:lang="no-nb" xml:id="id10"> + <green>This text must be green</green> + </phi> + </tau> + </omega> + </gamma> + </beta> + </nu> + </tau> + </tree> + </test> + <test> + <xpath>//*[@data="false"][@xml:id="id1"]/mu[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:lang="no-nb"][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][following-sibling::zeta[@xml:id="id3"][following-sibling::eta[@class][@xml:id="id4"][not(child::node())][following-sibling::sigma[@attrib][@xml:lang="no-nb"][not(following-sibling::*)]//mu[not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@delete][@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//gamma[not(preceding-sibling::*)]//upsilon[@data][@xml:id="id6"][not(following-sibling::*)]//beta/psi[contains(@number," green")][@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::alpha[@attrib][@xml:id="id8"][preceding-sibling::*[position() = 1]]//delta[contains(concat(@class,"$"),"this-is-att-value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::eta[@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@xml:lang="en-GB"][@xml:id="id10"][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <any data="false" xml:id="id1"> + <mu xml:lang="nb" xml:id="id2"> + <phi xml:lang="en-GB"> + <tau xml:lang="no-nb"/> + <lambda xml:lang="en-GB"/> + <zeta xml:id="id3"/> + <eta class="another attribute value" xml:id="id4"/> + <sigma attrib="this-is-att-value" xml:lang="no-nb"> + <mu/> + <sigma delete="this.nodeValue" xml:lang="en" xml:id="id5"> + <gamma> + <upsilon data="this-is-att-value" xml:id="id6"> + <beta> + <psi number="solid 1px green" xml:lang="en-GB" xml:id="id7"/> + <alpha attrib="100%" xml:id="id8"> + <delta class="this-is-att-value" xml:lang="no-nb"/> + <eta xml:id="id9"> + <zeta xml:lang="en-GB" xml:id="id10"> + <green>This text must be green</green> + </zeta> + </eta> + </alpha> + </beta> + </upsilon> + </gamma> + </sigma> + </sigma> + </phi> + </mu> + </any> + </tree> + </test> + <test> + <xpath>//lambda[contains(concat(@src,"$"),"-value$")]/omega[not(child::node())][following-sibling::zeta[@data][@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::omega[starts-with(concat(@attrib,"-"),"this.nodeValue-")][@xml:id="id2"]//nu[contains(@number,"00")][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/delta[starts-with(@true,"this-is-att")][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(@abort,"solid 1px gr")][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[not(following-sibling::*)]/eta[@xml:lang="no-nb"][@xml:id="id6"][following-sibling::sigma[starts-with(concat(@desciption,"-"),"123456789-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@insert="this-is-att-value"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::*[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(preceding-sibling::any)]/tau[@token="123456789"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[starts-with(@token,"_blan")][@xml:lang="no-nb"][@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <lambda src="this-is-att-value"> + <omega/> + <zeta data="this-is-att-value" xml:lang="en-GB" xml:id="id1"/> + <omega attrib="this.nodeValue" xml:id="id2"> + <nu number="100%"/> + <sigma xml:lang="en-US" xml:id="id3"> + <delta true="this-is-att-value" xml:id="id4"> + <zeta abort="solid 1px green" xml:id="id5"/> + <gamma> + <eta xml:lang="no-nb" xml:id="id6"/> + <sigma desciption="123456789" xml:lang="nb"/> + <iota insert="this-is-att-value" xml:id="id7"/> + <any xml:lang="en-GB" xml:id="id8"> + <tau token="123456789" xml:id="id9"> + <nu token="_blank" xml:lang="no-nb" xml:id="id10"/> + <delta> + <green>This text must be green</green> + </delta> + </tau> + </any> + </gamma> + </delta> + </sigma> + </omega> + </lambda> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(@content,"attribute valu")][@xml:lang="en"][@xml:id="id1"]/iota[contains(concat(@attrib,"$"),"tribute value$")][not(preceding-sibling::*)][following-sibling::alpha[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="no-nb"][@xml:id="id2"]//nu[contains(concat(@abort,"$"),"rue$")][@xml:id="id3"][following-sibling::omicron[preceding-sibling::*[position() = 1]][following-sibling::*[position()=6]][following-sibling::epsilon[@xml:lang="en-GB"][following-sibling::*[position()=5]][not(child::node())][following-sibling::mu[contains(concat(@data,"$"),"ute value$")][following-sibling::pi[@xml:id="id4"][not(child::node())][following-sibling::gamma[@desciption][@xml:lang="nb"][following-sibling::omicron[@insert][@xml:lang="en-US"][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 7]][not(following-sibling::*)]//omega[@attribute][@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]//gamma[@xml:lang="en"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::tau[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[starts-with(@delete,"false")][not(preceding-sibling::*)]//rho[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::delta//lambda[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::omega[@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[contains(@or,"ntent")][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)]/kappa[contains(@name,"reen")][@xml:lang="en-GB"][@xml:id="id11"][not(following-sibling::*)]//nu[@xml:lang="no"][@xml:id="id12"][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[@xml:lang="en-US"][@xml:id="id13"]]]]]][position() = 1]]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <upsilon content="attribute value" xml:lang="en" xml:id="id1"> + <iota attrib="another attribute value"/> + <alpha false="123456789" xml:lang="no-nb" xml:id="id2"> + <nu abort="true" xml:id="id3"/> + <omicron/> + <epsilon xml:lang="en-GB"/> + <mu data="attribute value"/> + <pi xml:id="id4"/> + <gamma desciption="100%" xml:lang="nb"/> + <omicron insert="content" xml:lang="en-US"/> + <sigma> + <omega attribute="attribute value" xml:lang="no" xml:id="id5"> + <gamma xml:lang="en" xml:id="id6"/> + <tau xml:id="id7"> + <omicron delete="false"> + <rho xml:lang="nb"/> + <delta> + <lambda xml:lang="en" xml:id="id8"/> + <omega xml:id="id9"> + <any or="content" xml:lang="nb" xml:id="id10"> + <kappa name="solid 1px green" xml:lang="en-GB" xml:id="id11"> + <nu xml:lang="no" xml:id="id12"/> + <rho/> + <phi xml:lang="en-US" xml:id="id13"> + <green>This text must be green</green> + </phi> + </kappa> + </any> + </omega> + </delta> + </omicron> + </tau> + </omega> + </sigma> + </alpha> + </upsilon> + </tree> + </test> + <test> + <xpath>//gamma[@object][@xml:lang="en-GB"][@xml:id="id1"]//tau[@class][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:id="id4"]//pi[starts-with(concat(@true,"-"),"_blank-")][@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::eta[@class="true"][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/theta[@src][not(preceding-sibling::*)][not(following-sibling::*)]//eta[starts-with(@attrib,"true")][@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]//zeta[starts-with(concat(@insert,"-"),"this.nodeValue-")][not(preceding-sibling::*)][following-sibling::xi[starts-with(concat(@attr,"-"),"another attribute value-")][not(child::node())][following-sibling::tau[@xml:id="id8"][preceding-sibling::*[position() = 2]]/lambda[@and][not(following-sibling::*)]//kappa[not(following-sibling::*)]//delta[@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="no-nb"][not(following-sibling::*)]/rho[@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::*[@true][@xml:lang="no"][@xml:id="id10"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <gamma object="100%" xml:lang="en-GB" xml:id="id1"> + <tau class="content" xml:id="id2"/> + <psi xml:id="id3"> + <mu xml:id="id4"> + <pi true="_blank" xml:lang="no" xml:id="id5"/> + <eta class="true" xml:lang="en-GB" xml:id="id6"> + <theta src="true"> + <eta attrib="true" xml:lang="no-nb" xml:id="id7"> + <zeta insert="this.nodeValue"/> + <xi attr="another attribute value"/> + <tau xml:id="id8"> + <lambda and="attribute value"> + <kappa> + <delta xml:lang="no" xml:id="id9"> + <omicron xml:lang="no-nb"> + <rho xml:lang="en"/> + <any true="attribute" xml:lang="no" xml:id="id10"> + <green>This text must be green</green> + </any> + </omicron> + </delta> + </kappa> + </lambda> + </tau> + </eta> + </theta> + </eta> + </mu> + </psi> + </gamma> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@object,"$")," 1px green$")][@xml:id="id1"]//xi[starts-with(@attr,"content")]//epsilon[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:lang="no"][preceding-sibling::*[position() = 2]]/iota[@abort][@xml:id="id3"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <phi object="solid 1px green" xml:id="id1"> + <xi attr="content"> + <epsilon xml:id="id2"/> + <any/> + <psi xml:lang="no"> + <iota abort="123456789" xml:id="id3"> + <green>This text must be green</green> + </iota> + </psi> + </xi> + </phi> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en"][@xml:id="id1"]/nu/pi[@attribute][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::nu[@xml:lang="nb"][preceding-sibling::*[position() = 1]]/beta[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:id="id4"][not(child::node())][following-sibling::lambda[@xml:lang="no"]/rho[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id6"][not(child::node())][following-sibling::tau[@or="content"][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 2]]/kappa[@xml:lang="en"][not(preceding-sibling::*)]/tau[starts-with(concat(@delete,"-"),"false-")][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(@and,"100")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::omicron[starts-with(concat(@title,"-"),"attribute-")][@xml:id="id8"][not(following-sibling::*)]//sigma[contains(@data,"fals")][@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)]//theta[@and="true"][@xml:lang="nb"][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="en" xml:id="id1"> + <nu> + <pi attribute="this-is-att-value" xml:id="id2"/> + <nu xml:lang="nb"> + <beta xml:id="id3"> + <psi xml:id="id4"/> + <lambda xml:lang="no"> + <rho xml:lang="no-nb" xml:id="id5"> + <mu xml:lang="no-nb" xml:id="id6"/> + <tau or="content" xml:lang="nb"/> + <rho> + <kappa xml:lang="en"> + <tau delete="false" xml:lang="en-GB" xml:id="id7"/> + <omicron and="100%" xml:lang="en"/> + <omicron title="attribute-value" xml:id="id8"> + <sigma data="false" xml:lang="en-GB" xml:id="id9"> + <theta and="true" xml:lang="nb"> + <green>This text must be green</green> + </theta> + </sigma> + </omicron> + </kappa> + </rho> + </rho> + </lambda> + </beta> + </nu> + </nu> + </psi> + </tree> + </test> + <test> + <xpath>//iota[starts-with(@title,"solid 1")]//nu[@xml:lang="no-nb"][not(child::node())][following-sibling::beta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::theta[@xml:id="id1"]/nu[contains(@number,"e valu")][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@string="content"][@xml:lang="no"][not(preceding-sibling::*)]//*[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/zeta[starts-with(@attrib,"this-is-att-valu")][@xml:lang="nb"][@xml:id="id3"]//*[@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[not(child::node())][following-sibling::omicron[contains(@number,"ibute")]/delta[contains(concat(@number,"$"),"his.nodeValue$")][@xml:lang="en-GB"][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@class][@xml:lang="nb"][not(following-sibling::*)]/zeta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::mu[@number="false"][@xml:lang="en"][following-sibling::zeta[following-sibling::*[position()=1]][following-sibling::nu[@class][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/epsilon[@abort][@xml:id="id7"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <iota title="solid 1px green"> + <nu xml:lang="no-nb"/> + <beta xml:lang="en-GB"/> + <kappa/> + <theta xml:id="id1"> + <nu number="attribute value"> + <mu string="content" xml:lang="no"> + <any/> + <chi xml:lang="en-GB" xml:id="id2"> + <zeta attrib="this-is-att-value" xml:lang="nb" xml:id="id3"> + <any xml:id="id4"/> + <zeta/> + <omicron number="attribute"> + <delta number="this.nodeValue" xml:lang="en-GB"/> + <lambda xml:lang="en-GB"> + <beta class="solid 1px green" xml:lang="nb"> + <zeta xml:lang="en-GB" xml:id="id5"/> + <mu number="false" xml:lang="en"/> + <zeta/> + <nu class="false" xml:lang="en" xml:id="id6"> + <epsilon abort="_blank" xml:id="id7"> + <green>This text must be green</green> + </epsilon> + </nu> + </beta> + </lambda> + </omicron> + </zeta> + </chi> + </mu> + </nu> + </theta> + </iota> + </tree> + </test> + <test> + <xpath>//phi//theta[@xml:lang="en-GB"]//*[@attribute][@xml:id="id1"][following-sibling::*[position()=6]][not(child::node())][following-sibling::*[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::nu[@object][@xml:id="id3"][not(child::node())][following-sibling::alpha[contains(concat(@true,"$"),"value$")][@xml:id="id4"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=3]][following-sibling::omicron[preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::phi[@or][@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="en-US"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]/delta[@name][@xml:lang="en-GB"][@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::nu[@xml:lang="en-US"][not(child::node())][following-sibling::nu[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::zeta[@data][@xml:id="id7"][not(following-sibling::*)]//alpha[@insert="solid 1px green"][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-US"][@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::kappa[contains(concat(@abort,"$"),"other attribute value$")][@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 2]]//gamma[@insert][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][not(following-sibling::*)]//gamma[@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[contains(@true,"rue")][@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]][position() = 1]]]]]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <theta xml:lang="en-GB"> + <any attribute="false" xml:id="id1"/> + <any xml:lang="no-nb" xml:id="id2"/> + <nu object="attribute value" xml:id="id3"/> + <alpha true="attribute value" xml:id="id4"/> + <omicron/> + <phi or="attribute-value" xml:lang="en-US"/> + <chi xml:lang="en-US"> + <delta name="this-is-att-value" xml:lang="en-GB" xml:id="id5"/> + <nu xml:lang="en-US"/> + <nu xml:id="id6"/> + <zeta data="123456789" xml:id="id7"> + <alpha insert="solid 1px green" xml:lang="en" xml:id="id8"/> + <theta xml:lang="en-US" xml:id="id9"/> + <kappa abort="another attribute value" xml:lang="en" xml:id="id10"> + <gamma insert="_blank" xml:lang="no-nb"/> + <tau xml:lang="en-GB"> + <gamma xml:lang="nb" xml:id="id11"> + <zeta true="true" xml:lang="en-GB"> + <green>This text must be green</green> + </zeta> + </gamma> + </tau> + </kappa> + </zeta> + </chi> + </theta> + </phi> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="nb"]/upsilon[@xml:lang="no-nb"][@xml:id="id1"]/psi[@xml:id="id2"]//kappa[@name][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-GB"][following-sibling::*[position()=1]][not(preceding-sibling::omicron)][not(child::node())][following-sibling::alpha[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 2]]//lambda[starts-with(concat(@class,"-"),"_blank-")][@xml:lang="no-nb"][not(preceding-sibling::*)]/alpha[@attribute][@xml:id="id5"][not(preceding-sibling::*)]/delta[@xml:id="id6"]/delta[contains(concat(@title,"$"),"3456789$")][following-sibling::omicron[contains(@true,"_blan")][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/sigma[contains(@token,"3456")][@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::xi[starts-with(concat(@title,"-"),"attribute-")][@xml:id="id9"][preceding-sibling::*[position() = 1]]//sigma[@attr][@xml:lang="en-US"][@xml:id="id10"][not(following-sibling::*)]/phi[contains(@desciption,"nother a")][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[contains(concat(@true,"$"),"ue$")][@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[starts-with(concat(@name,"-"),"solid 1px green-")][@xml:lang="no-nb"][@xml:id="id11"][preceding-sibling::*[position() = 2]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="nb"> + <upsilon xml:lang="no-nb" xml:id="id1"> + <psi xml:id="id2"> + <kappa name="content" xml:lang="en" xml:id="id3"/> + <omicron xml:lang="en-GB"/> + <alpha xml:lang="en" xml:id="id4"> + <lambda class="_blank" xml:lang="no-nb"> + <alpha attribute="attribute" xml:id="id5"> + <delta xml:id="id6"> + <delta title="123456789"/> + <omicron true="_blank" xml:lang="en" xml:id="id7"> + <sigma token="123456789" xml:lang="en-US" xml:id="id8"/> + <xi title="attribute-value" xml:id="id9"> + <sigma attr="100%" xml:lang="en-US" xml:id="id10"> + <phi desciption="another attribute value"/> + <zeta true="true" xml:lang="en-US"/> + <alpha name="solid 1px green" xml:lang="no-nb" xml:id="id11"> + <green>This text must be green</green> + </alpha> + </sigma> + </xi> + </omicron> + </delta> + </alpha> + </lambda> + </alpha> + </psi> + </upsilon> + </phi> + </tree> + </test> + <test> + <xpath>//delta[@xml:id="id1"]//eta[@xml:lang="en-US"][@xml:id="id2"]//*[starts-with(@attrib,"false")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@src,"$"),"lue$")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]/*[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:id="id6"][preceding-sibling::*[position() = 1]]/sigma[contains(@src,"l")][@xml:lang="no-nb"][@xml:id="id7"]/lambda[@xml:lang="no-nb"]//iota[contains(concat(@src,"$"),"ttribute value$")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="en-US"]//eta[starts-with(@desciption,"attribute va")][not(following-sibling::*)]//psi[following-sibling::*[position()=1]][following-sibling::rho[@attr][@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:id="id1"> + <eta xml:lang="en-US" xml:id="id2"> + <any attrib="false" xml:lang="no" xml:id="id3"/> + <alpha src="attribute value" xml:id="id4"/> + <delta xml:lang="en-GB" xml:id="id5"> + <any xml:lang="nb"/> + <rho xml:id="id6"> + <sigma src="_blank" xml:lang="no-nb" xml:id="id7"> + <lambda xml:lang="no-nb"> + <iota src="attribute value" xml:lang="nb"/> + <kappa xml:lang="en-US"> + <eta desciption="attribute value"> + <psi/> + <rho attr="this-is-att-value" xml:lang="no-nb" xml:id="id8"> + <green>This text must be green</green> + </rho> + </eta> + </kappa> + </lambda> + </sigma> + </rho> + </delta> + </eta> + </delta> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]/tau[@string][@xml:id="id2"]//alpha[@insert][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)]//lambda[starts-with(@or,"1234567")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::theta[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:lang="no"][@xml:id="id6"][not(child::node())][following-sibling::iota[contains(@title,"en")][@xml:lang="no"][@xml:id="id7"]/phi[contains(@or,"e")][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id8"]//*[contains(concat(@src,"$"),"e$")][@xml:lang="nb"][not(child::node())][following-sibling::eta[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//gamma[@xml:lang="no-nb"][following-sibling::omicron[contains(concat(@insert,"$"),"blank$")][@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <tau string="attribute" xml:id="id2"> + <alpha insert="attribute value" xml:lang="no-nb" xml:id="id3"> + <lambda or="123456789" xml:id="id4"/> + <theta xml:lang="nb" xml:id="id5"/> + <nu xml:lang="no" xml:id="id6"/> + <iota title="solid 1px green" xml:lang="no" xml:id="id7"> + <phi or="true"/> + <sigma xml:lang="en-US" xml:id="id8"> + <any src="attribute value" xml:lang="nb"/> + <eta attr="attribute" xml:lang="no"> + <gamma xml:lang="no-nb"/> + <omicron insert="_blank" xml:lang="en-GB" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </eta> + </sigma> + </iota> + </alpha> + </tau> + </rho> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@attr,"$"),"e$")][@xml:lang="no-nb"]/chi[@att][@xml:lang="en-GB"]//kappa[@name="content"][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[starts-with(concat(@title,"-"),"attribute-")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//xi[@attribute][not(preceding-sibling::*)]//phi[@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[contains(concat(@content,"$"),"ue$")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@class][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::zeta/iota[starts-with(@object,"c")][@xml:lang="en-US"][following-sibling::*[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id6"][preceding-sibling::*[position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <iota attr="attribute value" xml:lang="no-nb"> + <chi att="attribute" xml:lang="en-GB"> + <kappa name="content" xml:lang="en-GB" xml:id="id1"/> + <delta xml:id="id2"/> + <phi title="attribute"> + <xi attribute="solid 1px green"> + <phi xml:lang="en" xml:id="id3"/> + <any content="this-is-att-value" xml:lang="nb" xml:id="id4"> + <xi class="this-is-att-value" xml:id="id5"/> + <zeta> + <iota object="content" xml:lang="en-US"/> + <any token="another attribute value" xml:id="id6"> + <green>This text must be green</green> + </any> + </zeta> + </any> + </xi> + </phi> + </chi> + </iota> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="no"]//theta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::xi[contains(concat(@or,"$"),"false$")][following-sibling::*[position()=2]][following-sibling::beta[@content="true"][not(following-sibling::beta)][following-sibling::phi[@xml:lang="en-US"][not(following-sibling::*)]/epsilon[contains(concat(@title,"$")," value$")][@xml:id="id1"][not(preceding-sibling::*)]/theta[starts-with(@content,"a")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)]/xi[starts-with(@true,"true")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::delta[contains(@insert,"other att")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[contains(concat(@attr,"$"),"k$")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="no-nb"][following-sibling::alpha[@xml:lang="no-nb"][@xml:id="id4"]//lambda[contains(@insert,"ttr")][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::tau[@or="attribute value"][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::nu[contains(@string,"thi")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]]/nu[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="no"> + <theta xml:lang="en-US"/> + <xi or="false"/> + <beta content="true"/> + <phi xml:lang="en-US"> + <epsilon title="another attribute value" xml:id="id1"> + <theta content="another attribute value" xml:lang="en-GB" xml:id="id2"> + <xi true="true" xml:lang="nb"/> + <delta insert="another attribute value" xml:lang="no"> + <chi attr="_blank" xml:id="id3"/> + <omicron xml:lang="no-nb"/> + <alpha xml:lang="no-nb" xml:id="id4"> + <lambda insert="attribute-value" xml:lang="nb" xml:id="id5"> + <zeta xml:lang="en-GB"/> + <tau or="attribute value" xml:lang="en-US"/> + <nu string="this.nodeValue" xml:lang="en-US" xml:id="id6"> + <nu xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </nu> + </nu> + </lambda> + </alpha> + </delta> + </theta> + </epsilon> + </phi> + </chi> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en-US"][@xml:id="id1"]/omega[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)][not(preceding-sibling::omega)]//eta[starts-with(@number,"1234567")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="no"][not(child::node())][following-sibling::theta[starts-with(concat(@string,"-"),"solid 1px green-")][@xml:lang="en-US"][@xml:id="id3"]/nu[@object][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@src,"-"),"attribute-")][@xml:id="id4"]//kappa[@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::beta[starts-with(@name,"content")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="en-US" xml:id="id1"> + <omega xml:lang="en" xml:id="id2"> + <eta number="123456789" xml:lang="nb"/> + <kappa xml:lang="no"/> + <theta string="solid 1px green" xml:lang="en-US" xml:id="id3"> + <nu object="another attribute value" xml:lang="nb"/> + <nu src="attribute" xml:id="id4"> + <kappa xml:lang="no" xml:id="id5"/> + <beta name="content" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </beta> + </nu> + </theta> + </omega> + </iota> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no"][@xml:id="id1"]//zeta[@xml:id="id2"][not(preceding-sibling::*)]//delta[@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@xml:id="id4"]//nu[not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::upsilon[@attr="solid 1px green"][following-sibling::mu[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::alpha[@xml:lang="en"][@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@xml:id="id7"]//pi[@xml:id="id8"]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no" xml:id="id1"> + <zeta xml:id="id2"> + <delta xml:lang="en" xml:id="id3"> + <mu xml:id="id4"> + <nu/> + <upsilon attr="solid 1px green"/> + <mu xml:lang="en-GB" xml:id="id5"/> + <alpha xml:lang="en" xml:id="id6"/> + <delta xml:id="id7"> + <pi xml:id="id8"> + <green>This text must be green</green> + </pi> + </delta> + </mu> + </delta> + </zeta> + </iota> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@abort,"anoth")]//beta[@string][@xml:lang="no"][not(child::node())][following-sibling::xi[contains(concat(@content,"$"),"other attribute value$")][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[contains(@class,"_")][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@true][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::omega[starts-with(concat(@false,"-"),"content-")][@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omega abort="another attribute value"> + <beta string="attribute" xml:lang="no"/> + <xi content="another attribute value" xml:id="id1"/> + <lambda class="_blank"/> + <eta true="true" xml:lang="en-GB" xml:id="id2"/> + <omega false="content" xml:lang="nb"> + <green>This text must be green</green> + </omega> + </omega> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]//xi[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]/omicron[@xml:id="id3"][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@xml:id="id5"][preceding-sibling::*[position() = 2]]/xi[@string][@xml:lang="en-US"][not(preceding-sibling::*)]/xi[@att="content"][@xml:id="id6"][following-sibling::alpha[@xml:id="id7"][preceding-sibling::*[position() = 1]]//nu[@attrib][@xml:id="id8"][not(preceding-sibling::*)]/tau[starts-with(@att,"attribut")][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@token,"this.nodeValue")][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::lambda)][not(child::node())][following-sibling::alpha[@xml:lang="nb"][@xml:id="id11"]//delta[@delete][@xml:lang="no"][not(child::node())][following-sibling::upsilon[@class][@xml:lang="no"][@xml:id="id12"][following-sibling::phi[@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::lambda[@xml:lang="nb"][following-sibling::alpha[contains(@token,"s-is-a")][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//epsilon[starts-with(@name,"another attribute val")][@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="en-GB"][@xml:id="id14"][following-sibling::epsilon[starts-with(@token,"12345")][@xml:id="id15"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <xi xml:lang="no" xml:id="id2"> + <omicron xml:id="id3"/> + <xi xml:lang="en-GB" xml:id="id4"/> + <zeta xml:id="id5"> + <xi string="content" xml:lang="en-US"> + <xi att="content" xml:id="id6"/> + <alpha xml:id="id7"> + <nu attrib="true" xml:id="id8"> + <tau att="attribute" xml:id="id9"/> + <lambda token="this.nodeValue" xml:lang="nb" xml:id="id10"/> + <alpha xml:lang="nb" xml:id="id11"> + <delta delete="_blank" xml:lang="no"/> + <upsilon class="attribute-value" xml:lang="no" xml:id="id12"/> + <phi xml:lang="en"/> + <lambda xml:lang="nb"/> + <alpha token="this-is-att-value"> + <epsilon name="another attribute value" xml:id="id13"> + <phi xml:lang="en-GB" xml:id="id14"/> + <epsilon token="123456789" xml:id="id15"/> + <pi> + <green>This text must be green</green> + </pi> + </epsilon> + </alpha> + </alpha> + </nu> + </alpha> + </xi> + </zeta> + </xi> + </mu> + </tree> + </test> + <test> + <xpath>//gamma[@xml:lang="en"]/xi[contains(concat(@number,"$"),"ribute-value$")][@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)]/*[contains(concat(@object,"$"),"lank$")][@xml:id="id2"][following-sibling::psi[preceding-sibling::*[position() = 1]]//pi[not(preceding-sibling::*)][not(following-sibling::*)]/eta[@title="this.nodeValue"][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id3"][not(child::node())][following-sibling::chi[starts-with(concat(@name,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[contains(@number,"k")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::phi[preceding-sibling::*[position() = 1]][following-sibling::*[@xml:lang="en"][@xml:id="id6"]//omicron[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::eta[@xml:id="id8"][not(following-sibling::*)]//delta[contains(@abort,"al")][not(preceding-sibling::delta or following-sibling::delta)]/*[starts-with(concat(@and,"-"),"attribute value-")][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::eta[contains(@insert,"nk")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/sigma[@xml:lang="en-GB"][not(child::node())][following-sibling::zeta[starts-with(concat(@src,"-"),"solid 1px green-")][@xml:lang="en"][not(following-sibling::*)]//eta[@data][@xml:lang="nb"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:lang="en"> + <xi number="attribute-value" xml:lang="en" xml:id="id1"> + <any object="_blank" xml:id="id2"/> + <psi> + <pi> + <eta title="this.nodeValue" xml:lang="nb"/> + <epsilon xml:lang="no-nb" xml:id="id3"/> + <chi name="attribute-value" xml:lang="en-GB" xml:id="id4"> + <tau number="_blank" xml:id="id5"/> + <phi/> + <any xml:lang="en" xml:id="id6"> + <omicron xml:lang="en-GB" xml:id="id7"/> + <eta xml:id="id8"> + <delta abort="another attribute value"> + <any and="attribute value" xml:lang="no" xml:id="id9"/> + <eta insert="_blank"/> + <gamma xml:lang="no-nb"> + <sigma xml:lang="en-GB"/> + <zeta src="solid 1px green" xml:lang="en"> + <eta data="_blank" xml:lang="nb"> + <green>This text must be green</green> + </eta> + </zeta> + </gamma> + </delta> + </eta> + </any> + </chi> + </pi> + </psi> + </xi> + </gamma> + </tree> + </test> + <test> + <xpath>//mu[starts-with(@abort,"anothe")]/pi[@xml:id="id1"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[following-sibling::omega[@class="_blank"][following-sibling::delta[@object][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi/zeta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@attr][@xml:lang="no-nb"][@xml:id="id2"][following-sibling::sigma[contains(concat(@string,"$"),"789$")][@xml:lang="no"]//chi[not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@and][@xml:id="id3"]//eta[not(preceding-sibling::*)][not(child::node())][following-sibling::mu[starts-with(concat(@true,"-"),"true-")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[starts-with(concat(@or,"-"),"123456789-")][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omicron[@xml:id="id6"][following-sibling::sigma[@attr][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/*[starts-with(concat(@insert,"-"),"this.nodeValue-")][@xml:lang="en"]][position() = 1]]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <mu abort="another attribute value"> + <pi xml:id="id1"/> + <nu/> + <delta/> + <omega class="_blank"/> + <delta object="attribute value" xml:lang="en"/> + <pi> + <zeta xml:lang="no-nb"/> + <xi attr="123456789" xml:lang="no-nb" xml:id="id2"/> + <sigma string="123456789" xml:lang="no"> + <chi/> + <zeta and="attribute-value" xml:id="id3"> + <eta/> + <mu true="true" xml:id="id4"/> + <any or="123456789" xml:id="id5"> + <omicron xml:id="id6"/> + <sigma attr="123456789" xml:lang="en-US"> + <any insert="this.nodeValue" xml:lang="en"> + <green>This text must be green</green> + </any> + </sigma> + </any> + </zeta> + </sigma> + </pi> + </mu> + </tree> + </test> + <test> + <xpath>//omega[contains(concat(@desciption,"$"),"ute$")][@xml:lang="no"]//iota[@xml:lang="en-US"][@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::psi[following-sibling::chi[starts-with(@true,"12345678")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/omega[starts-with(@attribute,"solid 1px")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::zeta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//gamma[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::sigma[contains(@att,"e")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]//iota[starts-with(concat(@attr,"-"),"123456789-")][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega desciption="attribute" xml:lang="no"> + <iota xml:lang="en-US" xml:id="id1"/> + <psi/> + <chi true="123456789" xml:lang="no-nb"> + <omega attribute="solid 1px green" xml:lang="en"/> + <delta xml:lang="en"/> + <zeta> + <gamma xml:lang="no"/> + <sigma att="attribute" xml:id="id2"/> + <theta xml:lang="en" xml:id="id3"> + <iota attr="123456789"> + <green>This text must be green</green> + </iota> + </theta> + </zeta> + </chi> + </omega> + </tree> + </test> + <test> + <xpath>//beta/mu[@desciption][@xml:lang="no"][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[starts-with(concat(@attribute,"-"),"attribute-")][not(following-sibling::*)]//beta[contains(@or,"content")][@xml:lang="en"][@xml:id="id2"]/chi[@abort][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[@attrib][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::gamma[@xml:id="id5"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <beta> + <mu desciption="attribute" xml:lang="no"/> + <alpha xml:id="id1"/> + <tau attribute="attribute"> + <beta or="content" xml:lang="en" xml:id="id2"> + <chi abort="123456789"/> + <alpha xml:id="id3"/> + <eta attrib="attribute value" xml:id="id4"/> + <gamma xml:id="id5"> + <green>This text must be green</green> + </gamma> + </beta> + </tau> + </beta> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en-US"][@xml:id="id1"]/psi[contains(@data,"se")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[contains(concat(@token,"$"),"nk$")][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]//nu[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::phi[starts-with(@and,"this-is-att-val")][not(child::node())][following-sibling::eta[contains(@attribute,"is-is-att-v")][@xml:id="id4"][not(following-sibling::*)]/nu[@xml:id="id5"][not(preceding-sibling::*)][not(preceding-sibling::nu)]//tau[not(preceding-sibling::*)][following-sibling::alpha[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[@false][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[not(preceding-sibling::*)]//mu[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]/zeta[@name="another attribute value"][not(preceding-sibling::*)]//delta[@insert="123456789"][not(following-sibling::*)]/iota[@xml:id="id7"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="en-US" xml:id="id1"> + <psi data="false"/> + <gamma xml:lang="no"> + <delta token="_blank" xml:lang="en-GB" xml:id="id2"> + <nu xml:id="id3"/> + <phi and="this-is-att-value"/> + <eta attribute="this-is-att-value" xml:id="id4"> + <nu xml:id="id5"> + <tau/> + <alpha xml:lang="en-GB"> + <rho false="false" xml:lang="no"/> + <omicron> + <chi> + <mu xml:lang="en-GB"/> + <kappa xml:lang="en-GB" xml:id="id6"> + <zeta name="another attribute value"> + <delta insert="123456789"> + <iota xml:id="id7"> + <green>This text must be green</green> + </iota> + </delta> + </zeta> + </kappa> + </chi> + </omicron> + </alpha> + </nu> + </eta> + </delta> + </gamma> + </iota> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:id="id1"]//omega[@xml:lang="en-US"]/kappa[@desciption][not(preceding-sibling::*)]//omicron[@and="100%"][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[preceding-sibling::*[position() = 1]][following-sibling::theta[@title][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/pi[@and="attribute-value"][@xml:lang="en"][@xml:id="id3"]/upsilon[@xml:lang="nb"][following-sibling::omicron[@att="true"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[@or][@xml:id="id5"][not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:id="id1"> + <omega xml:lang="en-US"> + <kappa desciption="true"> + <omicron and="100%" xml:lang="no"/> + <mu/> + <theta title="attribute" xml:lang="no" xml:id="id2"> + <pi and="attribute-value" xml:lang="en" xml:id="id3"> + <upsilon xml:lang="nb"/> + <omicron att="true" xml:id="id4"> + <mu or="false" xml:id="id5"> + <green>This text must be green</green> + </mu> + </omicron> + </pi> + </theta> + </kappa> + </omega> + </upsilon> + </tree> + </test> + <test> + <xpath>//zeta/gamma[@class][@xml:id="id1"][not(following-sibling::*)]/sigma[@delete][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(@and,"ute-value")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[contains(concat(@string,"$"),"attribute-value$")][@xml:lang="no-nb"][@xml:id="id3"]//epsilon[@desciption][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/sigma[@xml:id="id5"][following-sibling::*[position()=11]][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=10]][following-sibling::omicron[@xml:lang="en-GB"][following-sibling::omicron[@content][@xml:id="id7"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::eta[@true][@xml:lang="nb"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=7]][following-sibling::tau[@xml:id="id8"][following-sibling::psi[@xml:id="id9"][not(child::node())][following-sibling::delta[contains(concat(@and,"$"),"nt$")][@xml:id="id10"][preceding-sibling::*[position() = 7]][following-sibling::*[position()=4]][following-sibling::zeta[@xml:id="id11"][following-sibling::alpha[not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 10]][following-sibling::psi[@string="false"][preceding-sibling::*[position() = 11]]][position() = 1]]]]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <zeta> + <gamma class="this-is-att-value" xml:id="id1"> + <sigma delete="false" xml:lang="nb" xml:id="id2"/> + <mu and="attribute-value"> + <upsilon string="attribute-value" xml:lang="no-nb" xml:id="id3"> + <epsilon desciption="attribute" xml:lang="no-nb" xml:id="id4"> + <sigma xml:id="id5"/> + <xi xml:lang="en-GB" xml:id="id6"/> + <omicron xml:lang="en-GB"/> + <omicron content="this.nodeValue" xml:id="id7"/> + <eta true="false" xml:lang="nb"/> + <tau xml:id="id8"/> + <psi xml:id="id9"/> + <delta and="content" xml:id="id10"/> + <zeta xml:id="id11"/> + <alpha/> + <iota/> + <psi string="false"> + <green>This text must be green</green> + </psi> + </epsilon> + </upsilon> + </mu> + </gamma> + </zeta> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]//tau[following-sibling::*[position()=1]][following-sibling::rho[starts-with(concat(@and,"-"),"attribute-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[following-sibling::*[position()=6]][not(child::node())][following-sibling::omicron[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=4]][following-sibling::theta[@token][@xml:lang="en-GB"][following-sibling::*[position()=3]][following-sibling::alpha[contains(concat(@string,"$"),"123456789$")][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::chi[@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::iota//pi[@name][@xml:id="id5"][not(preceding-sibling::*)]/phi[@xml:id="id6"][not(child::node())][following-sibling::pi[@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::theta[contains(@attrib,"olid 1p")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::pi[@false][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <tau/> + <rho and="attribute-value" xml:lang="en"> + <phi/> + <omicron xml:lang="en" xml:id="id2"/> + <alpha xml:id="id3"/> + <theta token="attribute value" xml:lang="en-GB"/> + <alpha string="123456789"/> + <chi xml:id="id4"/> + <iota> + <pi name="123456789" xml:id="id5"> + <phi xml:id="id6"/> + <pi xml:id="id7"/> + <theta attrib="solid 1px green"/> + <pi false="this.nodeValue" xml:id="id8"> + <green>This text must be green</green> + </pi> + </pi> + </iota> + </rho> + </pi> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no"][@xml:id="id1"]/chi[contains(@name,"0")][@xml:lang="en-GB"][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@attr][@xml:id="id2"][following-sibling::epsilon[@xml:lang="en"][@xml:id="id3"][not(following-sibling::epsilon)]/psi[starts-with(@title,"attrib")][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:lang="nb"][@xml:id="id5"][following-sibling::*[position()=1]][not(preceding-sibling::iota)][not(child::node())][following-sibling::epsilon[@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]//omicron[@src][@xml:lang="en-US"][@xml:id="id7"][following-sibling::*[position()=3]][following-sibling::upsilon[contains(@and,"fa")][@xml:id="id8"][following-sibling::sigma[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::zeta[starts-with(concat(@and,"-"),"123456789-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no" xml:id="id1"> + <chi name="100%" xml:lang="en-GB"/> + <any attr="this.nodeValue" xml:id="id2"/> + <epsilon xml:lang="en" xml:id="id3"> + <psi title="attribute" xml:lang="no-nb" xml:id="id4"/> + <iota xml:lang="nb" xml:id="id5"/> + <epsilon xml:lang="en" xml:id="id6"> + <omicron src="true" xml:lang="en-US" xml:id="id7"/> + <upsilon and="false" xml:id="id8"/> + <sigma xml:lang="no"/> + <zeta and="123456789" xml:lang="en-GB"> + <green>This text must be green</green> + </zeta> + </epsilon> + </epsilon> + </iota> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no-nb"][@xml:id="id1"]//rho[@xml:id="id2"][not(child::node())][following-sibling::chi[not(following-sibling::*)]/rho[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::kappa[@xml:lang="en"][following-sibling::*[@or][@xml:lang="en-GB"][@xml:id="id4"]//mu[@xml:lang="en"][@xml:id="id5"]//psi[following-sibling::pi[@number][not(following-sibling::*)]/beta[@xml:lang="en-GB"][following-sibling::*[position()=2]][following-sibling::lambda[@or][@xml:id="id6"][following-sibling::gamma[starts-with(concat(@insert,"-"),"content-")][@xml:lang="no"][@xml:id="id7"][not(following-sibling::*)]//*[@xml:lang="en-US"][@xml:id="id8"]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no-nb" xml:id="id1"> + <rho xml:id="id2"/> + <chi> + <rho xml:lang="no" xml:id="id3"/> + <kappa xml:lang="en"/> + <any or="this.nodeValue" xml:lang="en-GB" xml:id="id4"> + <mu xml:lang="en" xml:id="id5"> + <psi/> + <pi number="123456789"> + <beta xml:lang="en-GB"/> + <lambda or="100%" xml:id="id6"/> + <gamma insert="content" xml:lang="no" xml:id="id7"> + <any xml:lang="en-US" xml:id="id8"> + <green>This text must be green</green> + </any> + </gamma> + </pi> + </mu> + </any> + </chi> + </lambda> + </tree> + </test> + <test> + <xpath>//kappa[@data][@xml:lang="no"][@xml:id="id1"]//rho[contains(concat(@object,"$"),"te value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::rho)][following-sibling::phi[following-sibling::tau[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[@attribute][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::alpha[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/alpha[@xml:id="id4"][following-sibling::pi[contains(concat(@att,"$"),"lank$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[starts-with(concat(@and,"-"),"attribute value-")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <kappa data="this.nodeValue" xml:lang="no" xml:id="id1"> + <rho object="another attribute value" xml:lang="no-nb"/> + <phi/> + <tau xml:lang="en-GB" xml:id="id2"> + <mu attribute="100%" xml:lang="nb"/> + <alpha xml:lang="en-US" xml:id="id3"> + <alpha xml:id="id4"/> + <pi att="_blank" xml:lang="en"/> + <chi and="attribute value" xml:lang="no"> + <green>This text must be green</green> + </chi> + </alpha> + </tau> + </kappa> + </tree> + </test> + <test> + <xpath>//omicron[@xml:id="id1"]/kappa[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::gamma[@xml:id="id3"][not(following-sibling::*)]/rho[@xml:lang="nb"][not(preceding-sibling::*)]/rho[@xml:lang="en-US"]//upsilon[starts-with(@desciption,"false")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[starts-with(@delete,"123456789")][@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@data="content"][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 2]]/beta[contains(@title,"n")][@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]/omicron[@xml:lang="no"][not(child::node())][following-sibling::gamma[@false][@xml:id="id8"]/iota[following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[contains(concat(@title,"$"),"3456789$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::epsilon[@xml:lang="en-GB"][@xml:id="id9"]/zeta[contains(@delete,"reen")]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:id="id1"> + <kappa xml:lang="nb" xml:id="id2"/> + <gamma xml:id="id3"> + <rho xml:lang="nb"> + <rho xml:lang="en-US"> + <upsilon desciption="false" xml:id="id4"/> + <delta delete="123456789" xml:lang="no" xml:id="id5"/> + <upsilon data="content" xml:lang="no" xml:id="id6"> + <beta title="solid 1px green" xml:lang="en-GB" xml:id="id7"> + <omicron xml:lang="no"/> + <gamma false="attribute value" xml:id="id8"> + <iota/> + <omega title="123456789"/> + <iota xml:lang="no-nb"/> + <epsilon xml:lang="en-GB" xml:id="id9"> + <zeta delete="solid 1px green"> + <green>This text must be green</green> + </zeta> + </epsilon> + </gamma> + </beta> + </upsilon> + </rho> + </rho> + </gamma> + </omicron> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]//theta[starts-with(concat(@desciption,"-"),"false-")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(@or,"_blan")][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::theta[contains(concat(@content,"$"),"100%$")][@xml:lang="en-US"][@xml:id="id4"][not(child::node())][following-sibling::beta[starts-with(concat(@title,"-"),"false-")][@xml:lang="nb"][not(following-sibling::*)]//iota[@delete][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[starts-with(@att,"this-is-att-va")][not(preceding-sibling::*)]/iota[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:lang="en"][@xml:id="id6"][not(child::node())][following-sibling::*[contains(@and,"-value")][@xml:lang="nb"]/rho[following-sibling::epsilon[@abort][@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]//epsilon[@attrib][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <theta desciption="false" xml:lang="en-US" xml:id="id2"/> + <upsilon or="_blank" xml:lang="no-nb" xml:id="id3"/> + <theta content="100%" xml:lang="en-US" xml:id="id4"/> + <beta title="false" xml:lang="nb"> + <iota delete="another attribute value" xml:id="id5"> + <tau att="this-is-att-value"> + <iota xml:lang="no"> + <theta xml:lang="en" xml:id="id6"/> + <any and="attribute-value" xml:lang="nb"> + <rho/> + <epsilon abort="100%" xml:lang="no-nb" xml:id="id7"> + <epsilon attrib="solid 1px green"/> + <eta> + <green>This text must be green</green> + </eta> + </epsilon> + </any> + </iota> + </tau> + </iota> + </beta> + </phi> + </tree> + </test> + <test> + <xpath>//kappa[@abort]//delta[contains(@attr,"alu")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)]//epsilon[starts-with(concat(@attribute,"-"),"_blank-")][@xml:lang="no"][not(child::node())][following-sibling::omicron[@delete][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::theta[starts-with(@and,"attribute v")][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::delta[not(child::node())][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/eta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[not(preceding-sibling::*)]/theta[not(child::node())][following-sibling::beta[starts-with(@string,"a")][@xml:lang="nb"][not(following-sibling::*)]//epsilon[contains(@att,"olid 1px gr")][@xml:id="id4"][following-sibling::delta[@or="solid 1px green"][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[not(child::node())][following-sibling::eta[@xml:lang="nb"][not(child::node())][following-sibling::epsilon[@xml:id="id6"][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::phi[@attr="123456789"][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="en-GB"]//lambda[@xml:id="id9"][not(preceding-sibling::*)]//omicron[@attr="content"][@xml:lang="no-nb"][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:id="id11"]]]]][position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <kappa abort="another attribute value"> + <delta attr="attribute-value" xml:lang="en-US" xml:id="id1"> + <epsilon attribute="_blank" xml:lang="no"/> + <omicron delete="attribute-value" xml:lang="en-GB"/> + <theta and="attribute value" xml:id="id2"/> + <delta/> + <alpha xml:id="id3"> + <eta xml:lang="no-nb"> + <pi> + <theta/> + <beta string="attribute" xml:lang="nb"> + <epsilon att="solid 1px green" xml:id="id4"/> + <delta or="solid 1px green" xml:lang="nb" xml:id="id5"> + <pi/> + <eta xml:lang="nb"/> + <epsilon xml:id="id6"/> + <lambda xml:lang="en-US" xml:id="id7"/> + <phi attr="123456789" xml:id="id8"/> + <omega xml:lang="en-GB"> + <lambda xml:id="id9"> + <omicron attr="content" xml:lang="no-nb"/> + <pi xml:lang="en" xml:id="id10"> + <xi xml:id="id11"> + <green>This text must be green</green> + </xi> + </pi> + </lambda> + </omega> + </delta> + </beta> + </pi> + </eta> + </alpha> + </delta> + </kappa> + </tree> + </test> + <test> + <xpath>//*[@xml:id="id1"]/delta[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][@xml:id="id3"]//theta[@src][@xml:lang="en"][following-sibling::eta[@xml:id="id4"]/chi[@abort][@xml:id="id5"][not(child::node())][following-sibling::iota[starts-with(@false,"tru")][@xml:lang="nb"][not(following-sibling::*)]/psi[@att="solid 1px green"][@xml:lang="no-nb"]//kappa[@or][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::kappa[@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:id="id8"][not(following-sibling::*)]//kappa[starts-with(@attribute,"another a")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(concat(@insert,"-"),"attribute-")][@xml:lang="en-GB"][not(following-sibling::*)]/*[@and][@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)]//omicron[@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)]/phi[@xml:id="id11"][not(child::node())][following-sibling::tau[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::pi[@xml:id="id12"][following-sibling::iota[@name="123456789"][preceding-sibling::*[position() = 3]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:id="id1"> + <delta xml:lang="en-US" xml:id="id2"/> + <upsilon xml:lang="nb" xml:id="id3"> + <theta src="123456789" xml:lang="en"/> + <eta xml:id="id4"> + <chi abort="false" xml:id="id5"/> + <iota false="true" xml:lang="nb"> + <psi att="solid 1px green" xml:lang="no-nb"> + <kappa or="123456789" xml:lang="nb"/> + <rho xml:id="id6"/> + <kappa xml:id="id7"/> + <chi xml:id="id8"> + <kappa attribute="another attribute value" xml:lang="en-US"/> + <sigma insert="attribute-value" xml:lang="en-GB"> + <any and="another attribute value" xml:lang="no-nb" xml:id="id9"> + <omicron xml:lang="nb" xml:id="id10"> + <phi xml:id="id11"/> + <tau xml:lang="en"/> + <pi xml:id="id12"/> + <iota name="123456789"> + <green>This text must be green</green> + </iota> + </omicron> + </any> + </sigma> + </chi> + </psi> + </iota> + </eta> + </upsilon> + </any> + </tree> + </test> + <test> + <xpath>//iota[contains(@and,"ute value")][@xml:id="id1"]/nu[contains(@and," ")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::psi[starts-with(@token,"fals")][@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::tau[not(following-sibling::*)]/gamma[starts-with(@content,"a")][@xml:lang="en-GB"]//alpha[@data][@xml:lang="en-US"][not(preceding-sibling::*)]//upsilon[contains(concat(@true,"$"),"tribute-value$")][not(following-sibling::*)]/chi[contains(@data,"alue")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@src="another attribute value"][not(following-sibling::*)]//pi[@false][@xml:lang="no"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <iota and="another attribute value" xml:id="id1"> + <nu and="another attribute value" xml:lang="no"/> + <psi token="false" xml:lang="en-US" xml:id="id2"/> + <tau> + <gamma content="attribute-value" xml:lang="en-GB"> + <alpha data="this.nodeValue" xml:lang="en-US"> + <upsilon true="attribute-value"> + <chi data="another attribute value" xml:lang="nb" xml:id="id3"/> + <omicron src="another attribute value"> + <pi false="true" xml:lang="no"> + <green>This text must be green</green> + </pi> + </omicron> + </upsilon> + </alpha> + </gamma> + </tau> + </iota> + </tree> + </test> + <test> + <xpath>//eta/alpha[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="nb"]//iota/delta[contains(@token,"alue")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omega[@xml:id="id3"][preceding-sibling::*[position() = 1]]//theta[@xml:id="id4"][not(preceding-sibling::*)]/delta[@xml:lang="no-nb"][not(preceding-sibling::*)]//theta[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en-US"]//lambda//beta[@data][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(concat(@object,"$"),"bute value$")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@and][@xml:lang="en-US"][@xml:id="id8"]//*[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[not(preceding-sibling::*)][following-sibling::*[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@or][@xml:id="id9"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <eta> + <alpha xml:lang="no-nb" xml:id="id1"/> + <sigma xml:lang="nb"> + <iota> + <delta token="attribute value" xml:lang="en" xml:id="id2"/> + <omega xml:id="id3"> + <theta xml:id="id4"> + <delta xml:lang="no-nb"> + <theta xml:lang="nb" xml:id="id5"/> + <psi xml:lang="en-US"> + <lambda> + <beta data="content" xml:lang="no-nb" xml:id="id6"/> + <kappa object="another attribute value" xml:lang="en-US" xml:id="id7"> + <alpha and="_blank" xml:lang="en-US" xml:id="id8"> + <any xml:lang="en-US"> + <alpha/> + <any/> + <phi or="attribute" xml:id="id9"> + <green>This text must be green</green> + </phi> + </any> + </alpha> + </kappa> + </lambda> + </psi> + </delta> + </theta> + </omega> + </iota> + </sigma> + </eta> + </tree> + </test> + <test> + <xpath>//delta//delta[contains(@attr,"att")][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="en-GB"]//mu[starts-with(@true,"this.nodeVa")][@xml:lang="en"][@xml:id="id2"][not(child::node())][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(preceding-sibling::upsilon)]//lambda[starts-with(concat(@attribute,"-"),"_blank-")][@xml:lang="en-GB"][@xml:id="id4"]//theta[@data][@xml:lang="en-GB"][following-sibling::gamma[preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]/omega[@xml:id="id5"][not(preceding-sibling::*)]//xi[@class][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[contains(@string,"this-is-a")][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@number][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//eta[not(preceding-sibling::*)][not(following-sibling::*)]//eta[@xml:id="id7"][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omicron[contains(concat(@src,"$"),"his.nodeValue$")][@xml:id="id9"][preceding-sibling::*[position() = 2]]//upsilon[starts-with(@name,"fals")][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::beta[@xml:lang="no"][@xml:id="id11"][not(following-sibling::*)]/alpha[@delete][@xml:id="id12"][not(preceding-sibling::*)]/pi[starts-with(@name,"a")][@xml:lang="no"][@xml:id="id13"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[contains(concat(@attribute,"$"),"blank$")]/alpha[@xml:lang="en-US"][not(preceding-sibling::*)]//alpha[@true="123456789"][@xml:lang="en-GB"][@xml:id="id14"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>1</nth> + </result> + <tree> + <delta> + <delta attr="attribute value" xml:lang="en-GB" xml:id="id1"/> + <iota xml:lang="en-GB"> + <mu true="this.nodeValue" xml:lang="en" xml:id="id2"/> + <upsilon xml:lang="no-nb" xml:id="id3"> + <lambda attribute="_blank" xml:lang="en-GB" xml:id="id4"> + <theta data="another attribute value" xml:lang="en-GB"/> + <gamma/> + <omega xml:lang="en-GB"> + <omega xml:id="id5"> + <xi class="true" xml:lang="no"/> + <rho string="this-is-att-value"/> + <phi number="attribute value" xml:id="id6"> + <eta> + <eta xml:id="id7"/> + <omega xml:lang="en-GB" xml:id="id8"/> + <omicron src="this.nodeValue" xml:id="id9"> + <upsilon name="false" xml:id="id10"/> + <beta xml:lang="no" xml:id="id11"> + <alpha delete="this.nodeValue" xml:id="id12"> + <pi name="another attribute value" xml:lang="no" xml:id="id13"/> + <lambda attribute="_blank"> + <alpha xml:lang="en-US"> + <alpha true="123456789" xml:lang="en-GB" xml:id="id14"> + <green>This text must be green</green> + </alpha> + </alpha> + </lambda> + </alpha> + </beta> + </omicron> + </eta> + </phi> + </omega> + </omega> + </lambda> + </upsilon> + </iota> + </delta> + </tree> + </test> + <test> + <xpath>//tau/tau[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::upsilon[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@number="attribute-value"][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::chi[contains(@attribute,"bu")][@xml:id="id1"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:lang="no"][@xml:id="id2"]/nu[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::mu[starts-with(concat(@token,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id4"][not(child::node())][following-sibling::chi[@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/upsilon[starts-with(@string,"attribute-")][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)]/alpha[@true="attribute-value"][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <tau> + <tau xml:lang="no-nb"> + <lambda xml:lang="no-nb"/> + <upsilon xml:lang="no"/> + <xi number="attribute-value" xml:lang="nb"/> + <chi attribute="attribute value" xml:id="id1"/> + <epsilon xml:lang="no" xml:id="id2"> + <nu xml:id="id3"/> + <mu token="solid 1px green"/> + <tau xml:lang="no-nb" xml:id="id4"/> + <chi xml:lang="nb"> + <upsilon string="attribute-value" xml:lang="en" xml:id="id5"> + <alpha true="attribute-value" xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </alpha> + </upsilon> + </chi> + </epsilon> + </tau> + </tau> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(@attr,"attribute valu")][@xml:id="id1"]/psi[contains(concat(@src,"$"),"-att-value$")][@xml:lang="en"]//sigma[@xml:id="id2"][not(preceding-sibling::*)]//kappa[contains(@attrib,"attri")][@xml:id="id3"][not(preceding-sibling::*)]/alpha[@attr][@xml:id="id4"][not(following-sibling::*)]//alpha[contains(concat(@string,"$"),"89$")][@xml:lang="en-US"]//tau[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <alpha attr="attribute value" xml:id="id1"> + <psi src="this-is-att-value" xml:lang="en"> + <sigma xml:id="id2"> + <kappa attrib="attribute value" xml:id="id3"> + <alpha attr="true" xml:id="id4"> + <alpha string="123456789" xml:lang="en-US"> + <tau xml:lang="en" xml:id="id5"> + <green>This text must be green</green> + </tau> + </alpha> + </alpha> + </kappa> + </sigma> + </psi> + </alpha> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]/rho[not(following-sibling::*)]/mu[not(preceding-sibling::*)][not(following-sibling::*)]/mu[@data="this-is-att-value"][following-sibling::alpha[@xml:lang="en-US"][following-sibling::eta[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/psi[contains(concat(@title,"$"),"value$")][@xml:lang="en"]//tau[contains(concat(@class,"$"),"ue$")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::alpha[not(following-sibling::*)]/tau[@xml:lang="en-GB"][@xml:id="id5"]//omicron[contains(concat(@abort,"$"),"bute value$")][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="en"][not(following-sibling::*)]//alpha[@xml:id="id7"]/sigma[@attribute="123456789"][@xml:lang="en"][@xml:id="id8"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>1</nth> + </result> + <tree> + <phi xml:id="id1"> + <rho> + <mu> + <mu data="this-is-att-value"/> + <alpha xml:lang="en-US"/> + <eta xml:id="id2"/> + <chi xml:lang="no-nb" xml:id="id3"> + <psi title="attribute value" xml:lang="en"> + <tau class="attribute-value" xml:id="id4"/> + <alpha> + <tau xml:lang="en-GB" xml:id="id5"> + <omicron abort="another attribute value" xml:id="id6"/> + <phi xml:lang="en"> + <alpha xml:id="id7"> + <sigma attribute="123456789" xml:lang="en" xml:id="id8"> + <green>This text must be green</green> + </sigma> + </alpha> + </phi> + </tau> + </alpha> + </psi> + </chi> + </mu> + </rho> + </phi> + </tree> + </test> + <test> + <xpath>//sigma[contains(@false,"0%")][@xml:lang="no-nb"]/tau[@insert][@xml:id="id1"]//*[@title="false"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[contains(concat(@false,"$"),"nk$")][@xml:id="id2"][following-sibling::*[position()=3]][following-sibling::nu[@number][@xml:id="id3"][following-sibling::*[@object][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[contains(@att,"nk")][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//omicron[@or][@xml:id="id5"][not(preceding-sibling::*)]//omega[contains(concat(@delete,"$"),"ue$")][not(preceding-sibling::*)]/gamma[starts-with(concat(@abort,"-"),"false-")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::sigma[@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=2]][following-sibling::alpha[@xml:id="id8"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@xml:lang="en-US"]/lambda[@data][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::lambda)][not(child::node())][following-sibling::zeta[starts-with(concat(@delete,"-"),"true-")][@xml:lang="en-GB"]/pi[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>1</nth> + </result> + <tree> + <sigma false="100%" xml:lang="no-nb"> + <tau insert="true" xml:id="id1"> + <any title="false"> + <sigma false="_blank" xml:id="id2"/> + <nu number="attribute" xml:id="id3"/> + <any object="attribute value"/> + <omicron att="_blank" xml:id="id4"> + <omicron or="another attribute value" xml:id="id5"> + <omega delete="true"> + <gamma abort="false" xml:lang="en-US" xml:id="id6"/> + <sigma xml:lang="en-GB" xml:id="id7"/> + <alpha xml:id="id8"/> + <psi xml:lang="en-US"> + <lambda data="another attribute value" xml:lang="nb" xml:id="id9"/> + <zeta delete="true" xml:lang="en-GB"> + <pi> + <green>This text must be green</green> + </pi> + </zeta> + </psi> + </omega> + </omicron> + </omicron> + </any> + </tau> + </sigma> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="no-nb"][@xml:id="id1"]//eta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]/omega[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(@object,"a")][@xml:lang="nb"][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="no-nb" xml:id="id1"> + <eta xml:lang="no-nb"/> + <nu xml:lang="en-GB"> + <omega xml:id="id2"/> + <epsilon xml:lang="en-US" xml:id="id3"/> + <upsilon object="another attribute value" xml:lang="nb"> + <green>This text must be green</green> + </upsilon> + </nu> + </pi> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="nb"]//nu[following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[contains(concat(@and,"$"),"-att-value$")][@xml:lang="en"][not(child::node())][following-sibling::beta[not(following-sibling::*)]//lambda[not(preceding-sibling::*)][not(following-sibling::*)]//mu[starts-with(@title,"false")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::rho[@name="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id1"]/chi[@or="this-is-att-value"][@xml:lang="en-GB"][not(preceding-sibling::*)]/sigma[contains(concat(@att,"$"),"e$")][@xml:id="id2"][not(preceding-sibling::*)]//tau[not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:id="id3"]//pi[@xml:lang="en-US"][following-sibling::sigma[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[@string][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[contains(@title,"nk")][@xml:id="id5"][following-sibling::beta[contains(concat(@desciption,"$")," value$")][@xml:id="id6"][not(preceding-sibling::beta)][not(child::node())][following-sibling::rho[@src][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::xi[contains(@number," va")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::iota[not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="nb"> + <nu/> + <rho and="this-is-att-value" xml:lang="en"/> + <beta> + <lambda> + <mu title="false" xml:lang="en"/> + <rho name="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <chi or="this-is-att-value" xml:lang="en-GB"> + <sigma att="false" xml:id="id2"> + <tau/> + <omega xml:id="id3"> + <pi xml:lang="en-US"/> + <sigma xml:lang="no"> + <xi string="solid 1px green" xml:id="id4"> + <psi title="_blank" xml:id="id5"/> + <beta desciption="attribute value" xml:id="id6"/> + <rho src="100%" xml:lang="en-US" xml:id="id7"/> + <xi number="attribute value" xml:lang="nb"/> + <iota> + <green>This text must be green</green> + </iota> + </xi> + </sigma> + </omega> + </sigma> + </chi> + </rho> + </lambda> + </beta> + </upsilon> + </tree> + </test> + <test> + <xpath>//theta[@att][@xml:lang="no"]/phi[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)]//omicron[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//xi[contains(@name,"tribut")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::xi[not(following-sibling::*)]//epsilon[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>1</nth> + </result> + <tree> + <theta att="false" xml:lang="no"> + <phi xml:lang="en-GB" xml:id="id1"> + <omicron xml:lang="en-GB" xml:id="id2"> + <omicron xml:lang="no-nb"/> + <iota xml:lang="nb" xml:id="id3"> + <xi name="attribute value" xml:lang="en" xml:id="id4"/> + <xi> + <epsilon xml:lang="en-US" xml:id="id5"> + <green>This text must be green</green> + </epsilon> + </xi> + </iota> + </omicron> + </phi> + </theta> + </tree> + </test> + <test> + <xpath>//xi[@abort="100%"][@xml:lang="en-GB"][@xml:id="id1"]//theta[starts-with(@src,"this-is-att-valu")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::alpha[preceding-sibling::*[position() = 1]]//phi[not(preceding-sibling::*)][following-sibling::sigma[@name][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//rho[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/zeta[following-sibling::theta[@xml:lang="nb"][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <xi abort="100%" xml:lang="en-GB" xml:id="id1"> + <theta src="this-is-att-value" xml:id="id2"/> + <alpha> + <phi/> + <sigma name="100%" xml:lang="no"/> + <chi xml:lang="no-nb" xml:id="id3"> + <rho xml:lang="no-nb" xml:id="id4"> + <zeta/> + <theta xml:lang="nb"> + <green>This text must be green</green> + </theta> + </rho> + </chi> + </alpha> + </xi> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="no"]//lambda[@att][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[contains(concat(@att,"$"),"his.nodeValue$")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[contains(concat(@true,"$"),"ue$")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega[contains(@insert,"alse")][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::xi[not(child::node())][following-sibling::pi[starts-with(@att,"solid 1px gre")][@xml:id="id4"][preceding-sibling::*[position() = 5]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="no"> + <lambda att="attribute value" xml:id="id1"> + <zeta att="this.nodeValue" xml:id="id2"/> + <sigma/> + <psi true="attribute value" xml:lang="en-US"/> + <omega insert="false" xml:lang="en-US" xml:id="id3"/> + <xi/> + <pi att="solid 1px green" xml:id="id4"> + <green>This text must be green</green> + </pi> + </lambda> + </xi> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]/pi[contains(concat(@object,"$"),"3456789$")][@xml:id="id2"][following-sibling::zeta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//rho[starts-with(@object,"another attribute valu")][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:id="id5"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][following-sibling::phi[@attribute="100%"][@xml:id="id6"][preceding-sibling::*[position() = 2]]/theta[@xml:lang="en"][following-sibling::upsilon[starts-with(concat(@delete,"-"),"this.nodeValue-")][@xml:id="id7"]/chi[@false][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[starts-with(@src,"this.nodeVal")][@xml:id="id8"][preceding-sibling::*[position() = 1]]//iota[@xml:lang="en"][@xml:id="id9"][following-sibling::chi[contains(@and,".no")][@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[starts-with(@object,"fal")][@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:id="id1"> + <pi object="123456789" xml:id="id2"/> + <zeta xml:lang="no" xml:id="id3"> + <rho object="another attribute value" xml:id="id4"> + <epsilon xml:id="id5"/> + <nu/> + <phi attribute="100%" xml:id="id6"> + <theta xml:lang="en"/> + <upsilon delete="this.nodeValue" xml:id="id7"> + <chi false="content" xml:lang="nb"/> + <pi src="this.nodeValue" xml:id="id8"> + <iota xml:lang="en" xml:id="id9"/> + <chi and="this.nodeValue" xml:lang="nb" xml:id="id10"> + <nu content="this.nodeValue" xml:lang="en-GB"/> + <rho object="false" xml:lang="en-GB"> + <green>This text must be green</green> + </rho> + </chi> + </pi> + </upsilon> + </phi> + </rho> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@attr,"$"),"1px green$")][@xml:id="id1"]/eta[@xml:lang="en"][not(preceding-sibling::*)]/sigma[@xml:id="id2"][not(preceding-sibling::*)]//zeta[not(following-sibling::*)]/lambda[@xml:lang="no"][not(preceding-sibling::*)]/theta[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/omicron[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]//omicron[not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="no"][not(following-sibling::*)]/lambda[not(following-sibling::*)]/alpha[contains(concat(@desciption,"$"),"123456789$")][@xml:lang="en-US"][@xml:id="id5"]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <beta attr="solid 1px green" xml:id="id1"> + <eta xml:lang="en"> + <sigma xml:id="id2"> + <zeta> + <lambda xml:lang="no"> + <theta xml:lang="no-nb" xml:id="id3"> + <omicron xml:lang="no" xml:id="id4"> + <omicron> + <xi xml:lang="no"> + <lambda> + <alpha desciption="123456789" xml:lang="en-US" xml:id="id5"> + <green>This text must be green</green> + </alpha> + </lambda> + </xi> + </omicron> + </omicron> + </theta> + </lambda> + </zeta> + </sigma> + </eta> + </beta> + </tree> + </test> + <test> + <xpath>//mu[@name][@xml:lang="no"]/phi[@xml:lang="no-nb"][not(following-sibling::*)]/theta[contains(concat(@data,"$"),"lank$")][@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]/xi[starts-with(@insert,"con")][not(following-sibling::*)]//tau[not(preceding-sibling::*)][following-sibling::beta[@attrib][not(following-sibling::*)]//gamma[contains(@title,"se")][@xml:lang="no-nb"][following-sibling::zeta[@insert="this-is-att-value"][not(child::node())][following-sibling::alpha[@xml:lang="en-US"][not(child::node())][following-sibling::zeta[@content="attribute-value"][preceding-sibling::*[position() = 3]][following-sibling::kappa[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=6]][not(child::node())][following-sibling::beta[@desciption][@xml:lang="no-nb"][not(child::node())][following-sibling::pi[@delete="_blank"][preceding-sibling::*[position() = 6]][following-sibling::*[position()=4]][not(child::node())][following-sibling::gamma[contains(@insert,"ute")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 7]][following-sibling::*[position()=3]][not(child::node())][following-sibling::*[@true][@xml:lang="no"][@xml:id="id4"][following-sibling::pi[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 9]][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@false][@xml:lang="no"]//upsilon[@xml:id="id6"][not(preceding-sibling::*)]//psi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::rho[@attribute][@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::delta[@attribute="_blank"][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <mu name="solid 1px green" xml:lang="no"> + <phi xml:lang="no-nb"> + <theta data="_blank" xml:lang="en-GB" xml:id="id1"> + <xi insert="content"> + <tau/> + <beta attrib="false"> + <gamma title="false" xml:lang="no-nb"/> + <zeta insert="this-is-att-value"/> + <alpha xml:lang="en-US"/> + <zeta content="attribute-value"/> + <kappa xml:lang="no-nb" xml:id="id2"/> + <beta desciption="100%" xml:lang="no-nb"/> + <pi delete="_blank"/> + <gamma insert="attribute" xml:lang="nb" xml:id="id3"/> + <any true="content" xml:lang="no" xml:id="id4"/> + <pi xml:lang="en" xml:id="id5"/> + <eta false="another attribute value" xml:lang="no"> + <upsilon xml:id="id6"> + <psi xml:lang="no-nb"/> + <rho attribute="another attribute value" xml:lang="no-nb" xml:id="id7"/> + <delta attribute="_blank" xml:lang="en-GB" xml:id="id8"> + <omega xml:lang="no-nb"> + <green>This text must be green</green> + </omega> + </delta> + </upsilon> + </eta> + </beta> + </xi> + </theta> + </phi> + </mu> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="nb"][@xml:id="id1"]/sigma[@xml:id="id2"][not(following-sibling::*)]/xi[@content="attribute"][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::pi[starts-with(concat(@content,"-"),"123456789-")][preceding-sibling::*[position() = 1]][following-sibling::lambda[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//xi[@attribute][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(concat(@attr,"$"),"0%$")][not(preceding-sibling::eta)][following-sibling::kappa[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/xi[@xml:lang="no-nb"][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::sigma[@true="attribute-value"]/sigma[@token][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[contains(@delete,"ibute-value")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:id="id7"][following-sibling::epsilon[@or="attribute value"][@xml:lang="en-GB"][not(child::node())][following-sibling::theta[@delete="this-is-att-value"][@xml:id="id8"][not(following-sibling::*)]//delta[contains(concat(@true,"$"),"deValue$")][following-sibling::delta[@name="_blank"][@xml:lang="no"][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[@xml:lang="en-US"][@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::zeta[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="nb" xml:id="id1"> + <sigma xml:id="id2"> + <xi content="attribute" xml:lang="no-nb" xml:id="id3"/> + <pi content="123456789"/> + <lambda> + <xi attribute="this.nodeValue"/> + <eta attr="100%"/> + <kappa xml:lang="no-nb" xml:id="id4"> + <xi xml:lang="no-nb"/> + <tau xml:lang="no-nb" xml:id="id5"/> + <sigma true="attribute-value"> + <sigma token="content" xml:lang="en"> + <epsilon delete="attribute-value" xml:lang="no-nb" xml:id="id6"> + <any xml:id="id7"/> + <epsilon or="attribute value" xml:lang="en-GB"/> + <theta delete="this-is-att-value" xml:id="id8"> + <delta true="this.nodeValue"/> + <delta name="_blank" xml:lang="no"/> + <beta xml:lang="nb"> + <omega xml:lang="en-US" xml:id="id9"/> + <zeta attr="attribute" xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </zeta> + </beta> + </theta> + </epsilon> + </sigma> + </sigma> + </kappa> + </lambda> + </sigma> + </alpha> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en"][@xml:id="id1"]/rho[starts-with(@src,"f")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::epsilon[contains(concat(@title,"$"),"t$")][@xml:id="id3"][not(following-sibling::*)]//lambda[contains(concat(@token,"$"),"-value$")][not(child::node())][following-sibling::iota[starts-with(concat(@and,"-"),"attribute value-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]//kappa[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:lang="no"][preceding-sibling::*[position() = 1]]//theta[starts-with(@abort,"soli")][@xml:id="id6"]//delta[@attribute="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en" xml:id="id1"> + <rho src="false" xml:id="id2"/> + <epsilon title="content" xml:id="id3"> + <lambda token="attribute-value"/> + <iota and="attribute value" xml:lang="nb"> + <pi xml:lang="en" xml:id="id4"> + <kappa xml:id="id5"/> + <omega xml:lang="no"> + <theta abort="solid 1px green" xml:id="id6"> + <delta attribute="this.nodeValue" xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </delta> + </theta> + </omega> + </pi> + </iota> + </epsilon> + </upsilon> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@attrib,"-"),"this.nodeValue-")][@xml:lang="no-nb"][@xml:id="id1"]/nu[@xml:lang="nb"][following-sibling::alpha[starts-with(@attrib,"th")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@insert][@xml:id="id3"][not(child::node())][following-sibling::gamma[@xml:lang="en-US"][not(child::node())][following-sibling::mu[@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][following-sibling::delta[preceding-sibling::*[position() = 5]][following-sibling::*[position()=2]][following-sibling::rho[@xml:lang="no"][following-sibling::pi[@false][preceding-sibling::*[position() = 7]]/*[starts-with(@insert,"tr")][not(preceding-sibling::*)][not(preceding-sibling::any)]//alpha[following-sibling::eta[following-sibling::phi[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[@xml:lang="nb"]/beta[@xml:lang="en-GB"]/lambda[@name="this-is-att-value"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id5"]/alpha[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[contains(concat(@desciption,"$"),"%$")][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::eta[contains(@or,"nk")][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:id="id9"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::delta[@xml:lang="no"][@xml:id="id10"][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id11"][preceding-sibling::*[position() = 4]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <zeta attrib="this.nodeValue" xml:lang="no-nb" xml:id="id1"> + <nu xml:lang="nb"/> + <alpha attrib="this.nodeValue" xml:id="id2"/> + <delta insert="_blank" xml:id="id3"/> + <gamma xml:lang="en-US"/> + <mu xml:lang="no-nb"/> + <delta/> + <rho xml:lang="no"/> + <pi false="attribute value"> + <any insert="true"> + <alpha/> + <eta/> + <phi xml:id="id4"/> + <upsilon xml:lang="nb"> + <beta xml:lang="en-GB"> + <lambda name="this-is-att-value"/> + <kappa xml:lang="en-GB" xml:id="id5"> + <alpha xml:id="id6"> + <eta desciption="100%" xml:id="id7"/> + <eta or="_blank" xml:id="id8"/> + <pi xml:id="id9"/> + <delta xml:lang="no" xml:id="id10"/> + <zeta xml:lang="en-GB" xml:id="id11"> + <green>This text must be green</green> + </zeta> + </alpha> + </kappa> + </beta> + </upsilon> + </any> + </pi> + </zeta> + </tree> + </test> + <test> + <xpath>//upsilon[@name="123456789"]//theta[@xml:lang="no"][not(following-sibling::*)]//nu[contains(concat(@attrib,"$"),"te$")][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::chi[starts-with(@object,"false")][not(following-sibling::*)]/pi[@xml:lang="no"][not(following-sibling::*)]/rho[starts-with(concat(@false,"-"),"attribute-")][@xml:id="id2"][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 1]]/alpha[contains(concat(@string,"$"),"false$")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@true][@xml:id="id3"][not(preceding-sibling::*)]//iota[starts-with(@src,"1234567")][@xml:lang="no-nb"][not(preceding-sibling::*)]/upsilon[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[@or="attribute value"][not(following-sibling::*)]/gamma[contains(concat(@or,"$"),"reen$")][@xml:id="id5"][not(preceding-sibling::*)]//rho[@attr="another attribute value"]//phi[@xml:id="id6"][following-sibling::chi[starts-with(@title,"1234567")][preceding-sibling::*[position() = 1]]//xi[not(child::node())][following-sibling::pi[starts-with(concat(@number,"-"),"solid 1px green-")][@xml:id="id7"]/theta[@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]/iota[@attribute="attribute value"][@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon name="123456789"> + <theta xml:lang="no"> + <nu attrib="attribute" xml:id="id1"/> + <chi object="false"> + <pi xml:lang="no"> + <rho false="attribute-value" xml:id="id2"/> + <lambda> + <alpha string="false" xml:lang="en-GB"> + <iota xml:lang="en-GB"> + <rho true="_blank" xml:id="id3"> + <iota src="123456789" xml:lang="no-nb"> + <upsilon xml:lang="en-US" xml:id="id4"> + <zeta or="attribute value"> + <gamma or="solid 1px green" xml:id="id5"> + <rho attr="another attribute value"> + <phi xml:id="id6"/> + <chi title="123456789"> + <xi/> + <pi number="solid 1px green" xml:id="id7"> + <theta xml:lang="en-GB"/> + <theta xml:lang="no" xml:id="id8"> + <iota attribute="attribute value" xml:lang="en-US" xml:id="id9"> + <green>This text must be green</green> + </iota> + </theta> + </pi> + </chi> + </rho> + </gamma> + </zeta> + </upsilon> + </iota> + </rho> + </iota> + </alpha> + </lambda> + </pi> + </chi> + </theta> + </upsilon> + </tree> + </test> + <test> + <xpath>//phi//kappa[@object][@xml:lang="en-US"][@xml:id="id1"]/theta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::iota[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[contains(@attrib,"k")][@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[starts-with(concat(@name,"-"),"100%-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/epsilon[starts-with(@true,"attribute-va")][not(following-sibling::*)]/mu[@xml:lang="en"][@xml:id="id4"][not(child::node())][following-sibling::beta[@false][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::tau[not(following-sibling::*)]/nu[@attribute][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::lambda[@number][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::mu[contains(@true,"cont")][@xml:lang="en-GB"][@xml:id="id5"][not(child::node())][following-sibling::delta[contains(@title,"value")][@xml:lang="en-US"]/omega[@content][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[starts-with(@attrib,"t")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(preceding-sibling::theta or following-sibling::theta)]//rho//sigma[@xml:id="id7"][not(preceding-sibling::*)][position() = 1]]]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <kappa object="this-is-att-value" xml:lang="en-US" xml:id="id1"> + <theta xml:id="id2"/> + <iota xml:id="id3"/> + <chi attrib="_blank" xml:lang="en-GB"/> + <psi name="100%"> + <epsilon true="attribute-value"> + <mu xml:lang="en" xml:id="id4"/> + <beta false="attribute-value"/> + <omicron xml:lang="en-GB"/> + <tau> + <nu attribute="this-is-att-value" xml:lang="no"/> + <lambda number="attribute value" xml:lang="no-nb"/> + <mu true="content" xml:lang="en-GB" xml:id="id5"/> + <delta title="this-is-att-value" xml:lang="en-US"> + <omega content="this-is-att-value"/> + <theta attrib="this-is-att-value" xml:lang="en" xml:id="id6"> + <rho> + <sigma xml:id="id7"> + <green>This text must be green</green> + </sigma> + </rho> + </theta> + </delta> + </tau> + </epsilon> + </psi> + </kappa> + </phi> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(concat(@class,"-"),"content-")][@xml:lang="nb"][@xml:id="id1"]/*[@src="123456789"][following-sibling::omega[contains(@string,"blank")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@false][not(child::node())][following-sibling::zeta[starts-with(concat(@desciption,"-"),"solid 1px green-")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[starts-with(concat(@token,"-"),"100%-")][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]//pi[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[contains(concat(@object,"$")," attribute value$")][following-sibling::gamma[contains(@attr,"nt")][@xml:id="id6"][not(following-sibling::*)]//beta[@xml:id="id7"][not(following-sibling::*)]/alpha[starts-with(concat(@true,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id8"]/iota[@xml:lang="nb"][not(child::node())][following-sibling::omega[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[@att="attribute value"][@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[starts-with(@insert,"thi")][@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)]/chi[@xml:lang="no-nb"][@xml:id="id12"][not(following-sibling::*)]/psi[starts-with(@object,"an")][@xml:lang="en-US"][not(child::node())][following-sibling::upsilon[@xml:id="id13"][preceding-sibling::*[position() = 1]][following-sibling::pi[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//delta[@xml:lang="en-GB"][@xml:id="id14"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <alpha class="content" xml:lang="nb" xml:id="id1"> + <any src="123456789"/> + <omega string="_blank" xml:lang="no"> + <psi false="this-is-att-value"/> + <zeta desciption="solid 1px green" xml:id="id2"/> + <omega token="100%" xml:lang="en-GB" xml:id="id3"> + <nu xml:lang="no-nb" xml:id="id4"> + <pi xml:lang="no" xml:id="id5"/> + <omega object="another attribute value"/> + <gamma attr="content" xml:id="id6"> + <beta xml:id="id7"> + <alpha true="attribute-value" xml:lang="en-US" xml:id="id8"> + <iota xml:lang="nb"/> + <omega xml:lang="nb" xml:id="id9"> + <omega att="attribute value" xml:lang="en-US" xml:id="id10"> + <delta insert="this.nodeValue" xml:lang="no" xml:id="id11"> + <chi xml:lang="no-nb" xml:id="id12"> + <psi object="another attribute value" xml:lang="en-US"/> + <upsilon xml:id="id13"/> + <pi xml:lang="en"> + <delta xml:lang="en-GB" xml:id="id14"> + <green>This text must be green</green> + </delta> + </pi> + </chi> + </delta> + </omega> + </omega> + </alpha> + </beta> + </gamma> + </nu> + </omega> + </omega> + </alpha> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en"]//gamma[@data][not(preceding-sibling::*)]//pi[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::mu[starts-with(concat(@att,"-"),"attribute value-")][@xml:lang="no"][following-sibling::chi[@attr][@xml:lang="no-nb"]/epsilon[@and="attribute-value"][@xml:lang="en"][following-sibling::upsilon[starts-with(concat(@token,"-"),"123456789-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[contains(@desciption,"%")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::xi[not(child::node())][following-sibling::eta[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::omega[@xml:id="id3"][not(child::node())][following-sibling::phi[@xml:id="id4"][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 6]][following-sibling::mu[@xml:id="id6"][preceding-sibling::*[position() = 7]][following-sibling::omega[contains(@false,"this")][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 8]][following-sibling::*[position()=1]][following-sibling::beta[not(following-sibling::*)]/alpha[@xml:lang="en"][not(preceding-sibling::*)]//rho[@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[contains(@attribute,"bute")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="nb"][@xml:id="id9"][following-sibling::delta[not(child::node())][following-sibling::zeta[@xml:lang="no"][not(following-sibling::*)]/iota[@xml:id="id10"][not(following-sibling::*)]]][position() = 1]]]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en"> + <gamma data="this-is-att-value"> + <pi xml:id="id1"/> + <mu att="attribute value" xml:lang="no"/> + <chi attr="_blank" xml:lang="no-nb"> + <epsilon and="attribute-value" xml:lang="en"/> + <upsilon token="123456789" xml:lang="nb"> + <xi desciption="100%" xml:lang="en" xml:id="id2"/> + <xi/> + <eta xml:lang="en-US"/> + <omega xml:id="id3"/> + <phi xml:id="id4"/> + <psi/> + <pi xml:id="id5"/> + <mu xml:id="id6"/> + <omega false="this-is-att-value" xml:lang="en" xml:id="id7"/> + <beta> + <alpha xml:lang="en"> + <rho xml:id="id8"> + <chi attribute="attribute" xml:lang="en-GB"/> + <tau xml:lang="nb" xml:id="id9"/> + <delta/> + <zeta xml:lang="no"> + <iota xml:id="id10"> + <green>This text must be green</green> + </iota> + </zeta> + </rho> + </alpha> + </beta> + </upsilon> + </chi> + </gamma> + </omega> + </tree> + </test> + <test> + <xpath>//*[contains(concat(@name,"$"),"ue$")][@xml:lang="en-US"]//kappa[starts-with(@desciption,"10")][@xml:id="id1"][following-sibling::omicron[contains(concat(@att,"$"),"er attribute value$")][@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]/rho[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@title="content"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@xml:lang="no"]//alpha[following-sibling::chi[@attr][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::chi[position()=1]][not(child::node())][following-sibling::rho[following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 3]][following-sibling::mu[@insert="attribute-value"][@xml:id="id6"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//lambda[@content="123456789"][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::*[contains(concat(@or,"$"),"nk$")][@xml:lang="en-GB"][@xml:id="id7"]/eta[@xml:lang="en-US"]/zeta[contains(@content,"attribu")][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::tau[starts-with(@false,"this.nodeVa")][@xml:id="id9"][following-sibling::chi[contains(@att," valu")][@xml:id="id10"][following-sibling::*[position()=1]][following-sibling::xi[contains(concat(@false,"$"),"ibute$")][@xml:lang="en-US"][@xml:id="id11"][not(following-sibling::*)]//omega[starts-with(concat(@and,"-"),"100%-")][@xml:lang="nb"][@xml:id="id12"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <any name="true" xml:lang="en-US"> + <kappa desciption="100%" xml:id="id1"/> + <omicron att="another attribute value" xml:lang="no" xml:id="id2"> + <rho xml:id="id3"> + <tau title="content" xml:id="id4"> + <nu xml:lang="no"> + <alpha/> + <chi attr="another attribute value" xml:id="id5"/> + <rho/> + <chi/> + <mu insert="attribute-value" xml:id="id6"> + <lambda content="123456789" xml:lang="no"/> + <any or="_blank" xml:lang="en-GB" xml:id="id7"> + <eta xml:lang="en-US"> + <zeta content="attribute value"> + <rho xml:id="id8"/> + <tau false="this.nodeValue" xml:id="id9"/> + <chi att="attribute value" xml:id="id10"/> + <xi false="attribute" xml:lang="en-US" xml:id="id11"> + <omega and="100%" xml:lang="nb" xml:id="id12"/> + <omicron xml:lang="en-US"> + <green>This text must be green</green> + </omicron> + </xi> + </zeta> + </eta> + </any> + </mu> + </nu> + </tau> + </rho> + </omicron> + </any> + </tree> + </test> + <test> + <xpath>//nu/kappa[@xml:id="id1"]//phi[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[contains(@attribute,"id 1p")][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[starts-with(concat(@and,"-"),"another attribute value-")][@xml:id="id4"][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@desciption][following-sibling::gamma[@false][@xml:id="id6"][following-sibling::xi[@true="this-is-att-value"][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]]/mu[starts-with(concat(@name,"-"),"this-")][@xml:lang="nb"][@xml:id="id8"][not(child::node())][following-sibling::lambda[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//eta[starts-with(@desciption,"so")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::alpha[contains(concat(@content,"$"),"alue$")][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::*[following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[contains(concat(@token,"$"),"ue$")][preceding-sibling::*[position() = 4]][following-sibling::phi[@xml:lang="en-US"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <nu> + <kappa xml:id="id1"> + <phi xml:lang="en-US" xml:id="id2"/> + <xi attribute="solid 1px green" xml:lang="en-GB" xml:id="id3"> + <iota and="another attribute value" xml:id="id4"/> + <omicron xml:lang="en-GB" xml:id="id5"> + <nu desciption="solid 1px green"/> + <gamma false="attribute-value" xml:id="id6"/> + <xi true="this-is-att-value" xml:lang="nb" xml:id="id7"> + <mu name="this-is-att-value" xml:lang="nb" xml:id="id8"/> + <lambda token="attribute" xml:lang="no-nb"> + <eta desciption="solid 1px green" xml:lang="en"> + <phi/> + <psi xml:id="id9"/> + <alpha content="this-is-att-value" xml:lang="en-US" xml:id="id10"/> + <any/> + <kappa token="true"/> + <phi xml:lang="en-US"> + <green>This text must be green</green> + </phi> + </eta> + </lambda> + </xi> + </omicron> + </xi> + </kappa> + </nu> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="no"]//chi[contains(concat(@title,"$"),"lue$")][@xml:id="id1"]/phi[not(child::node())][following-sibling::eta[@xml:id="id2"][preceding-sibling::*[position() = 1]]/kappa[starts-with(concat(@src,"-"),"100%-")][@xml:lang="en"][@xml:id="id3"][following-sibling::psi[contains(concat(@true,"$"),"content$")][@xml:lang="en-US"][@xml:id="id4"]/sigma[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[@abort="this.nodeValue"][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]/psi[@class][@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]/nu[@delete][following-sibling::kappa[@xml:lang="en-GB"]//xi[starts-with(@insert,"attri")][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::tau[starts-with(concat(@class,"-"),"content-")][@xml:id="id7"][not(preceding-sibling::tau)]/nu[@or="false"][@xml:id="id8"]/theta[@xml:lang="no"][@xml:id="id9"][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(concat(@and,"-"),"this-")][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="no"> + <chi title="this.nodeValue" xml:id="id1"> + <phi/> + <eta xml:id="id2"> + <kappa src="100%" xml:lang="en" xml:id="id3"/> + <psi true="content" xml:lang="en-US" xml:id="id4"> + <sigma xml:lang="en"/> + <tau abort="this.nodeValue" xml:lang="en"> + <eta/> + <omicron xml:lang="en-GB"> + <psi class="attribute" xml:lang="en-US" xml:id="id5"> + <nu delete="this.nodeValue"/> + <kappa xml:lang="en-GB"> + <xi insert="attribute-value" xml:lang="en-US" xml:id="id6"/> + <tau class="content" xml:id="id7"> + <nu or="false" xml:id="id8"> + <theta xml:lang="no" xml:id="id9"/> + <upsilon and="this-is-att-value"> + <green>This text must be green</green> + </upsilon> + </nu> + </tau> + </kappa> + </psi> + </omicron> + </tau> + </psi> + </eta> + </chi> + </theta> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@or,"$"),"deValue$")][@xml:lang="en-GB"][@xml:id="id1"]/gamma[not(following-sibling::*)]/pi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@number="false"][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[@src][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::rho[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@object][@xml:id="id6"][not(following-sibling::*)]//tau[not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no-nb"][following-sibling::mu[@attrib="attribute value"][@xml:lang="en"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <phi or="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <gamma> + <pi xml:id="id2"> + <sigma number="false" xml:lang="en-US" xml:id="id3"> + <tau src="false" xml:lang="nb" xml:id="id4"> + <alpha xml:lang="nb"/> + <rho xml:id="id5"/> + <psi object="this.nodeValue" xml:id="id6"> + <tau/> + <iota xml:lang="no-nb"/> + <mu attrib="attribute value" xml:lang="en"> + <green>This text must be green</green> + </mu> + </psi> + </tau> + </sigma> + </pi> + </gamma> + </phi> + </tree> + </test> + <test> + <xpath>//rho/theta[starts-with(@name,"cont")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@content="attribute-value"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[starts-with(concat(@number,"-"),"_blank-")][@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@xml:lang="no-nb"][not(following-sibling::*)]//omicron[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::nu[contains(concat(@att,"$"),"100%$")][@xml:lang="en"][not(following-sibling::*)]/sigma[contains(@attribute,"e")][@xml:lang="en-GB"][not(preceding-sibling::*)]//sigma[contains(@object,"s")]/omega[@xml:lang="nb"][@xml:id="id3"]//omega[@token][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::upsilon[contains(@class,"s-att-value")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[starts-with(@abort,"attri")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::theta[following-sibling::nu[@insert="attribute-value"]//rho[starts-with(concat(@content,"-"),"true-")][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[following-sibling::omicron[@class][@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 2]]/chi[starts-with(concat(@false,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:lang="no-nb"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@abort][@xml:lang="en-GB"][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <theta name="content" xml:lang="en-GB"/> + <phi content="attribute-value"> + <eta number="_blank" xml:lang="no" xml:id="id1"> + <chi xml:id="id2"> + <sigma xml:lang="no-nb"> + <omicron xml:lang="en-US"/> + <nu att="100%" xml:lang="en"> + <sigma attribute="attribute" xml:lang="en-GB"> + <sigma object="false"> + <omega xml:lang="nb" xml:id="id3"> + <omega token="attribute-value" xml:lang="nb" xml:id="id4"> + <mu xml:lang="en"/> + <upsilon class="this-is-att-value" xml:lang="en-US" xml:id="id5"> + <rho abort="attribute value" xml:lang="nb" xml:id="id6"/> + <theta/> + <nu insert="attribute-value"> + <rho content="true" xml:lang="en" xml:id="id7"/> + <upsilon/> + <omicron class="this.nodeValue" xml:lang="en" xml:id="id8"> + <chi false="attribute-value"> + <lambda xml:lang="no-nb" xml:id="id9"/> + <chi abort="attribute value" xml:lang="en-GB"> + <green>This text must be green</green> + </chi> + </chi> + </omicron> + </nu> + </upsilon> + </omega> + </omega> + </sigma> + </sigma> + </nu> + </sigma> + </chi> + </eta> + </phi> + </rho> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@insert,"-"),"attribute value-")][@xml:lang="no"]//zeta[not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::pi[starts-with(@string,"fal")][@xml:id="id2"][preceding-sibling::*[position() = 2]]/sigma[contains(@class,"ank")][following-sibling::*[position()=5]][not(child::node())][following-sibling::xi[@att="_blank"][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::tau[@false][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::chi[contains(@and,"bute-value")][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::gamma[preceding-sibling::*[position() = 4]][following-sibling::iota[@xml:id="id5"][not(following-sibling::*)]//eta[@insert="_blank"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@title,"-"),"true-")][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::phi[@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::eta[starts-with(concat(@att,"-"),"_blank-")][@xml:lang="en-US"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::alpha//omicron[not(preceding-sibling::*)]//omega[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@title="_blank"][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@name][@xml:lang="no"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <mu insert="attribute value" xml:lang="no"> + <zeta/> + <theta xml:lang="en" xml:id="id1"/> + <pi string="false" xml:id="id2"> + <sigma class="_blank"/> + <xi att="_blank" xml:lang="en-GB" xml:id="id3"/> + <tau false="this-is-att-value"/> + <chi and="attribute-value" xml:id="id4"/> + <gamma/> + <iota xml:id="id5"> + <eta insert="_blank" xml:lang="no-nb"/> + <nu title="true" xml:id="id6"/> + <phi xml:id="id7"/> + <gamma/> + <eta att="_blank" xml:lang="en-US"/> + <alpha> + <omicron> + <omega xml:lang="no-nb" xml:id="id8"/> + <gamma title="_blank" xml:lang="no"> + <phi name="attribute-value" xml:lang="no"> + <green>This text must be green</green> + </phi> + </gamma> + </omicron> + </alpha> + </iota> + </pi> + </mu> + </tree> + </test> + <test> + <xpath>//upsilon[@attrib="123456789"][@xml:lang="no"]//alpha[@xml:lang="en"][following-sibling::delta[@attrib][@xml:lang="no-nb"][not(child::node())][following-sibling::lambda[starts-with(@attrib,"1")][@xml:lang="nb"][not(child::node())][following-sibling::eta[starts-with(@content,"attr")][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 3]]/mu[@xml:id="id2"]/pi[@and][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@xml:lang="no"]/chi[@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[starts-with(@false,"false")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(@abort,"10")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <upsilon attrib="123456789" xml:lang="no"> + <alpha xml:lang="en"/> + <delta attrib="false" xml:lang="no-nb"/> + <lambda attrib="100%" xml:lang="nb"/> + <eta content="attribute-value" xml:lang="no-nb" xml:id="id1"> + <mu xml:id="id2"> + <pi and="content" xml:id="id3"> + <nu xml:lang="no"> + <chi xml:id="id4"/> + <zeta xml:lang="en-US"> + <xi false="false" xml:lang="no-nb"> + <zeta abort="100%"/> + <epsilon> + <green>This text must be green</green> + </epsilon> + </xi> + </zeta> + </nu> + </pi> + </mu> + </eta> + </upsilon> + </tree> + </test> + <test> + <xpath>//sigma[@token][@xml:id="id1"]//rho[@xml:id="id2"][not(preceding-sibling::*)]//theta[starts-with(concat(@number,"-"),"false-")][not(child::node())][following-sibling::alpha[@number="attribute-value"][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//psi[@title][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)]//delta[starts-with(@insert,"fal")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::theta[@xml:lang="en-GB"][following-sibling::*[position()=4]][not(child::node())][following-sibling::rho[starts-with(concat(@number,"-"),"another attribute value-")][not(child::node())][following-sibling::psi[@delete="false"][@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::psi[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::pi[@attrib]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <sigma token="another attribute value" xml:id="id1"> + <rho xml:id="id2"> + <theta number="false"/> + <alpha number="attribute-value" xml:lang="en" xml:id="id3"> + <psi title="true" xml:lang="en-GB" xml:id="id4"> + <delta insert="false" xml:lang="en-US"/> + <theta xml:lang="en-GB"/> + <rho number="another attribute value"/> + <psi delete="false" xml:lang="no" xml:id="id5"/> + <psi xml:lang="en-US" xml:id="id6"/> + <pi attrib="this.nodeValue"> + <green>This text must be green</green> + </pi> + </psi> + </alpha> + </rho> + </sigma> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="nb"]/chi[contains(concat(@true,"$"),"e$")][@xml:id="id1"]/xi[starts-with(@content,"1")][@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@xml:lang="en-GB"][not(child::node())][following-sibling::omicron[@xml:lang="no-nb"][@xml:id="id3"]/pi[@src][@xml:lang="nb"]/phi[not(preceding-sibling::*)][following-sibling::eta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[@content][@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]//theta[@abort][@xml:id="id5"][following-sibling::psi[@att][@xml:lang="nb"][@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:id="id7"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="nb"> + <chi true="false" xml:id="id1"> + <xi content="100%" xml:lang="en" xml:id="id2"/> + <xi xml:lang="nb"> + <beta xml:lang="en-GB"/> + <omicron xml:lang="no-nb" xml:id="id3"> + <pi src="_blank" xml:lang="nb"> + <phi/> + <eta> + <sigma content="true" xml:lang="en" xml:id="id4"> + <theta abort="100%" xml:id="id5"/> + <psi att="solid 1px green" xml:lang="nb" xml:id="id6"/> + <omega xml:id="id7"> + <green>This text must be green</green> + </omega> + </sigma> + </eta> + </pi> + </omicron> + </xi> + </chi> + </omega> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="en-GB"]//alpha//phi[@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]/upsilon[@attribute][@xml:lang="no"][not(following-sibling::*)][not(following-sibling::upsilon)]//chi[following-sibling::*[position()=2]][following-sibling::upsilon[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@title="solid 1px green"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/omicron[starts-with(@or,"fa")][not(child::node())][following-sibling::lambda[contains(concat(@token,"$"),"green$")][@xml:id="id3"][not(following-sibling::*)]/gamma[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::omega[starts-with(@attrib,"a")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id6"][following-sibling::kappa[following-sibling::phi[contains(concat(@attribute,"$"),"k$")][@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::iota[starts-with(concat(@delete,"-"),"100%-")][@xml:id="id8"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::*[@xml:lang="no-nb"][not(following-sibling::*)]//alpha[contains(concat(@number,"$"),"ibute-value$")]//omega[contains(@desciption,"0%")][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id9"][not(following-sibling::*)]//xi[@xml:lang="en"][not(preceding-sibling::*)]/beta[@xml:lang="en-GB"][not(preceding-sibling::*)]/upsilon[@xml:id="id10"][not(following-sibling::*)]]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="en-GB"> + <alpha> + <phi xml:lang="no" xml:id="id1"> + <upsilon attribute="attribute-value" xml:lang="no"> + <chi/> + <upsilon/> + <nu title="solid 1px green" xml:id="id2"> + <omicron or="false"/> + <lambda token="solid 1px green" xml:id="id3"> + <gamma xml:lang="no" xml:id="id4"/> + <omega attrib="attribute" xml:lang="no"> + <omicron xml:id="id5"/> + <epsilon xml:id="id6"/> + <kappa/> + <phi attribute="_blank" xml:lang="no-nb" xml:id="id7"/> + <iota delete="100%" xml:id="id8"/> + <any xml:lang="no-nb"> + <alpha number="attribute-value"> + <omega desciption="100%"/> + <eta xml:id="id9"> + <xi xml:lang="en"> + <beta xml:lang="en-GB"> + <upsilon xml:id="id10"> + <green>This text must be green</green> + </upsilon> + </beta> + </xi> + </eta> + </alpha> + </any> + </omega> + </lambda> + </nu> + </upsilon> + </phi> + </alpha> + </eta> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@attribute,"$"),"ue$")]//chi[contains(concat(@object,"$"),"blank$")][@xml:id="id1"][not(preceding-sibling::*)]//delta[@xml:id="id2"]/iota[@title="123456789"][@xml:id="id3"]/beta[@xml:id="id4"][not(child::node())][following-sibling::rho[contains(@string,"sol")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::mu[@true][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[contains(concat(@and,"$"),"ibute-value$")]/rho[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::tau[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="no"][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <iota attribute="true"> + <chi object="_blank" xml:id="id1"> + <delta xml:id="id2"> + <iota title="123456789" xml:id="id3"> + <beta xml:id="id4"/> + <rho string="solid 1px green" xml:lang="en-US"/> + <mu true="this-is-att-value" xml:lang="no"/> + <zeta and="attribute-value"> + <rho/> + <tau xml:lang="en" xml:id="id5"/> + <nu xml:lang="no"> + <green>This text must be green</green> + </nu> + </zeta> + </iota> + </delta> + </chi> + </iota> + </tree> + </test> + <test> + <xpath>//omega[@name="false"][@xml:lang="no"][@xml:id="id1"]/lambda[@xml:id="id2"][not(preceding-sibling::lambda or following-sibling::lambda)]/xi[following-sibling::*[position()=1]][following-sibling::mu[@attr][@xml:lang="en-GB"][@xml:id="id3"]//sigma[contains(@number,"n")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[starts-with(concat(@src,"-"),"solid 1px green-")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="en-US"][not(preceding-sibling::*)]//omicron[@xml:lang="nb"][not(following-sibling::*)]//pi[contains(@false,"green")][@xml:lang="en-GB"][@xml:id="id6"]//*[starts-with(@or,"c")][not(preceding-sibling::*)][following-sibling::pi[@xml:lang="no"][preceding-sibling::*[position() = 1]]//lambda[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@attr="this.nodeValue"][@xml:lang="en-GB"]//xi[not(preceding-sibling::*)]//alpha[starts-with(concat(@class,"-"),"123456789-")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[not(following-sibling::*)]//beta[@xml:lang="en-US"][not(preceding-sibling::beta)]/nu[@xml:lang="en-US"][not(child::node())][following-sibling::nu[@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:id="id9"]//zeta[@xml:lang="no-nb"][not(parent::*/*[position()=2])]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <omega name="false" xml:lang="no" xml:id="id1"> + <lambda xml:id="id2"> + <xi/> + <mu attr="this.nodeValue" xml:lang="en-GB" xml:id="id3"> + <sigma number="solid 1px green" xml:lang="en" xml:id="id4"/> + <omega xml:lang="en-GB"> + <xi src="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <iota xml:lang="en-US"> + <omicron xml:lang="nb"> + <pi false="solid 1px green" xml:lang="en-GB" xml:id="id6"> + <any or="content"/> + <pi xml:lang="no"> + <lambda xml:lang="en" xml:id="id7"/> + <rho attr="this.nodeValue" xml:lang="en-GB"> + <xi> + <alpha class="123456789" xml:lang="nb"> + <kappa> + <beta xml:lang="en-US"> + <nu xml:lang="en-US"/> + <nu xml:id="id8"/> + <xi xml:id="id9"> + <zeta xml:lang="no-nb"> + <green>This text must be green</green> + </zeta> + </xi> + </beta> + </kappa> + </alpha> + </xi> + </rho> + </pi> + </pi> + </omicron> + </iota> + </xi> + </omega> + </mu> + </lambda> + </omega> + </tree> + </test> + <test> + <xpath>//phi[starts-with(concat(@class,"-"),"true-")][@xml:id="id1"]//beta[@xml:lang="no-nb"][@xml:id="id2"][not(child::node())][following-sibling::theta[@delete][following-sibling::rho[@title][@xml:id="id3"][not(following-sibling::*)]//iota[starts-with(concat(@title,"-"),"_blank-")][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(concat(@data,"$"),"s-is-att-value$")][@xml:lang="no"][preceding-sibling::*[position() = 1]]//epsilon[contains(concat(@content,"$"),"lue$")][@xml:lang="en-GB"][@xml:id="id4"]//delta[starts-with(@desciption,"_blan")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::lambda[@and][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[starts-with(concat(@data,"-"),"attribute-")][following-sibling::rho[contains(concat(@true,"$"),"ute value$")][@xml:id="id7"][following-sibling::psi[@desciption][@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]/tau[@attrib][@xml:lang="en-US"][not(child::node())][following-sibling::omicron[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[@xml:id="id9"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 3]][following-sibling::nu[preceding-sibling::*[position() = 4]][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <phi class="true" xml:id="id1"> + <beta xml:lang="no-nb" xml:id="id2"/> + <theta delete="solid 1px green"/> + <rho title="100%" xml:id="id3"> + <iota title="_blank"/> + <eta data="this-is-att-value" xml:lang="no"> + <epsilon content="attribute value" xml:lang="en-GB" xml:id="id4"> + <delta desciption="_blank" xml:id="id5"/> + <lambda and="100%" xml:id="id6"/> + <mu data="attribute-value"/> + <rho true="attribute value" xml:id="id7"/> + <psi desciption="_blank" xml:lang="en-GB" xml:id="id8"> + <tau attrib="false" xml:lang="en-US"/> + <omicron xml:lang="nb"/> + <lambda xml:id="id9"/> + <theta/> + <nu> + <green>This text must be green</green> + </nu> + </psi> + </epsilon> + </eta> + </rho> + </phi> + </tree> + </test> + <test> + <xpath>//nu[contains(concat(@or,"$"),"89$")]/iota[@desciption][@xml:lang="no"][@xml:id="id1"][not(child::node())][following-sibling::delta[contains(@attrib,"Value")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="en-US"]/gamma[not(preceding-sibling::*)][not(following-sibling::*)]//xi[@and][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::rho[contains(@attr,"%")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[contains(@class," val")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@delete][@xml:id="id3"][preceding-sibling::*[position() = 1]]//epsilon[contains(@true,"ue")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::tau[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="no-nb"][not(following-sibling::*)]//psi[starts-with(concat(@string,"-"),"another attribute value-")][@xml:lang="no"][not(preceding-sibling::*)]/pi[@att][@xml:lang="en-US"][not(preceding-sibling::*)]/chi[starts-with(concat(@object,"-"),"false-")][not(preceding-sibling::*)][following-sibling::omicron[@false="100%"][@xml:lang="no"][@xml:id="id6"][following-sibling::xi[@xml:id="id7"][following-sibling::lambda[not(following-sibling::*)]//*[not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:lang="en-US"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <nu or="123456789"> + <iota desciption="solid 1px green" xml:lang="no" xml:id="id1"/> + <delta attrib="this.nodeValue" xml:lang="en-US"/> + <chi xml:lang="en"/> + <theta xml:lang="en-US"> + <gamma> + <xi and="_blank" xml:lang="no"/> + <rho attr="100%" xml:lang="no"> + <eta class="attribute value" xml:id="id2"/> + <psi delete="another attribute value" xml:id="id3"> + <epsilon true="true" xml:lang="no"/> + <alpha xml:id="id4"/> + <tau xml:id="id5"/> + <gamma xml:lang="no-nb"> + <psi string="another attribute value" xml:lang="no"> + <pi att="false" xml:lang="en-US"> + <chi object="false"/> + <omicron false="100%" xml:lang="no" xml:id="id6"/> + <xi xml:id="id7"/> + <lambda> + <any/> + <chi xml:lang="en-US"> + <green>This text must be green</green> + </chi> + </lambda> + </pi> + </psi> + </gamma> + </psi> + </rho> + </gamma> + </theta> + </nu> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no"]/psi[@attr][@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::eta[@delete][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::xi[@object][not(following-sibling::*)]/pi[@att][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[@abort][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no"> + <psi attr="attribute" xml:id="id1"/> + <eta delete="attribute"/> + <xi object="content"> + <pi att="solid 1px green" xml:id="id2"/> + <xi abort="this.nodeValue" xml:id="id3"> + <green>This text must be green</green> + </xi> + </xi> + </iota> + </tree> + </test> + <test> + <xpath>//upsilon//alpha[@content][@xml:id="id1"]//epsilon[contains(@attribute,"tent")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[@false="attribute value"][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::kappa[@attribute][@xml:lang="no"][not(following-sibling::*)]/xi[starts-with(concat(@true,"-"),"content-")][@xml:lang="no-nb"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:lang="en"][preceding-sibling::*[position() = 1]]//xi[@xml:id="id3"][not(following-sibling::*)]//lambda[starts-with(@attr,"another attribute valu")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]//gamma[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)]/rho[starts-with(concat(@src,"-"),"_blank-")][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id6"]//omicron[@xml:lang="en-US"]/nu[@attribute][@xml:id="id7"][not(following-sibling::*)]//epsilon[contains(@src,"value")][@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::sigma[@desciption="123456789"][not(child::node())][following-sibling::chi[starts-with(@attribute,"attribute-value")][@xml:lang="en-US"]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <upsilon> + <alpha content="solid 1px green" xml:id="id1"> + <epsilon attribute="content" xml:lang="en-GB"> + <omega false="attribute value" xml:lang="en"/> + <kappa attribute="100%" xml:lang="no"> + <xi true="content" xml:lang="no-nb" xml:id="id2"/> + <epsilon xml:lang="en"> + <xi xml:id="id3"> + <lambda attr="another attribute value" xml:lang="en-US" xml:id="id4"> + <gamma xml:lang="no-nb" xml:id="id5"> + <rho src="_blank"/> + <alpha xml:id="id6"> + <omicron xml:lang="en-US"> + <nu attribute="attribute-value" xml:id="id7"> + <epsilon src="attribute-value" xml:lang="en-GB" xml:id="id8"/> + <sigma desciption="123456789"/> + <chi attribute="attribute-value" xml:lang="en-US"> + <green>This text must be green</green> + </chi> + </nu> + </omicron> + </alpha> + </gamma> + </lambda> + </xi> + </epsilon> + </kappa> + </epsilon> + </alpha> + </upsilon> + </tree> + </test> + <test> + <xpath>//beta[starts-with(@attrib,"f")][@xml:lang="no-nb"]//alpha[@data][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[starts-with(concat(@string,"-"),"solid 1px green-")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[starts-with(concat(@or,"-"),"attribute value-")][@xml:id="id2"]/theta[@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="nb"][@xml:id="id4"]/pi[@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]/alpha[starts-with(@string,"_")][@xml:lang="nb"][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[contains(@object,"lank")][not(following-sibling::*)]//zeta[contains(concat(@attribute,"$"),"ue$")][@xml:id="id8"][not(preceding-sibling::*)]/rho[starts-with(concat(@false,"-"),"content-")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="nb"][@xml:id="id9"]//mu[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@class][@xml:lang="no"]//omega[@xml:lang="nb"][not(child::node())][following-sibling::pi[@xml:id="id10"][not(child::node())][following-sibling::beta[starts-with(concat(@and,"-"),"100%-")][@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="en"][preceding-sibling::*[position() = 3]]/chi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::psi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@string="123456789"][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <beta attrib="false" xml:lang="no-nb"> + <alpha data="false" xml:id="id1"> + <omega string="solid 1px green" xml:lang="en"/> + <upsilon or="attribute value" xml:id="id2"> + <theta xml:lang="en-US" xml:id="id3"/> + <chi xml:lang="nb" xml:id="id4"> + <pi xml:lang="en" xml:id="id5"> + <alpha string="_blank" xml:lang="nb" xml:id="id6"/> + <pi xml:lang="en" xml:id="id7"/> + <omega object="_blank"> + <zeta attribute="true" xml:id="id8"> + <rho false="content" xml:lang="en-US"> + <mu xml:lang="nb" xml:id="id9"> + <mu xml:lang="en"/> + <beta class="_blank" xml:lang="no"> + <omega xml:lang="nb"/> + <pi xml:id="id10"/> + <beta and="100%" xml:lang="nb" xml:id="id11"/> + <omega xml:lang="en"> + <chi xml:lang="en"/> + <psi xml:lang="en-US"/> + <zeta string="123456789"> + <green>This text must be green</green> + </zeta> + </omega> + </beta> + </mu> + </rho> + </zeta> + </omega> + </pi> + </chi> + </upsilon> + </alpha> + </beta> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(concat(@false,"-"),"100%-")]/kappa[@xml:id="id1"][following-sibling::mu[@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/alpha[not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::alpha or following-sibling::alpha)]/*[@xml:lang="en"][following-sibling::omega[starts-with(concat(@att,"-"),"100%-")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@attrib="attribute-value"][@xml:id="id3"][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::psi[starts-with(@att,"soli")][@xml:id="id4"][preceding-sibling::*[position() = 2]]/xi[@xml:id="id5"]//*[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]]//tau[contains(@title,"is.nodeValue")][@xml:lang="en-GB"][not(preceding-sibling::*)]/pi[@xml:lang="no"][following-sibling::tau[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@xml:lang="no"]//alpha[not(following-sibling::*)]//epsilon[contains(@number,"e")]//tau[starts-with(concat(@token,"-"),"this-")][@xml:id="id9"][not(preceding-sibling::*)]/kappa[starts-with(concat(@name,"-"),"100%-")][not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <epsilon false="100%"> + <kappa xml:id="id1"/> + <mu xml:id="id2"/> + <zeta/> + <alpha> + <alpha> + <any xml:lang="en"/> + <omega att="100%" xml:lang="no"> + <any attrib="attribute-value" xml:id="id3"/> + <iota xml:lang="no-nb"/> + <psi att="solid 1px green" xml:id="id4"> + <xi xml:id="id5"> + <any xml:id="id6"/> + <sigma/> + <pi xml:lang="no-nb" xml:id="id7"> + <tau title="this.nodeValue" xml:lang="en-GB"> + <pi xml:lang="no"/> + <tau xml:lang="nb" xml:id="id8"/> + <upsilon xml:lang="no"> + <alpha> + <epsilon number="false"> + <tau token="this-is-att-value" xml:id="id9"> + <kappa name="100%"> + <green>This text must be green</green> + </kappa> + </tau> + </epsilon> + </alpha> + </upsilon> + </tau> + </pi> + </xi> + </psi> + </omega> + </alpha> + </alpha> + </epsilon> + </tree> + </test> + <test> + <xpath>//kappa[contains(@object,"ttrib")]//tau[@abort][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[contains(concat(@content,"$"),"een$")][following-sibling::mu[@object][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[@xml:lang="en-US"]//psi[starts-with(@content,"123456")][@xml:id="id2"][not(preceding-sibling::*)]/omicron[@string][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]/chi[@content="_blank"][@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::gamma[@or="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(following-sibling::gamma)][not(child::node())][following-sibling::mu[@name][@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::eta[@xml:id="id7"][not(following-sibling::*)]/phi][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>1</nth> + </result> + <tree> + <kappa object="attribute"> + <tau abort="123456789" xml:id="id1"> + <tau content="solid 1px green"/> + <mu object="attribute value"/> + <psi/> + <iota xml:lang="en-US"> + <psi content="123456789" xml:id="id2"> + <omicron string="false" xml:lang="en-US" xml:id="id3"> + <chi content="_blank" xml:lang="nb" xml:id="id4"/> + <gamma or="this.nodeValue" xml:lang="en-GB" xml:id="id5"/> + <mu name="true" xml:lang="en-US" xml:id="id6"/> + <eta xml:id="id7"> + <phi> + <green>This text must be green</green> + </phi> + </eta> + </omicron> + </psi> + </iota> + </tau> + </kappa> + </tree> + </test> + <test> + <xpath>//beta[@attr="this.nodeValue"][@xml:lang="no-nb"]/theta[starts-with(@title,"100")]/omicron[@abort="true"][@xml:lang="en-GB"][not(child::node())][following-sibling::phi[@xml:id="id1"]/chi[contains(@attr,"u")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//sigma[@string="this-is-att-value"][not(following-sibling::*)]//epsilon[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@name="content"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[starts-with(@string,"attribute")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)]//chi[@xml:lang="en-GB"][@xml:id="id7"][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <beta attr="this.nodeValue" xml:lang="no-nb"> + <theta title="100%"> + <omicron abort="true" xml:lang="en-GB"/> + <phi xml:id="id1"> + <chi attr="true" xml:lang="en-GB" xml:id="id2"/> + <nu xml:lang="no" xml:id="id3"> + <sigma string="this-is-att-value"> + <epsilon xml:id="id4"> + <epsilon name="content" xml:id="id5"> + <alpha string="attribute value" xml:lang="no-nb" xml:id="id6"> + <chi xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </chi> + </alpha> + </epsilon> + </epsilon> + </sigma> + </nu> + </phi> + </theta> + </beta> + </tree> + </test> + <test> + <xpath>//omicron/zeta[@xml:lang="en-US"][not(preceding-sibling::*)]/*[not(preceding-sibling::*)][not(following-sibling::*)]/mu[starts-with(concat(@false,"-"),"false-")][@xml:lang="nb"][not(following-sibling::*)]/beta[contains(concat(@and,"$"),"100%$")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@desciption][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[contains(@token,"nten")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::pi[contains(@token,"olid 1px ")][@xml:id="id3"][following-sibling::alpha[@name="this-is-att-value"][not(following-sibling::*)]//psi[@xml:lang="nb"][@xml:id="id4"]//epsilon[not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="no"][following-sibling::epsilon[@xml:lang="en"][@xml:id="id5"][following-sibling::epsilon[@object][@xml:lang="no-nb"][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omicron> + <zeta xml:lang="en-US"> + <any> + <mu false="false" xml:lang="nb"> + <beta and="100%" xml:lang="en-US" xml:id="id1"/> + <pi desciption="this-is-att-value" xml:lang="en" xml:id="id2"> + <rho xml:lang="nb"> + <kappa token="content" xml:lang="nb"/> + <pi token="solid 1px green" xml:id="id3"/> + <alpha name="this-is-att-value"> + <psi xml:lang="nb" xml:id="id4"> + <epsilon/> + <nu xml:lang="no"/> + <epsilon xml:lang="en" xml:id="id5"/> + <epsilon object="another attribute value" xml:lang="no-nb"/> + <omicron xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </psi> + </alpha> + </rho> + </pi> + </mu> + </any> + </zeta> + </omicron> + </tree> + </test> + <test> + <xpath>//psi[@number][@xml:lang="en"]/xi[contains(@name,"id ")]/omega[starts-with(concat(@insert,"-"),"123456789-")][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@src][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::gamma[@xml:lang="no"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][following-sibling::mu[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::sigma[@attrib="_blank"][@xml:id="id3"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <psi number="solid 1px green" xml:lang="en"> + <xi name="solid 1px green"> + <omega insert="123456789"/> + <psi xml:id="id1"/> + <delta src="123456789"/> + <gamma xml:lang="no"/> + <mu xml:lang="en-US" xml:id="id2"/> + <sigma attrib="_blank" xml:id="id3"> + <green>This text must be green</green> + </sigma> + </xi> + </psi> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]//beta[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//lambda[not(preceding-sibling::*)][not(following-sibling::*)]/omicron[contains(concat(@desciption,"$"),"e$")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//xi[@xml:lang="en-GB"]/nu[contains(concat(@abort,"$"),"e$")][@xml:id="id4"][not(following-sibling::*)]/nu[starts-with(@string,"this.n")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][following-sibling::omicron[preceding-sibling::*[position() = 2]]/gamma[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@class][@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]//xi[@xml:id="id9"][not(preceding-sibling::*)]//omega[@name="_blank"][@xml:lang="no-nb"][@xml:id="id10"][not(following-sibling::*)]//pi[starts-with(@and,"solid 1px g")][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>1</nth> + </result> + <tree> + <mu xml:id="id1"> + <beta xml:lang="en-US" xml:id="id2"> + <lambda> + <omicron desciption="this.nodeValue" xml:lang="no-nb" xml:id="id3"> + <xi xml:lang="en-GB"> + <nu abort="false" xml:id="id4"> + <nu string="this.nodeValue"/> + <omicron xml:lang="en-US"/> + <omicron> + <gamma xml:lang="nb" xml:id="id5"> + <mu class="attribute" xml:lang="en-US" xml:id="id6"/> + <any xml:lang="no" xml:id="id7"/> + <eta xml:lang="en-GB" xml:id="id8"> + <xi xml:id="id9"> + <omega name="_blank" xml:lang="no-nb" xml:id="id10"> + <pi and="solid 1px green"> + <green>This text must be green</green> + </pi> + </omega> + </xi> + </eta> + </gamma> + </omicron> + </nu> + </xi> + </omicron> + </lambda> + </beta> + </mu> + </tree> + </test> + <test> + <xpath>//rho[contains(concat(@desciption,"$"),"tribute value$")][@xml:lang="nb"]/alpha[contains(concat(@string,"$"),"e$")][@xml:lang="nb"][@xml:id="id1"][following-sibling::lambda[@name][@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::eta[@insert][@xml:id="id3"]/theta[@xml:id="id4"]//chi[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::eta[@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:lang="nb"][not(following-sibling::*)]//zeta[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:id="id8"][not(following-sibling::*)]//psi[@xml:lang="nb"][@xml:id="id9"][following-sibling::omega[@false="attribute"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(@data,"e")][@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::phi[@number="another attribute value"][@xml:lang="en-US"][@xml:id="id10"][following-sibling::beta[@token][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::chi[@false][@xml:id="id11"][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <rho desciption="attribute value" xml:lang="nb"> + <alpha string="attribute-value" xml:lang="nb" xml:id="id1"/> + <lambda name="100%" xml:lang="nb" xml:id="id2"/> + <eta insert="_blank" xml:id="id3"> + <theta xml:id="id4"> + <chi xml:lang="no-nb" xml:id="id5"/> + <eta xml:id="id6"/> + <mu xml:lang="nb"> + <zeta xml:id="id7"> + <lambda xml:id="id8"> + <psi xml:lang="nb" xml:id="id9"/> + <omega false="attribute"/> + <delta data="attribute-value" xml:lang="no"/> + <phi number="another attribute value" xml:lang="en-US" xml:id="id10"/> + <beta token="attribute"/> + <chi false="attribute-value" xml:id="id11"> + <green>This text must be green</green> + </chi> + </lambda> + </zeta> + </mu> + </theta> + </eta> + </rho> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="en-GB"]/lambda[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::iota[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[@attr][@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]//eta[starts-with(concat(@desciption,"-"),"this-")][@xml:lang="no"][not(child::node())][following-sibling::*[@or="another attribute value"][not(child::node())][following-sibling::beta[contains(concat(@object,"$"),"other attribute value$")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[starts-with(@string,"thi")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::omicron[@attr][not(following-sibling::*)]/theta[@att][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[@xml:lang="nb"][not(following-sibling::*)]//beta[not(preceding-sibling::*)]/nu[@or][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[starts-with(@delete,"conten")][not(preceding-sibling::iota)][not(child::node())][following-sibling::lambda[contains(concat(@attrib,"$"),"9$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[@xml:id="id7"][not(preceding-sibling::*)]/lambda[starts-with(@attrib,"conten")]/zeta[@xml:lang="en"]//lambda[starts-with(@content,"at")][@xml:lang="en-US"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="en-GB"> + <lambda xml:lang="en" xml:id="id1"/> + <iota xml:id="id2"> + <rho attr="_blank" xml:lang="en-US" xml:id="id3"> + <eta desciption="this-is-att-value" xml:lang="no"/> + <any or="another attribute value"/> + <beta object="another attribute value" xml:lang="nb" xml:id="id4"/> + <omega string="this.nodeValue" xml:lang="nb"/> + <omicron attr="100%"> + <theta att="false" xml:lang="en"/> + <chi xml:lang="nb"> + <beta> + <nu or="this-is-att-value" xml:lang="no" xml:id="id5"> + <iota delete="content"/> + <lambda attrib="123456789" xml:lang="en"/> + <omicron xml:id="id6"> + <phi xml:id="id7"> + <lambda attrib="content"> + <zeta xml:lang="en"> + <lambda content="attribute" xml:lang="en-US"> + <green>This text must be green</green> + </lambda> + </zeta> + </lambda> + </phi> + </omicron> + </nu> + </beta> + </chi> + </omicron> + </rho> + </iota> + </alpha> + </tree> + </test> + <test> + <xpath>//omicron/chi[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@src][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::beta[starts-with(concat(@false,"-"),"this-")][preceding-sibling::*[position() = 2]]/phi[@string][@xml:id="id3"]//beta[contains(concat(@name,"$"),"r attribute value$")][@xml:lang="no-nb"][not(preceding-sibling::*)]//gamma[@att][following-sibling::beta[not(following-sibling::*)]//*[@number][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[contains(@class,"r")]/rho[@xml:id="id4"][not(child::node())][following-sibling::sigma[@insert][@xml:id="id5"][preceding-sibling::*[position() = 1]]/gamma[@xml:lang="nb"][@xml:id="id6"][not(child::node())][following-sibling::iota[@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[starts-with(@name,"100%")][not(following-sibling::*)]//epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)]/theta[@xml:lang="nb"][not(child::node())][following-sibling::zeta[contains(@false,"bu")][@xml:id="id8"][not(following-sibling::*)]/nu[following-sibling::epsilon[starts-with(@attribute,"tr")]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <omicron> + <chi xml:id="id1"/> + <tau src="_blank" xml:id="id2"/> + <beta false="this-is-att-value"> + <phi string="_blank" xml:id="id3"> + <beta name="another attribute value" xml:lang="no-nb"> + <gamma att="true"/> + <beta> + <any number="true"/> + <xi class="true"> + <rho xml:id="id4"/> + <sigma insert="attribute-value" xml:id="id5"> + <gamma xml:lang="nb" xml:id="id6"/> + <iota xml:lang="en" xml:id="id7"/> + <psi name="100%"> + <epsilon xml:lang="no-nb"> + <theta xml:lang="nb"/> + <zeta false="attribute-value" xml:id="id8"> + <nu/> + <epsilon attribute="true"> + <green>This text must be green</green> + </epsilon> + </zeta> + </epsilon> + </psi> + </sigma> + </xi> + </beta> + </beta> + </phi> + </beta> + </omicron> + </tree> + </test> + <test> + <xpath>//beta[@xml:id="id1"]/upsilon[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[@xml:id="id3"][following-sibling::chi[not(following-sibling::*)]/sigma[starts-with(@content,"12345678")][@xml:lang="en-GB"][@xml:id="id4"][following-sibling::lambda[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id6"][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]]/eta[following-sibling::omicron[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::eta[@insert="solid 1px green"][@xml:lang="no"][@xml:id="id7"][following-sibling::theta[@xml:id="id8"][preceding-sibling::*[position() = 4]]//zeta[@delete][not(preceding-sibling::*)][following-sibling::alpha[contains(@data,"ue")][not(child::node())][following-sibling::alpha[@xml:lang="no-nb"][not(following-sibling::*)]/kappa[@attr][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(@token,"attr")][following-sibling::xi[@insert][@xml:lang="nb"][@xml:id="id9"][following-sibling::phi//alpha[starts-with(concat(@token,"-"),"content-")][@xml:lang="no"][@xml:id="id10"][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id11"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]]]]][position() = 1]][position() = 1]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:id="id1"> + <upsilon xml:lang="no" xml:id="id2"/> + <delta xml:id="id3"/> + <chi> + <sigma content="123456789" xml:lang="en-GB" xml:id="id4"/> + <lambda xml:lang="no-nb" xml:id="id5"/> + <delta xml:lang="en-GB" xml:id="id6"/> + <omega xml:lang="en-GB"> + <eta/> + <omicron xml:lang="nb"/> + <upsilon/> + <eta insert="solid 1px green" xml:lang="no" xml:id="id7"/> + <theta xml:id="id8"> + <zeta delete="this.nodeValue"/> + <alpha data="true"/> + <alpha xml:lang="no-nb"> + <kappa attr="100%"> + <zeta token="attribute"/> + <xi insert="another attribute value" xml:lang="nb" xml:id="id9"/> + <phi> + <alpha token="content" xml:lang="no" xml:id="id10"/> + <delta xml:lang="en-GB" xml:id="id11"> + <green>This text must be green</green> + </delta> + </phi> + </kappa> + </alpha> + </theta> + </omega> + </chi> + </beta> + </tree> + </test> + <test> + <xpath>//mu[@insert][@xml:lang="nb"]/chi[@title][@xml:id="id1"][not(preceding-sibling::*)]/sigma[@false][not(preceding-sibling::*)][not(following-sibling::*)]/chi[contains(@desciption,"1")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="en"][not(following-sibling::*)]/beta[@attrib][not(following-sibling::*)]/epsilon[@xml:lang="no"][not(child::node())][following-sibling::mu[@xml:id="id3"]/rho[@xml:lang="no"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@title="attribute value"][not(following-sibling::*)]//theta[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@attr="another attribute value"][@xml:lang="no"][not(preceding-sibling::*)]//omega[starts-with(@object,"another attribute value")][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)]//tau[not(preceding-sibling::*)][not(child::node())][following-sibling::iota[starts-with(@name,"attri")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 2]][following-sibling::beta[@xml:id="id7"][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id8"][not(child::node())][following-sibling::gamma[@xml:id="id9"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//xi[following-sibling::lambda[contains(concat(@true,"$"),"n$")][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <mu insert="_blank" xml:lang="nb"> + <chi title="attribute" xml:id="id1"> + <sigma false="attribute value"> + <chi desciption="100%" xml:lang="en" xml:id="id2"> + <gamma xml:lang="en"> + <beta attrib="attribute"> + <epsilon xml:lang="no"/> + <mu xml:id="id3"> + <rho xml:lang="no" xml:id="id4"/> + <psi> + <chi title="attribute value"> + <theta token="another attribute value" xml:id="id5"> + <phi attr="another attribute value" xml:lang="no"> + <omega object="another attribute value" xml:lang="en-GB" xml:id="id6"> + <tau/> + <iota name="attribute" xml:lang="en-US"/> + <upsilon/> + <beta xml:id="id7"/> + <sigma xml:lang="no-nb" xml:id="id8"/> + <gamma xml:id="id9"> + <xi/> + <lambda true="solid 1px green" xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </lambda> + </gamma> + </omega> + </phi> + </theta> + </chi> + </psi> + </mu> + </beta> + </gamma> + </chi> + </sigma> + </chi> + </mu> + </tree> + </test> + <test> + <xpath>//sigma[starts-with(concat(@src,"-"),"attribute-")]//zeta[@true][@xml:id="id1"][not(child::node())][following-sibling::psi[@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[contains(concat(@number,"$"),"s.nodeValue$")][@xml:id="id3"][preceding-sibling::*[position() = 2]]//mu[not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:lang="nb"][following-sibling::iota[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@false="content"][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[@xml:lang="en"][following-sibling::upsilon[@number="false"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]//pi[@xml:lang="nb"][@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::epsilon[@delete="true"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::eta[@src="false"][@xml:lang="no-nb"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <sigma src="attribute"> + <zeta true="attribute" xml:id="id1"/> + <psi xml:lang="en" xml:id="id2"/> + <omega number="this.nodeValue" xml:id="id3"> + <mu> + <chi xml:lang="nb"/> + <iota/> + <gamma false="content" xml:lang="no"> + <tau xml:lang="en"/> + <upsilon number="false" xml:id="id4"/> + <xi xml:lang="en-GB"> + <pi xml:lang="nb" xml:id="id5"/> + <epsilon delete="true" xml:id="id6"/> + <eta src="false" xml:lang="no-nb"> + <green>This text must be green</green> + </eta> + </xi> + </gamma> + </mu> + </omega> + </sigma> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-US"][@xml:id="id1"]//lambda[starts-with(@class,"att")][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 2]][following-sibling::alpha[@delete][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::iota[@xml:lang="en"][not(child::node())][following-sibling::chi[starts-with(concat(@or,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::mu[@insert][@xml:id="id5"][preceding-sibling::*[position() = 6]]/nu[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::rho[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[starts-with(concat(@src,"-"),"100%-")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omicron[@insert="false"][@xml:id="id8"][following-sibling::iota[@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::iota)]]]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-US" xml:id="id1"> + <lambda class="attribute value"/> + <nu xml:id="id2"/> + <beta/> + <alpha delete="123456789" xml:id="id3"/> + <iota xml:lang="en"/> + <chi or="this.nodeValue" xml:lang="nb" xml:id="id4"/> + <mu insert="true" xml:id="id5"> + <nu xml:id="id6"/> + <rho xml:id="id7"/> + <any src="100%" xml:lang="en-US"> + <omicron insert="false" xml:id="id8"/> + <iota xml:lang="no" xml:id="id9"> + <green>This text must be green</green> + </iota> + </any> + </mu> + </kappa> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:id="id1"]//alpha[contains(concat(@string,"$"),"ttribute$")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:id="id3"]/phi[@xml:lang="no"][following-sibling::*[position()=4]][not(child::node())][following-sibling::beta[@xml:id="id4"][not(child::node())][following-sibling::phi[following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::omega[@xml:lang="en-GB"][not(following-sibling::*)]/pi[starts-with(@or,"_bl")][@xml:id="id6"][not(following-sibling::*)]//pi[contains(@title,"rue")][not(preceding-sibling::*)]/eta[@xml:lang="en-GB"][@xml:id="id7"]/omega[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[not(following-sibling::*)]/lambda[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[starts-with(concat(@src,"-"),"true-")][@xml:lang="no-nb"][@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[contains(@attrib,"t")][@xml:id="id11"][not(following-sibling::*)]//theta[@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:id="id1"> + <alpha string="attribute" xml:id="id2"/> + <omicron xml:id="id3"> + <phi xml:lang="no"/> + <beta xml:id="id4"/> + <phi/> + <chi xml:id="id5"/> + <omega xml:lang="en-GB"> + <pi or="_blank" xml:id="id6"> + <pi title="true"> + <eta xml:lang="en-GB" xml:id="id7"> + <omega xml:lang="en-GB" xml:id="id8"> + <kappa> + <lambda xml:id="id9"> + <delta src="true" xml:lang="no-nb" xml:id="id10"/> + <any attrib="content" xml:id="id11"> + <theta xml:id="id12"> + <green>This text must be green</green> + </theta> + </any> + </lambda> + </kappa> + </omega> + </eta> + </pi> + </pi> + </omega> + </omicron> + </epsilon> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]//mu[@object][@xml:lang="en"][not(following-sibling::*)]/mu[@xml:lang="en"][not(following-sibling::*)]/sigma[@xml:lang="no"][not(preceding-sibling::*)]//kappa[@desciption][@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::xi[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::alpha[contains(concat(@and,"$"),"lank$")][@xml:id="id4"]/theta[contains(concat(@true,"$"),"ribute$")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//chi[@string="attribute-value"][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::psi[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::tau[@xml:lang="no-nb"][following-sibling::beta[starts-with(concat(@src,"-"),"false-")][@xml:lang="no-nb"][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::lambda[@xml:id="id9"][preceding-sibling::*[position() = 5]][not(following-sibling::*)][not(preceding-sibling::lambda)]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <mu object="attribute value" xml:lang="en"> + <mu xml:lang="en"> + <sigma xml:lang="no"> + <kappa desciption="attribute value" xml:lang="en-GB" xml:id="id2"/> + <xi xml:lang="en-US" xml:id="id3"/> + <alpha and="_blank" xml:id="id4"> + <theta true="attribute" xml:lang="nb" xml:id="id5"> + <chi string="attribute-value" xml:lang="en-US"/> + <psi xml:id="id6"/> + <sigma xml:lang="no-nb" xml:id="id7"/> + <tau xml:lang="no-nb"/> + <beta src="false" xml:lang="no-nb" xml:id="id8"/> + <lambda xml:id="id9"> + <green>This text must be green</green> + </lambda> + </theta> + </alpha> + </sigma> + </mu> + </mu> + </phi> + </tree> + </test> + <test> + <xpath>//rho[@title="true"][@xml:lang="nb"][@xml:id="id1"]//phi[contains(concat(@false,"$"),"-value$")][@xml:id="id2"][not(following-sibling::*)]//chi[starts-with(@title,"_bl")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::kappa[@attr][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//eta[starts-with(@desciption,"fal")][@xml:id="id5"]/upsilon[starts-with(concat(@class,"-"),"another attribute value-")][@xml:lang="en"][following-sibling::zeta[contains(@data,"ute value")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 2]]//lambda[@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::*[contains(@attrib,"0%")][not(child::node())][following-sibling::beta[@number][@xml:lang="no-nb"][@xml:id="id8"][not(child::node())][following-sibling::nu[@xml:lang="no-nb"][@xml:id="id9"][preceding-sibling::*[position() = 3]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <rho title="true" xml:lang="nb" xml:id="id1"> + <phi false="attribute-value" xml:id="id2"> + <chi title="_blank" xml:lang="no"/> + <psi xml:lang="en-US" xml:id="id3"/> + <kappa attr="true" xml:id="id4"> + <eta desciption="false" xml:id="id5"> + <upsilon class="another attribute value" xml:lang="en"/> + <zeta data="another attribute value" xml:lang="en-US" xml:id="id6"/> + <pi> + <lambda xml:lang="en-US" xml:id="id7"/> + <any attrib="100%"/> + <beta number="attribute value" xml:lang="no-nb" xml:id="id8"/> + <nu xml:lang="no-nb" xml:id="id9"> + <green>This text must be green</green> + </nu> + </pi> + </eta> + </kappa> + </phi> + </rho> + </tree> + </test> + <test> + <xpath>//delta[contains(@title,"te")][@xml:id="id1"]//upsilon[@content][@xml:id="id2"][following-sibling::pi[@att][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[following-sibling::mu[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::mu)]/*[contains(@name,"lue")][not(preceding-sibling::*)]/omega[contains(@desciption,"%")][@xml:lang="en-US"][not(preceding-sibling::*)]/zeta[starts-with(concat(@attrib,"-"),"another attribute value-")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[starts-with(concat(@data,"-"),"attribute value-")][@xml:lang="nb"][@xml:id="id6"][following-sibling::*[@class][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@attr="another attribute value"][@xml:lang="en"][@xml:id="id7"]/xi[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)]//zeta[contains(@attribute,"se")][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@title="attribute"][@xml:lang="en"][@xml:id="id10"]/theta[starts-with(@content,"at")][@xml:id="id11"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:lang="nb"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <delta title="attribute" xml:id="id1"> + <upsilon content="attribute" xml:id="id2"/> + <pi att="attribute value" xml:lang="en-US" xml:id="id3"> + <chi/> + <mu xml:id="id4"> + <any name="this-is-att-value"> + <omega desciption="100%" xml:lang="en-US"> + <zeta attrib="another attribute value" xml:id="id5"/> + <pi xml:lang="en-US"> + <phi data="attribute value" xml:lang="nb" xml:id="id6"/> + <any class="_blank" xml:lang="en"> + <kappa attr="another attribute value" xml:lang="en" xml:id="id7"> + <xi src="this.nodeValue" xml:lang="en" xml:id="id8"> + <zeta attribute="false" xml:id="id9"/> + <delta title="attribute" xml:lang="en" xml:id="id10"> + <theta content="attribute-value" xml:id="id11"/> + <psi xml:lang="nb"> + <green>This text must be green</green> + </psi> + </delta> + </xi> + </kappa> + </any> + </pi> + </omega> + </any> + </mu> + </pi> + </delta> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(concat(@attribute,"-"),"content-")][@xml:lang="en"][@xml:id="id1"]/tau[not(following-sibling::*)]/delta[contains(concat(@true,"$"),"reen$")][@xml:lang="en"][following-sibling::beta[@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::sigma[@string][@xml:lang="no"][@xml:id="id3"]/theta[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@insert][@xml:lang="no"][not(following-sibling::*)]/rho[@xml:lang="no-nb"][@xml:id="id5"]/kappa[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[@att][@xml:id="id7"][preceding-sibling::*[position() = 1]]/rho[@xml:lang="no"][@xml:id="id8"][following-sibling::rho[starts-with(concat(@or,"-"),"false-")]/beta[@xml:lang="no-nb"][@xml:id="id9"][following-sibling::beta[@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <gamma attribute="content" xml:lang="en" xml:id="id1"> + <tau> + <delta true="solid 1px green" xml:lang="en"/> + <beta xml:id="id2"/> + <sigma string="solid 1px green" xml:lang="no" xml:id="id3"> + <theta xml:id="id4"/> + <phi insert="this-is-att-value" xml:lang="no"> + <rho xml:lang="no-nb" xml:id="id5"> + <kappa xml:id="id6"> + <beta desciption="this.nodeValue" xml:lang="en-US"/> + <beta att="attribute-value" xml:id="id7"> + <rho xml:lang="no" xml:id="id8"/> + <rho or="false"> + <beta xml:lang="no-nb" xml:id="id9"/> + <beta xml:id="id10"> + <green>This text must be green</green> + </beta> + </rho> + </beta> + </kappa> + </rho> + </phi> + </sigma> + </tau> + </gamma> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="no-nb"]//kappa[contains(@token,"1234567")][@xml:lang="en-GB"][not(preceding-sibling::*)]/alpha[@xml:lang="en"][not(following-sibling::*)]//epsilon[starts-with(@data,"tr")][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[starts-with(concat(@and,"-"),"false-")][@xml:lang="en-US"][following-sibling::upsilon[not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="no-nb"> + <kappa token="123456789" xml:lang="en-GB"> + <alpha xml:lang="en"> + <epsilon data="true" xml:lang="nb" xml:id="id1"/> + <nu and="false" xml:lang="en-US"/> + <upsilon> + <green>This text must be green</green> + </upsilon> + </alpha> + </kappa> + </rho> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(concat(@src,"-"),"solid 1px green-")]//*[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)]//iota[@xml:lang="no-nb"]/phi[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:id="id2"][not(child::node())][following-sibling::theta[@xml:id="id3"][not(following-sibling::*)]//lambda[@class][@xml:lang="en-GB"][not(preceding-sibling::*)]/chi[@object][not(preceding-sibling::*)][not(following-sibling::*)]/*[starts-with(@token,"fa")]//phi[@xml:lang="en-GB"]/rho[contains(concat(@false,"$"),"id 1px green$")][not(following-sibling::rho)]/phi[@insert="another attribute value"][@xml:lang="no"][@xml:id="id4"][following-sibling::lambda[preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="nb"][following-sibling::mu[@xml:id="id5"][preceding-sibling::*[position() = 3]]//lambda[starts-with(concat(@src,"-"),"false-")][@xml:lang="no"][@xml:id="id6"][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/nu[contains(concat(@string,"$"),"ttribute$")][@xml:id="id9"][not(child::node())][following-sibling::theta[contains(@true,"attribute-v")][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::nu[preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <omicron src="solid 1px green"> + <any xml:lang="en" xml:id="id1"> + <iota xml:lang="no-nb"> + <phi src="this.nodeValue" xml:id="id2"/> + <theta xml:id="id3"> + <lambda class="100%" xml:lang="en-GB"> + <chi object="false"> + <any token="false"> + <phi xml:lang="en-GB"> + <rho false="solid 1px green"> + <phi insert="another attribute value" xml:lang="no" xml:id="id4"/> + <lambda/> + <lambda xml:lang="nb"/> + <mu xml:id="id5"> + <lambda src="false" xml:lang="no" xml:id="id6"/> + <chi xml:lang="no-nb" xml:id="id7"/> + <rho xml:lang="en" xml:id="id8"> + <nu string="attribute" xml:id="id9"/> + <theta true="attribute-value" xml:id="id10"/> + <nu> + <green>This text must be green</green> + </nu> + </rho> + </mu> + </rho> + </phi> + </any> + </chi> + </lambda> + </theta> + </iota> + </any> + </omicron> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="en-GB"][@xml:id="id1"]/omega[starts-with(@string,"c")][following-sibling::alpha[@desciption][@xml:lang="en"][@xml:id="id2"]/lambda[starts-with(concat(@number,"-"),"123456789-")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id4"][following-sibling::alpha[@delete][preceding-sibling::*[position() = 1]][following-sibling::beta[contains(@abort,"bute valu")][@xml:lang="nb"][@xml:id="id5"][following-sibling::xi[contains(concat(@class,"$"),"_blank$")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/chi[@xml:id="id6"]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="en-GB" xml:id="id1"> + <omega string="content"/> + <alpha desciption="another attribute value" xml:lang="en" xml:id="id2"> + <lambda number="123456789" xml:id="id3"/> + <theta> + <mu xml:lang="no-nb" xml:id="id4"/> + <alpha delete="this-is-att-value"/> + <beta abort="another attribute value" xml:lang="nb" xml:id="id5"/> + <xi class="_blank"> + <chi xml:id="id6"> + <green>This text must be green</green> + </chi> + </xi> + </theta> + </alpha> + </theta> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@content,"-"),"true-")][@xml:lang="en-GB"][@xml:id="id1"]//theta[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]]//rho[@xml:lang="en"][@xml:id="id3"][following-sibling::upsilon[contains(@desciption,"is-is-att-valu")][preceding-sibling::*[position() = 1]]//rho[@name][@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::pi[@string][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[@xml:lang="nb"][following-sibling::epsilon[@xml:lang="en-US"]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <zeta content="true" xml:lang="en-GB" xml:id="id1"> + <theta xml:lang="en-US" xml:id="id2"/> + <iota> + <rho xml:lang="en" xml:id="id3"/> + <upsilon desciption="this-is-att-value"> + <rho name="content" xml:lang="en-GB" xml:id="id4"/> + <pi string="123456789"> + <omega xml:lang="nb"/> + <epsilon xml:lang="en-US"> + <green>This text must be green</green> + </epsilon> + </pi> + </upsilon> + </iota> + </zeta> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]/theta[@xml:id="id2"][not(following-sibling::*)]//eta[contains(concat(@string,"$"),"00%$")][following-sibling::omega[starts-with(concat(@abort,"-"),"attribute-")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@class][preceding-sibling::*[position() = 2]]//iota[@abort="this.nodeValue"][@xml:lang="en"][not(preceding-sibling::*)]/mu[starts-with(@insert,"attr")][@xml:lang="en-US"][following-sibling::omicron[@attr="_blank"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[not(child::node())][following-sibling::omega[@data="100%"][@xml:lang="no-nb"]//omega[@xml:lang="nb"][@xml:id="id4"]//xi[@xml:lang="en"][not(preceding-sibling::*)][not(preceding-sibling::xi)][not(child::node())][following-sibling::omega[starts-with(@abort,"100%")][preceding-sibling::*[position() = 1]]/tau[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::zeta[starts-with(@delete,"solid")][@xml:id="id5"][preceding-sibling::*[position() = 1]]/pi[@desciption="solid 1px green"][not(following-sibling::*)]/beta[@attribute="solid 1px green"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="nb"][following-sibling::iota[contains(@true,"true")][preceding-sibling::*[position() = 2]]//psi[contains(@delete,"ttribu")][not(preceding-sibling::*)][not(following-sibling::*)]//nu[not(preceding-sibling::*)][following-sibling::chi[@attr="attribute value"][following-sibling::iota[@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]]]]][position() = 1]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <theta xml:id="id2"> + <eta string="100%"/> + <omega abort="attribute-value" xml:id="id3"/> + <sigma class="another attribute value"> + <iota abort="this.nodeValue" xml:lang="en"> + <mu insert="attribute" xml:lang="en-US"/> + <omicron attr="_blank"/> + <theta/> + <omega data="100%" xml:lang="no-nb"> + <omega xml:lang="nb" xml:id="id4"> + <xi xml:lang="en"/> + <omega abort="100%"> + <tau xml:lang="nb"/> + <zeta delete="solid 1px green" xml:id="id5"> + <pi desciption="solid 1px green"> + <beta attribute="solid 1px green" xml:id="id6"/> + <xi xml:lang="nb"/> + <iota true="true"> + <psi delete="attribute-value"> + <nu/> + <chi attr="attribute value"/> + <iota xml:id="id7"> + <green>This text must be green</green> + </iota> + </psi> + </iota> + </pi> + </zeta> + </omega> + </omega> + </omega> + </iota> + </sigma> + </theta> + </gamma> + </tree> + </test> + <test> + <xpath>//*[starts-with(@number,"conten")][@xml:lang="nb"]/iota[@attr="123456789"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@data="attribute-value"][@xml:lang="no-nb"][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/nu[@xml:lang="no-nb"][not(preceding-sibling::*)]/psi[@xml:lang="en-US"][@xml:id="id1"][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <any number="content" xml:lang="nb"> + <iota attr="123456789"/> + <tau data="attribute-value" xml:lang="no-nb"/> + <rho xml:lang="no-nb"> + <nu xml:lang="no-nb"> + <psi xml:lang="en-US" xml:id="id1"> + <green>This text must be green</green> + </psi> + </nu> + </rho> + </any> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en"]/theta[not(following-sibling::*)]//nu[@delete][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[starts-with(@string,"_bl")][preceding-sibling::*[position() = 1]]/mu[@xml:id="id1"][not(preceding-sibling::*)]/beta[@xml:id="id2"]//upsilon[@xml:id="id3"][not(following-sibling::*)]/chi[contains(concat(@abort,"$"),"tribute-value$")][@xml:lang="en-GB"][@xml:id="id4"]/delta[@number][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[not(following-sibling::*)]//epsilon[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="no"][preceding-sibling::*[position() = 1]]/tau[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@content][@xml:lang="en"][preceding-sibling::*[position() = 1]]//zeta[@and][@xml:id="id7"][following-sibling::mu[@insert="solid 1px green"][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[starts-with(@object,"10")][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en"> + <theta> + <nu delete="attribute-value" xml:lang="no-nb"/> + <zeta string="_blank"> + <mu xml:id="id1"> + <beta xml:id="id2"> + <upsilon xml:id="id3"> + <chi abort="attribute-value" xml:lang="en-GB" xml:id="id4"> + <delta number="content"/> + <nu> + <epsilon xml:id="id5"/> + <nu xml:lang="no"> + <tau xml:id="id6"/> + <theta content="content" xml:lang="en"> + <zeta and="content" xml:id="id7"/> + <mu insert="solid 1px green" xml:lang="en"> + <xi object="100%"> + <green>This text must be green</green> + </xi> + </mu> + </theta> + </nu> + </nu> + </chi> + </upsilon> + </beta> + </mu> + </zeta> + </theta> + </upsilon> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en"][@xml:id="id1"]//omicron[not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:lang="no-nb"]/delta[@xml:id="id2"]/phi[starts-with(@or,"another attribute value")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::rho[@xml:id="id5"][preceding-sibling::*[position() = 3]][not(preceding-sibling::rho)][following-sibling::upsilon[@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::omicron[contains(concat(@attr,"$"),"ttribute value$")][@xml:lang="en-US"]//phi[@xml:id="id7"][following-sibling::*[position()=3]][not(child::node())][following-sibling::gamma[@name][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[contains(@data,"ank")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[not(following-sibling::*)]//tau[@xml:lang="en-GB"][not(preceding-sibling::*)]/chi[following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[contains(@or,"blank")][@xml:lang="nb"]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <phi xml:lang="en" xml:id="id1"> + <omicron> + <theta xml:lang="no-nb"> + <delta xml:id="id2"> + <phi or="another attribute value" xml:lang="en"/> + <chi xml:lang="en-GB" xml:id="id3"/> + <omega xml:lang="no" xml:id="id4"/> + <rho xml:id="id5"/> + <upsilon xml:id="id6"/> + <omicron attr="attribute value" xml:lang="en-US"> + <phi xml:id="id7"/> + <gamma name="this.nodeValue" xml:lang="en"/> + <gamma data="_blank" xml:lang="en-GB"/> + <upsilon> + <tau xml:lang="en-GB"> + <chi/> + <pi or="_blank" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </tau> + </upsilon> + </omicron> + </delta> + </theta> + </omicron> + </phi> + </tree> + </test> + <test> + <xpath>//theta[starts-with(concat(@delete,"-"),"another attribute value-")][@xml:lang="en"][@xml:id="id1"]//psi//beta[not(preceding-sibling::*)]/delta[not(preceding-sibling::*)]//lambda[starts-with(@class,"1")][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[contains(concat(@false,"$"),"e$")][@xml:id="id2"][not(preceding-sibling::*)]//omega[@name][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[contains(concat(@content,"$"),"attribute$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//psi[@name="attribute"][@xml:id="id3"]//theta[contains(@or,"0%")]/xi[@xml:lang="no-nb"][@xml:id="id4"]//kappa[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[contains(@or,"solid 1px gre")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::chi)]/theta[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="en"][preceding-sibling::*[position() = 1]]/psi[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[contains(concat(@attrib,"$"),"e$")][@xml:id="id7"][not(following-sibling::*)]/tau[@xml:lang="no-nb"]/beta[@xml:id="id8"][following-sibling::omega[contains(concat(@data,"$"),"lue$")][preceding-sibling::*[position() = 1]][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id9"]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <theta delete="another attribute value" xml:lang="en" xml:id="id1"> + <psi> + <beta> + <delta> + <lambda class="100%"> + <alpha false="true" xml:id="id2"> + <omega name="true" xml:lang="no"/> + <iota/> + <iota content="attribute"> + <psi name="attribute" xml:id="id3"> + <theta or="100%"> + <xi xml:lang="no-nb" xml:id="id4"> + <kappa xml:lang="en-US" xml:id="id5"> + <chi or="solid 1px green" xml:lang="en-GB"> + <theta xml:lang="nb"/> + <theta xml:lang="en"> + <psi xml:id="id6"> + <rho attrib="attribute value" xml:id="id7"> + <tau xml:lang="no-nb"> + <beta xml:id="id8"/> + <omega data="this.nodeValue"/> + <epsilon xml:lang="en-US" xml:id="id9"> + <green>This text must be green</green> + </epsilon> + </tau> + </rho> + </psi> + </theta> + </chi> + </kappa> + </xi> + </theta> + </psi> + </iota> + </alpha> + </lambda> + </delta> + </beta> + </psi> + </theta> + </tree> + </test> + <test> + <xpath>//eta[contains(@number,"deValue")][@xml:id="id1"]/delta[contains(@content,"ue")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::alpha[contains(@attrib,"0%")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/tau[@attr="attribute value"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::eta/lambda[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[not(preceding-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <eta number="this.nodeValue" xml:id="id1"> + <delta content="true" xml:lang="no" xml:id="id2"/> + <alpha attrib="100%"/> + <eta xml:lang="en" xml:id="id3"> + <tau attr="attribute value" xml:id="id4"/> + <eta> + <lambda xml:id="id5"> + <iota> + <green>This text must be green</green> + </iota> + </lambda> + </eta> + </eta> + </eta> + </tree> + </test> + <test> + <xpath>//kappa[@attr]/gamma[contains(concat(@content,"$"),"tribute value$")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[starts-with(@att,"f")]/xi[@token][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@src][preceding-sibling::*[position() = 2]][not(following-sibling::xi)]/kappa[@and][@xml:lang="en-GB"][not(child::node())][following-sibling::upsilon[@xml:lang="en"]//rho[@att="another attribute value"][@xml:lang="en"][not(preceding-sibling::*)]/beta[not(preceding-sibling::*)][not(following-sibling::*)]//nu[not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@att][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@xml:lang="en-US"][not(preceding-sibling::*)]/mu[@xml:id="id3"]/delta[@object][@xml:lang="en-GB"][not(following-sibling::*)]//gamma[starts-with(@attr,"attribu")][following-sibling::iota[@xml:id="id4"][following-sibling::phi[@or][@xml:id="id5"][not(following-sibling::*)]//sigma[not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::lambda[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//kappa[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::upsilon[contains(@data,"b")][@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::tau[@and="100%"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]]][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <kappa attr="this-is-att-value"> + <gamma content="attribute value" xml:id="id1"> + <tau att="false"> + <xi token="attribute" xml:lang="en-GB"/> + <psi xml:id="id2"/> + <xi src="another attribute value"> + <kappa and="solid 1px green" xml:lang="en-GB"/> + <upsilon xml:lang="en"> + <rho att="another attribute value" xml:lang="en"> + <beta> + <nu/> + <mu att="attribute" xml:lang="en-US"> + <any xml:lang="en-US"> + <mu xml:id="id3"> + <delta object="attribute" xml:lang="en-GB"> + <gamma attr="attribute-value"/> + <iota xml:id="id4"/> + <phi or="attribute value" xml:id="id5"> + <sigma/> + <kappa xml:lang="nb"/> + <lambda> + <kappa xml:lang="en-GB"/> + <upsilon data="attribute-value" xml:lang="en-US" xml:id="id6"/> + <tau and="100%" xml:id="id7"> + <green>This text must be green</green> + </tau> + </lambda> + </phi> + </delta> + </mu> + </any> + </mu> + </beta> + </rho> + </upsilon> + </xi> + </tau> + </gamma> + </kappa> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no"]/beta[@false="solid 1px green"][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[contains(concat(@string,"$"),"tent$")][@xml:lang="en-GB"][not(preceding-sibling::*)]/nu[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@abort][@xml:lang="nb"][following-sibling::*[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[not(following-sibling::*)]/delta[@name="this-is-att-value"][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@insert][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[contains(@number,"n")][@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:id="id6"]/*[@xml:lang="en"]//upsilon[contains(concat(@delete,"$"),"ntent$")][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@xml:id="id8"][not(following-sibling::*)]//omega[@object="false"][following-sibling::*[position()=1]][following-sibling::kappa[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[contains(concat(@title,"$"),"nodeValue$")][@xml:id="id9"][not(following-sibling::*)]//beta[starts-with(@title,"th")][not(preceding-sibling::*)][not(preceding-sibling::beta)][not(child::node())][following-sibling::rho[@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 1]]//upsilon[@token][@xml:id="id11"]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no"> + <beta false="solid 1px green" xml:lang="en-GB" xml:id="id1"/> + <omicron> + <tau string="content" xml:lang="en-GB"> + <nu xml:lang="nb" xml:id="id2"> + <mu abort="attribute value" xml:lang="nb"/> + <any> + <chi> + <delta name="this-is-att-value" xml:lang="no-nb" xml:id="id3"> + <mu insert="attribute" xml:lang="nb" xml:id="id4"> + <kappa number="solid 1px green" xml:id="id5"/> + <theta xml:id="id6"> + <any xml:lang="en"> + <upsilon delete="content" xml:id="id7"/> + <phi xml:id="id8"> + <omega object="false"/> + <kappa xml:lang="en-US"> + <pi title="this.nodeValue" xml:id="id9"> + <beta title="this-is-att-value"/> + <rho xml:lang="no" xml:id="id10"> + <upsilon token="this.nodeValue" xml:id="id11"> + <green>This text must be green</green> + </upsilon> + </rho> + </pi> + </kappa> + </phi> + </any> + </theta> + </mu> + </delta> + </chi> + </any> + </nu> + </tau> + </omicron> + </kappa> + </tree> + </test> + <test> + <xpath>//gamma[@attribute][@xml:lang="no-nb"]/omega[not(preceding-sibling::*)]//xi[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(preceding-sibling::xi)][following-sibling::rho[contains(concat(@attribute,"$"),"e$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau/omicron[@true][@xml:lang="no"][not(following-sibling::*)]//pi[starts-with(concat(@attr,"-"),"content-")][@xml:lang="nb"][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <gamma attribute="100%" xml:lang="no-nb"> + <omega> + <xi xml:lang="en" xml:id="id1"/> + <rho attribute="false"/> + <tau> + <omicron true="content" xml:lang="no"> + <pi attr="content" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </omicron> + </tau> + </omega> + </gamma> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no-nb"]/psi[not(preceding-sibling::*)]//epsilon[not(preceding-sibling::*)][not(following-sibling::*)]//rho[starts-with(concat(@or,"-"),"100%-")][following-sibling::alpha[contains(@object,"green")][@xml:lang="en-GB"][not(child::node())][following-sibling::beta[@xml:id="id1"][preceding-sibling::*[position() = 2]][following-sibling::omega[@xml:id="id2"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/omega[contains(@data,"e val")][@xml:lang="en"]//alpha[contains(concat(@desciption,"$"),"9$")]//rho[@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::mu[starts-with(@data,"attribute valu")][@xml:lang="en-US"][@xml:id="id5"]//delta[starts-with(@content,"thi")][not(following-sibling::*)]//omega[@desciption][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@data][not(child::node())][following-sibling::phi/kappa[starts-with(concat(@desciption,"-"),"this-")][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(@string,"a")][@xml:id="id7"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no-nb"> + <psi> + <epsilon> + <rho or="100%"/> + <alpha object="solid 1px green" xml:lang="en-GB"/> + <beta xml:id="id1"/> + <omega xml:id="id2"/> + <omicron xml:lang="en-US" xml:id="id3"> + <omega data="attribute value" xml:lang="en"> + <alpha desciption="123456789"> + <rho xml:lang="no-nb" xml:id="id4"/> + <mu data="attribute value" xml:lang="en-US" xml:id="id5"> + <delta content="this-is-att-value"> + <omega desciption="this.nodeValue"/> + <eta data="100%"/> + <phi> + <kappa desciption="this-is-att-value" xml:id="id6"/> + <mu string="another attribute value" xml:id="id7"> + <green>This text must be green</green> + </mu> + </phi> + </delta> + </mu> + </alpha> + </omega> + </omicron> + </epsilon> + </psi> + </tau> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@name,"-"),"content-")][@xml:lang="en-US"]/alpha[contains(@number,"a")][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::lambda[@object][preceding-sibling::*[position() = 1]]//chi[@and][@xml:id="id2"][not(preceding-sibling::*)]//alpha[@xml:id="id3"][not(preceding-sibling::*)]//xi[@true][@xml:id="id4"][not(child::node())][following-sibling::pi[@false][preceding-sibling::*[position() = 1]]/rho[@xml:id="id5"][not(child::node())][following-sibling::psi[starts-with(@title,"12345678")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <delta name="content" xml:lang="en-US"> + <alpha number="false" xml:id="id1"/> + <lambda object="attribute-value"> + <chi and="content" xml:id="id2"> + <alpha xml:id="id3"> + <xi true="content" xml:id="id4"/> + <pi false="123456789"> + <rho xml:id="id5"/> + <psi title="123456789"> + <green>This text must be green</green> + </psi> + </pi> + </alpha> + </chi> + </lambda> + </delta> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en-GB"][@xml:id="id1"]//pi[contains(@att,"e")][@xml:lang="no"][@xml:id="id2"][not(following-sibling::pi)][following-sibling::eta[@attrib="false"][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::eta[@xml:lang="no"][not(child::node())][following-sibling::theta[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 3]][following-sibling::theta/gamma[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@name][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(preceding-sibling::omicron or following-sibling::omicron)][following-sibling::kappa[@name][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/delta[not(following-sibling::*)]/pi[@attribute="true"][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]/beta[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]/lambda[@title="content"][@xml:id="id8"][following-sibling::epsilon[@abort="attribute value"][not(following-sibling::*)]//epsilon[@data="this.nodeValue"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en"][@xml:id="id10"][not(child::node())][following-sibling::omicron[@xml:id="id11"]/kappa[contains(@title,"lue")][@xml:id="id12"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="no-nb"][not(preceding-sibling::phi)][not(child::node())][following-sibling::beta[contains(concat(@string,"$"),"ue$")][@xml:id="id13"][following-sibling::*[position()=1]][following-sibling::zeta[starts-with(concat(@src,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id14"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]][position() = 1]]]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="en-GB" xml:id="id1"> + <pi att="true" xml:lang="no" xml:id="id2"/> + <eta attrib="false" xml:lang="no-nb" xml:id="id3"/> + <eta xml:lang="no"/> + <theta xml:lang="no-nb" xml:id="id4"/> + <theta> + <gamma xml:id="id5"/> + <omicron name="true" xml:lang="en-GB"/> + <kappa name="attribute"> + <delta> + <pi attribute="true" xml:lang="en" xml:id="id6"> + <beta xml:lang="en-GB" xml:id="id7"> + <lambda title="content" xml:id="id8"/> + <epsilon abort="attribute value"> + <epsilon data="this.nodeValue" xml:id="id9"/> + <omicron xml:lang="en" xml:id="id10"/> + <omicron xml:id="id11"> + <kappa title="attribute value" xml:id="id12"/> + <phi xml:lang="no-nb"/> + <beta string="attribute value" xml:id="id13"/> + <zeta src="attribute" xml:lang="en-US" xml:id="id14"> + <green>This text must be green</green> + </zeta> + </omicron> + </epsilon> + </beta> + </pi> + </delta> + </kappa> + </theta> + </omicron> + </tree> + </test> + <test> + <xpath>//epsilon[contains(concat(@attr,"$"),"reen$")][@xml:lang="en-GB"]//phi[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(preceding-sibling::phi)][not(child::node())][following-sibling::lambda[starts-with(@insert,"another attribute ")][@xml:lang="en"][preceding-sibling::*[position() = 1]]//iota[contains(@or,"bute-value")][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::iota[@xml:id="id2"]/kappa[@attr]/kappa[@xml:id="id3"][not(child::node())][following-sibling::eta[starts-with(concat(@true,"-"),"this.nodeValue-")][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::chi[@string][preceding-sibling::*[position() = 2]][not(preceding-sibling::chi)][following-sibling::theta[@xml:id="id5"][preceding-sibling::*[position() = 3]]//omicron[@insert][@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::psi[@xml:id="id7"][preceding-sibling::*[position() = 1]]//*[@xml:lang="no-nb"][not(following-sibling::*)]//tau[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)]/sigma[contains(concat(@false,"$"),"value$")][@xml:lang="en-GB"]//alpha[@class][not(child::node())][following-sibling::mu[contains(concat(@attrib,"$"),"blank$")][@xml:lang="no"][@xml:id="id9"][not(child::node())][following-sibling::tau[@xml:id="id10"][not(following-sibling::*)]/theta[starts-with(@attr,"attrib")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:lang="en-US"][not(child::node())][following-sibling::gamma[@content][@xml:id="id11"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon attr="solid 1px green" xml:lang="en-GB"> + <phi/> + <lambda insert="another attribute value" xml:lang="en"> + <iota or="attribute-value" xml:id="id1"/> + <mu/> + <iota xml:id="id2"> + <kappa attr="content"> + <kappa xml:id="id3"/> + <eta true="this.nodeValue" xml:id="id4"/> + <chi string="100%"/> + <theta xml:id="id5"> + <omicron insert="this-is-att-value" xml:lang="en-US" xml:id="id6"/> + <psi xml:id="id7"> + <any xml:lang="no-nb"> + <tau xml:lang="en-GB" xml:id="id8"> + <sigma false="attribute-value" xml:lang="en-GB"> + <alpha class="attribute"/> + <mu attrib="_blank" xml:lang="no" xml:id="id9"/> + <tau xml:id="id10"> + <theta attr="attribute value" xml:lang="no-nb"> + <any xml:lang="en-US"/> + <gamma content="solid 1px green" xml:id="id11"> + <green>This text must be green</green> + </gamma> + </theta> + </tau> + </sigma> + </tau> + </any> + </psi> + </theta> + </kappa> + </iota> + </lambda> + </epsilon> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="nb"][@xml:id="id1"]//omicron[starts-with(@token,"1")][following-sibling::theta[contains(concat(@content,"$")," value$")][@xml:lang="en"]/beta[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:id="id3"][not(following-sibling::*)]//mu[@xml:lang="en-GB"][not(preceding-sibling::*)]/delta[@xml:lang="en"][not(preceding-sibling::*)]/beta[starts-with(concat(@attribute,"-"),"this-")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[not(child::node())][following-sibling::gamma[@xml:lang="en-US"][not(following-sibling::*)]//iota[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[@content="true"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="nb" xml:id="id1"> + <omicron token="123456789"/> + <theta content="another attribute value" xml:lang="en"> + <beta xml:lang="en-US" xml:id="id2"/> + <tau xml:id="id3"> + <mu xml:lang="en-GB"> + <delta xml:lang="en"> + <beta attribute="this-is-att-value" xml:lang="en-US" xml:id="id4"/> + <mu/> + <gamma xml:lang="en-US"> + <iota xml:id="id5"/> + <beta content="true"> + <green>This text must be green</green> + </beta> + </gamma> + </delta> + </mu> + </tau> + </theta> + </rho> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(@data,"attribute value")][@xml:lang="en-GB"][@xml:id="id1"]//omega[@xml:id="id2"][following-sibling::theta[not(preceding-sibling::theta)]/gamma[@class][@xml:id="id3"][not(preceding-sibling::*)]/beta[contains(@attr,"value")][@xml:lang="en"][not(preceding-sibling::*)]//sigma[contains(concat(@object,"$"),"ttribute value$")][@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=4]][not(child::node())][following-sibling::omega[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::omega[contains(@object,"ru")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[@xml:lang="en-US"][@xml:id="id6"][following-sibling::upsilon[@xml:lang="en-US"][preceding-sibling::*[position() = 4]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <alpha data="attribute value" xml:lang="en-GB" xml:id="id1"> + <omega xml:id="id2"/> + <theta> + <gamma class="content" xml:id="id3"> + <beta attr="this-is-att-value" xml:lang="en"> + <sigma object="attribute value" xml:lang="en" xml:id="id4"/> + <omega xml:lang="no" xml:id="id5"/> + <omega object="true" xml:lang="no-nb"/> + <omega xml:lang="en-US" xml:id="id6"/> + <upsilon xml:lang="en-US"> + <green>This text must be green</green> + </upsilon> + </beta> + </gamma> + </theta> + </alpha> + </tree> + </test> + <test> + <xpath>//lambda[contains(@object,"u")]//omicron[not(preceding-sibling::*)][following-sibling::gamma[starts-with(concat(@att,"-"),"another attribute value-")][@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[starts-with(@or,"attribute-")][@xml:lang="nb"][not(child::node())][following-sibling::pi[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:id="id3"][preceding-sibling::*[position() = 2]]//sigma[@xml:id="id4"][not(following-sibling::*)]/theta[starts-with(@src,"another attri")][@xml:id="id5"][following-sibling::kappa[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::eta[contains(@true,"1")][@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::chi[@xml:id="id9"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <lambda object="attribute-value"> + <omicron/> + <gamma att="another attribute value" xml:lang="en-GB" xml:id="id1"> + <epsilon or="attribute-value" xml:lang="nb"/> + <pi xml:lang="nb" xml:id="id2"/> + <iota xml:id="id3"> + <sigma xml:id="id4"> + <theta src="another attribute value" xml:id="id5"/> + <kappa xml:id="id6"/> + <delta xml:lang="no-nb" xml:id="id7"/> + <eta true="100%" xml:lang="en-GB" xml:id="id8"/> + <chi xml:id="id9"> + <green>This text must be green</green> + </chi> + </sigma> + </iota> + </gamma> + </lambda> + </tree> + </test> + <test> + <xpath>//sigma/iota[starts-with(concat(@data,"-"),"solid 1px green-")][@xml:lang="en"]/kappa[@and="false"][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@string="solid 1px green"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::psi)]/upsilon[starts-with(concat(@false,"-"),"_blank-")][not(preceding-sibling::*)]//pi[contains(concat(@attribute,"$"),"tent$")][not(following-sibling::*)]/alpha[not(following-sibling::*)]/kappa[starts-with(concat(@false,"-"),"this-")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@attr="123456789"][@xml:id="id2"][not(following-sibling::*)]/upsilon[contains(@or,"attrib")][@xml:lang="nb"][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][following-sibling::kappa[contains(concat(@name,"$"),"px green$")][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::rho[@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]/gamma[starts-with(@desciption,"_blan")][@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[following-sibling::epsilon[contains(@attribute,"tribute-value")][@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//beta[contains(@src,"ue")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::beta)]//alpha[starts-with(@attr,"fals")][not(preceding-sibling::*)]/mu[following-sibling::gamma[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[@xml:lang="no"][@xml:id="id8"][following-sibling::alpha[contains(@attr,"nodeVa")][@xml:lang="en-US"][@xml:id="id9"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>1</nth> + </result> + <tree> + <sigma> + <iota data="solid 1px green" xml:lang="en"> + <kappa and="false" xml:lang="en-GB"> + <psi string="solid 1px green"> + <upsilon false="_blank"> + <pi attribute="content"> + <alpha> + <kappa false="this-is-att-value" xml:id="id1"/> + <xi attr="123456789" xml:id="id2"> + <upsilon or="attribute value" xml:lang="nb"/> + <delta xml:lang="no-nb"/> + <kappa name="solid 1px green" xml:id="id3"/> + <rho xml:lang="nb" xml:id="id4"> + <gamma desciption="_blank" xml:lang="no-nb" xml:id="id5"/> + <upsilon/> + <epsilon attribute="attribute-value" xml:lang="en-US" xml:id="id6"> + <beta src="true" xml:lang="no" xml:id="id7"> + <alpha attr="false"> + <mu/> + <gamma/> + <pi/> + <iota xml:lang="no" xml:id="id8"/> + <alpha attr="this.nodeValue" xml:lang="en-US" xml:id="id9"> + <green>This text must be green</green> + </alpha> + </alpha> + </beta> + </epsilon> + </rho> + </xi> + </alpha> + </pi> + </upsilon> + </psi> + </kappa> + </iota> + </sigma> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="no"][@xml:id="id1"]//zeta[contains(@data,"another attri")][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@name][not(preceding-sibling::*)][following-sibling::tau[following-sibling::omicron[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::rho[starts-with(concat(@or,"-"),"100%-")][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 3]][following-sibling::upsilon[preceding-sibling::*[position() = 4]][not(following-sibling::*)]/omega[not(preceding-sibling::*)]//eta[@xml:lang="no"]//theta[@token][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/omicron[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@xml:lang="en-US"][@xml:id="id4"]/mu[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[contains(@object,"456789")][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:lang="nb"][not(preceding-sibling::*)]/lambda[@and][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:lang="no"][not(following-sibling::eta)]/nu[contains(@abort,"attribute value")][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="no"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="no" xml:id="id1"> + <zeta data="another attribute value"> + <sigma name="content"/> + <tau/> + <omicron xml:lang="nb"/> + <rho or="100%" xml:lang="no" xml:id="id2"/> + <upsilon> + <omega> + <eta xml:lang="no"> + <theta token="another attribute value" xml:lang="en-US"> + <lambda xml:lang="en" xml:id="id3"> + <omicron/> + <xi xml:lang="en-US" xml:id="id4"> + <mu xml:id="id5"> + <chi object="123456789"> + <pi xml:lang="nb"> + <lambda and="attribute" xml:lang="no"/> + <eta xml:lang="no"> + <nu abort="another attribute value"> + <delta xml:lang="no"> + <green>This text must be green</green> + </delta> + </nu> + </eta> + </pi> + </chi> + </mu> + </xi> + </lambda> + </theta> + </eta> + </omega> + </upsilon> + </zeta> + </chi> + </tree> + </test> + <test> + <xpath>//phi[contains(@abort,"o")]/iota[@xml:id="id1"]/delta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@xml:id="id3"][following-sibling::upsilon[@string][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 2]]//*[@xml:id="id4"][following-sibling::sigma[@xml:lang="no"][@xml:id="id5"]/eta[starts-with(concat(@content,"-"),"attribute value-")][@xml:id="id6"]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <phi abort="content"> + <iota xml:id="id1"> + <delta xml:lang="no"/> + <epsilon xml:id="id2"> + <beta xml:id="id3"/> + <upsilon string="attribute-value" xml:lang="en-GB"/> + <chi> + <any xml:id="id4"/> + <sigma xml:lang="no" xml:id="id5"> + <eta content="attribute value" xml:id="id6"> + <green>This text must be green</green> + </eta> + </sigma> + </chi> + </epsilon> + </iota> + </phi> + </tree> + </test> + <test> + <xpath>//sigma//rho[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:id="id1"][preceding-sibling::*[position() = 1]]//nu[@attribute="_blank"][@xml:id="id2"]//tau[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/delta//gamma[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <rho xml:lang="nb"/> + <pi xml:id="id1"> + <nu attribute="_blank" xml:id="id2"> + <tau xml:lang="no-nb" xml:id="id3"> + <delta> + <gamma content="attribute" xml:lang="no-nb"> + <green>This text must be green</green> + </gamma> + </delta> + </tau> + </nu> + </pi> + </sigma> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:id="id1"]/nu[starts-with(@content,"f")]//xi[starts-with(@abort,"1")][not(child::node())][following-sibling::mu[@desciption="_blank"][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="nb"][not(child::node())][following-sibling::eta[@xml:lang="no-nb"]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:id="id1"> + <nu content="false"> + <xi abort="123456789"/> + <mu desciption="_blank" xml:lang="en-US"/> + <any xml:lang="nb"/> + <eta xml:lang="no-nb"> + <green>This text must be green</green> + </eta> + </nu> + </upsilon> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@and,"-"),"this-")]/rho[starts-with(concat(@or,"-"),"this-")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::psi[contains(@and,"ute-value")][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[contains(@src,"lse")][@xml:id="id2"][following-sibling::nu[@xml:id="id3"][not(following-sibling::*)]/sigma[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@string][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]/delta[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@token="100%"][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[starts-with(concat(@class,"-"),"another attribute value-")][@xml:id="id6"][not(preceding-sibling::*)]//psi[@xml:id="id7"][following-sibling::chi[starts-with(concat(@name,"-"),"attribute-")][@xml:lang="no"][preceding-sibling::*[position() = 1]]/chi[@xml:lang="nb"][not(following-sibling::*)]/rho[@title][not(preceding-sibling::*)]/omicron[@string][@xml:lang="en"][not(following-sibling::*)]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <zeta and="this-is-att-value"> + <rho or="this-is-att-value" xml:lang="en"/> + <xi xml:lang="en"/> + <psi and="attribute-value" xml:lang="no-nb" xml:id="id1"> + <epsilon xml:lang="no-nb"> + <lambda src="false" xml:id="id2"/> + <nu xml:id="id3"> + <sigma xml:lang="no-nb"> + <theta string="false" xml:lang="no" xml:id="id4"> + <delta xml:lang="en-US"/> + <upsilon token="100%" xml:lang="nb" xml:id="id5"> + <chi class="another attribute value" xml:id="id6"> + <psi xml:id="id7"/> + <chi name="attribute-value" xml:lang="no"> + <chi xml:lang="nb"> + <rho title="attribute-value"> + <omicron string="content" xml:lang="en"> + <green>This text must be green</green> + </omicron> + </rho> + </chi> + </chi> + </chi> + </upsilon> + </theta> + </sigma> + </nu> + </epsilon> + </psi> + </zeta> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="no"][@xml:id="id1"]/gamma[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[@xml:id="id2"][not(preceding-sibling::*)]/phi[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::delta[@class="123456789"][@xml:lang="no-nb"][not(child::node())][following-sibling::rho[@xml:lang="en-US"][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 3]]/tau[@desciption][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="en-GB"]/beta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(preceding-sibling::beta)][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[starts-with(concat(@title,"-"),"false-")][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::eta[starts-with(concat(@title,"-"),"false-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::tau[@xml:lang="no"][@xml:id="id8"][not(child::node())][following-sibling::gamma[contains(concat(@name,"$"),"value$")][@xml:lang="nb"][preceding-sibling::*[position() = 6]]//lambda[starts-with(@delete,"100%")][@xml:lang="nb"][@xml:id="id9"][not(child::node())][following-sibling::chi[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="no" xml:id="id1"> + <gamma xml:lang="en-US"/> + <chi xml:lang="no"> + <nu xml:id="id2"> + <phi xml:lang="no" xml:id="id3"/> + <delta class="123456789" xml:lang="no-nb"/> + <rho xml:lang="en-US"/> + <iota> + <tau desciption="attribute" xml:id="id4"/> + <theta xml:lang="en-GB"> + <beta xml:lang="en-GB" xml:id="id5"/> + <gamma/> + <omega title="false" xml:lang="en-GB" xml:id="id6"/> + <eta title="false" xml:lang="en-GB"/> + <omicron xml:lang="en" xml:id="id7"/> + <tau xml:lang="no" xml:id="id8"/> + <gamma name="another attribute value" xml:lang="nb"> + <lambda delete="100%" xml:lang="nb" xml:id="id9"/> + <chi xml:lang="en"> + <green>This text must be green</green> + </chi> + </gamma> + </theta> + </iota> + </nu> + </chi> + </pi> + </tree> + </test> + <test> + <xpath>//kappa[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:lang="nb"]//rho[@attribute="100%"][@xml:lang="en-GB"][following-sibling::delta[contains(@attrib,"c")][@xml:lang="en-US"][following-sibling::zeta[contains(@delete,"gre")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[not(following-sibling::*)]/phi[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:lang="nb"][not(following-sibling::*)]/phi[contains(concat(@string,"$"),"ibute value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@xml:id="id2"]/tau[starts-with(concat(@attribute,"-"),"solid 1px green-")][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::tau[@xml:lang="en-GB"][not(following-sibling::*)]//delta[@xml:lang="en-GB"][following-sibling::chi[@xml:lang="en"][@xml:id="id3"][following-sibling::psi[contains(concat(@and,"$"),"e$")]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <kappa desciption="this.nodeValue" xml:lang="nb"> + <rho attribute="100%" xml:lang="en-GB"/> + <delta attrib="content" xml:lang="en-US"/> + <zeta delete="solid 1px green"/> + <gamma> + <phi xml:lang="en-US" xml:id="id1"> + <any xml:lang="nb"> + <phi string="attribute value" xml:lang="no-nb"> + <beta xml:id="id2"> + <tau attribute="solid 1px green" xml:lang="no"/> + <tau xml:lang="en-GB"> + <delta xml:lang="en-GB"/> + <chi xml:lang="en" xml:id="id3"/> + <psi and="this-is-att-value"> + <green>This text must be green</green> + </psi> + </tau> + </beta> + </phi> + </any> + </phi> + </gamma> + </kappa> + </tree> + </test> + <test> + <xpath>//pi[@title]/xi[@data][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[contains(@content,"r")][@xml:lang="nb"][not(preceding-sibling::*)]/kappa[@xml:lang="en"][following-sibling::gamma[@or="another attribute value"][@xml:id="id2"][not(following-sibling::*)]//eta[not(following-sibling::*)]//tau[starts-with(@desciption,"attribute")][@xml:id="id3"][following-sibling::iota[starts-with(@content,"_")][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::omicron[@src="another attribute value"][@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//phi[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]//kappa[starts-with(@desciption,"this.n")][@xml:id="id7"]//lambda[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>1</nth> + </result> + <tree> + <pi title="_blank"> + <xi data="content" xml:id="id1"> + <kappa content="true" xml:lang="nb"> + <kappa xml:lang="en"/> + <gamma or="another attribute value" xml:id="id2"> + <eta> + <tau desciption="attribute value" xml:id="id3"/> + <iota content="_blank" xml:lang="no-nb" xml:id="id4"/> + <omicron src="another attribute value" xml:lang="en" xml:id="id5"> + <phi xml:lang="en" xml:id="id6"> + <kappa desciption="this.nodeValue" xml:id="id7"> + <lambda xml:lang="en-GB" xml:id="id8"> + <green>This text must be green</green> + </lambda> + </kappa> + </phi> + </omicron> + </eta> + </gamma> + </kappa> + </xi> + </pi> + </tree> + </test> + <test> + <xpath>//omicron[@xml:id="id1"]//iota[starts-with(@attr,"this-is-att-")][@xml:id="id2"][not(following-sibling::*)]/beta[@string][@xml:lang="no-nb"][not(child::node())][following-sibling::omega[@or][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//pi[not(following-sibling::*)]/nu[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)]//tau[@xml:id="id5"][not(following-sibling::*)]//theta[@src][@xml:lang="en"][following-sibling::xi[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(preceding-sibling::xi)][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/rho[starts-with(concat(@false,"-"),"false-")][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)]//phi[@attribute][@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]//omega[starts-with(concat(@abort,"-"),"attribute-")][@xml:lang="en-US"][following-sibling::*[position()=2]][following-sibling::lambda[@attrib="_blank"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:id="id9"][preceding-sibling::*[position() = 2]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:id="id1"> + <iota attr="this-is-att-value" xml:id="id2"> + <beta string="content" xml:lang="no-nb"/> + <omega or="this-is-att-value" xml:lang="en-GB" xml:id="id3"> + <pi> + <nu xml:lang="nb" xml:id="id4"> + <tau xml:id="id5"> + <theta src="solid 1px green" xml:lang="en"/> + <xi xml:lang="en"/> + <xi xml:lang="en-GB" xml:id="id6"> + <rho false="false" xml:lang="en-GB" xml:id="id7"> + <phi attribute="attribute value" xml:lang="en-GB" xml:id="id8"> + <omega abort="attribute" xml:lang="en-US"/> + <lambda attrib="_blank"/> + <nu xml:id="id9"> + <green>This text must be green</green> + </nu> + </phi> + </rho> + </xi> + </tau> + </nu> + </pi> + </omega> + </iota> + </omicron> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no"]//theta[@xml:id="id1"][not(following-sibling::*)]/upsilon[@xml:id="id2"][not(preceding-sibling::*)]//*[@attribute][@xml:lang="no"]/eta[contains(concat(@string,"$"),"bute-value$")][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@title][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::alpha[@token][@xml:lang="en-US"][@xml:id="id5"][following-sibling::phi[contains(concat(@or,"$"),"e$")][@xml:lang="en"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::chi[@number="123456789"][@xml:lang="no-nb"][following-sibling::epsilon[starts-with(@name,"_blank")][@xml:id="id6"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//omega[@string][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="no-nb"]//omega[@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::*[@attr][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[contains(@abort,"tr")][@xml:lang="en"][@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::chi[starts-with(concat(@true,"-"),"attribute value-")][@xml:lang="en-GB"][not(following-sibling::*)]//pi[@xml:lang="en-US"][@xml:id="id10"][not(following-sibling::*)][not(following-sibling::pi)]/eta[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::kappa[@data][@xml:id="id11"][not(following-sibling::*)]/sigma[@attribute][not(preceding-sibling::*)][following-sibling::mu[@object][@xml:id="id12"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="no"][not(following-sibling::*)]//delta[@xml:lang="en-GB"][@xml:id="id13"][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no"> + <theta xml:id="id1"> + <upsilon xml:id="id2"> + <any attribute="this-is-att-value" xml:lang="no"> + <eta string="attribute-value" xml:id="id3"/> + <mu title="attribute-value" xml:id="id4"/> + <alpha token="123456789" xml:lang="en-US" xml:id="id5"/> + <phi or="this-is-att-value" xml:lang="en"/> + <chi number="123456789" xml:lang="no-nb"/> + <epsilon name="_blank" xml:id="id6"> + <omega string="this.nodeValue" xml:id="id7"/> + <omicron xml:lang="no-nb"> + <omega xml:lang="no"/> + <any attr="another attribute value" xml:lang="en-GB" xml:id="id8"/> + <theta abort="another attribute value" xml:lang="en" xml:id="id9"/> + <chi true="attribute value" xml:lang="en-GB"> + <pi xml:lang="en-US" xml:id="id10"> + <eta/> + <kappa data="solid 1px green" xml:id="id11"> + <sigma attribute="content"/> + <mu object="100%" xml:id="id12"/> + <theta xml:lang="no"> + <delta xml:lang="en-GB" xml:id="id13"/> + <zeta> + <green>This text must be green</green> + </zeta> + </theta> + </kappa> + </pi> + </chi> + </omicron> + </epsilon> + </any> + </upsilon> + </theta> + </tau> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no"][@xml:id="id1"]/rho[@attrib="this-is-att-value"][@xml:id="id2"][not(preceding-sibling::*)][not(preceding-sibling::rho)][following-sibling::lambda[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:id="id3"][not(child::node())][following-sibling::zeta[starts-with(@content,"true")][@xml:id="id4"]/pi[contains(concat(@attr,"$"),"0%$")][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::iota[@and][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::chi[@xml:lang="nb"][following-sibling::*[position()=3]][not(child::node())][following-sibling::upsilon[starts-with(@desciption,"another attr")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::eta[starts-with(@number,"this-is-att-valu")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::chi[preceding-sibling::*[position() = 5]]//omega[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)]/upsilon[starts-with(@desciption,"fals")][following-sibling::delta[starts-with(@data,"this.nodeVa")][@xml:lang="no-nb"][@xml:id="id8"][not(following-sibling::*)]//epsilon[@content="false"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::epsilon)]/sigma[contains(@desciption,"9")][@xml:lang="nb"][not(preceding-sibling::*)]//rho[@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[starts-with(concat(@attribute,"-"),"false-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]//delta[@xml:lang="en-GB"][not(following-sibling::delta)][following-sibling::theta[@or="attribute"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[starts-with(@abort,"this.node")][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:id="id11"][preceding-sibling::*[position() = 3]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no" xml:id="id1"> + <rho attrib="this-is-att-value" xml:id="id2"/> + <lambda> + <beta xml:id="id3"/> + <zeta content="true" xml:id="id4"> + <pi attr="100%" xml:lang="nb" xml:id="id5"/> + <iota and="solid 1px green"/> + <chi xml:lang="nb"/> + <upsilon desciption="another attribute value" xml:lang="en-GB"/> + <eta number="this-is-att-value" xml:lang="en-US" xml:id="id6"/> + <chi> + <omega xml:lang="no" xml:id="id7"> + <upsilon desciption="false"/> + <delta data="this.nodeValue" xml:lang="no-nb" xml:id="id8"> + <epsilon content="false"> + <sigma desciption="123456789" xml:lang="nb"> + <rho xml:id="id9"/> + <omicron attribute="false" xml:lang="nb"> + <delta xml:lang="en-GB"/> + <theta or="attribute"/> + <psi abort="this.nodeValue" xml:id="id10"/> + <upsilon xml:id="id11"> + <green>This text must be green</green> + </upsilon> + </omicron> + </sigma> + </epsilon> + </delta> + </omega> + </chi> + </zeta> + </lambda> + </psi> + </tree> + </test> + <test> + <xpath>//nu[contains(concat(@abort,"$"),"blank$")][@xml:lang="en-US"]/nu[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::chi[following-sibling::epsilon[@xml:id="id2"][preceding-sibling::*[position() = 2]]/lambda[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::rho[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[contains(concat(@attribute,"$"),"ank$")][@xml:lang="nb"][@xml:id="id6"][not(child::node())][following-sibling::eta[@delete][preceding-sibling::*[position() = 3]]/beta[@xml:lang="no-nb"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::phi[@content][@xml:id="id8"][following-sibling::nu[following-sibling::zeta[@xml:lang="no-nb"][@xml:id="id9"][following-sibling::delta[@xml:id="id10"][following-sibling::zeta[@xml:lang="en"][@xml:id="id11"][preceding-sibling::*[position() = 5]]]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>1</nth> + </result> + <tree> + <nu abort="_blank" xml:lang="en-US"> + <nu xml:id="id1"/> + <chi/> + <epsilon xml:id="id2"> + <lambda xml:id="id3"> + <tau xml:lang="no" xml:id="id4"/> + <rho xml:id="id5"/> + <beta attribute="_blank" xml:lang="nb" xml:id="id6"/> + <eta delete="123456789"> + <beta xml:lang="no-nb" xml:id="id7"/> + <phi content="_blank" xml:id="id8"/> + <nu/> + <zeta xml:lang="no-nb" xml:id="id9"/> + <delta xml:id="id10"/> + <zeta xml:lang="en" xml:id="id11"> + <green>This text must be green</green> + </zeta> + </eta> + </lambda> + </epsilon> + </nu> + </tree> + </test> + <test> + <xpath>//beta[starts-with(@and,"this-is-at")][@xml:lang="nb"][@xml:id="id1"]/psi[@token][@xml:lang="en-US"][@xml:id="id2"]/tau[@xml:lang="en-GB"][not(following-sibling::*)]/pi[@xml:lang="en-US"][following-sibling::alpha[contains(@content,"tr")][@xml:id="id3"][preceding-sibling::*[position() = 1]]//pi[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::*[contains(concat(@true,"$"),"lue$")][@xml:lang="en-GB"][not(following-sibling::*)]/iota[contains(concat(@number,"$"),"e$")][@xml:lang="en-GB"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="nb"][@xml:id="id6"]/beta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:lang="nb"][@xml:id="id7"][not(child::node())][following-sibling::epsilon[@content="123456789"][@xml:id="id8"][not(following-sibling::*)]/beta[contains(concat(@and,"$"),"e$")][@xml:lang="no"]/nu[@xml:id="id9"][not(following-sibling::*)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <beta and="this-is-att-value" xml:lang="nb" xml:id="id1"> + <psi token="false" xml:lang="en-US" xml:id="id2"> + <tau xml:lang="en-GB"> + <pi xml:lang="en-US"/> + <alpha content="attribute-value" xml:id="id3"> + <pi xml:lang="en-US" xml:id="id4"/> + <any true="attribute value" xml:lang="en-GB"> + <iota number="another attribute value" xml:lang="en-GB" xml:id="id5"/> + <delta xml:lang="nb" xml:id="id6"> + <beta xml:lang="no"> + <sigma xml:lang="nb" xml:id="id7"/> + <epsilon content="123456789" xml:id="id8"> + <beta and="true" xml:lang="no"> + <nu xml:id="id9"> + <green>This text must be green</green> + </nu> + </beta> + </epsilon> + </beta> + </delta> + </any> + </alpha> + </tau> + </psi> + </beta> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no"]/theta[following-sibling::zeta[@src="this.nodeValue"][@xml:lang="nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::psi[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/chi[not(child::node())][following-sibling::phi[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no"> + <theta/> + <zeta src="this.nodeValue" xml:lang="nb" xml:id="id1"/> + <psi xml:lang="no"> + <chi/> + <phi xml:id="id2"> + <green>This text must be green</green> + </phi> + </psi> + </iota> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@object,"$"),"en$")][@xml:id="id1"]//omega[not(preceding-sibling::*)]//sigma[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::gamma[@insert="content"][preceding-sibling::*[position() = 1]]//sigma[@xml:lang="en"]/alpha[@xml:id="id3"]//zeta[@xml:lang="no"][@xml:id="id4"][following-sibling::omega[@xml:id="id5"][not(following-sibling::*)]/xi[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@xml:id="id6"][not(following-sibling::*)]//epsilon[contains(concat(@false,"$"),"e$")][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[starts-with(concat(@and,"-"),"solid 1px green-")][@xml:lang="en"][not(following-sibling::*)]//phi[starts-with(@token,"th")][@xml:lang="en-US"][following-sibling::*[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[@number="true"][@xml:id="id8"][not(child::node())][following-sibling::zeta[starts-with(@data,"so")][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <iota object="solid 1px green" xml:id="id1"> + <omega> + <sigma xml:id="id2"/> + <gamma insert="content"> + <sigma xml:lang="en"> + <alpha xml:id="id3"> + <zeta xml:lang="no" xml:id="id4"/> + <omega xml:id="id5"> + <xi xml:lang="nb"/> + <theta xml:lang="en-US"> + <nu xml:id="id6"> + <epsilon false="true" xml:id="id7"> + <iota and="solid 1px green" xml:lang="en"> + <phi token="this.nodeValue" xml:lang="en-US"/> + <any xml:lang="en-US"/> + <upsilon number="true" xml:id="id8"/> + <zeta data="solid 1px green"> + <green>This text must be green</green> + </zeta> + </iota> + </epsilon> + </nu> + </theta> + </omega> + </alpha> + </sigma> + </gamma> + </omega> + </iota> + </tree> + </test> + <test> + <xpath>//eta[starts-with(concat(@object,"-"),"attribute value-")][@xml:lang="nb"]//omicron[@xml:lang="en-US"][@xml:id="id1"]/pi[@att="true"][@xml:id="id2"]/omega[@att="123456789"][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::phi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::tau[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/iota[@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[@title="_blank"][not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <eta object="attribute value" xml:lang="nb"> + <omicron xml:lang="en-US" xml:id="id1"> + <pi att="true" xml:id="id2"> + <omega att="123456789" xml:lang="en-GB" xml:id="id3"/> + <phi xml:lang="no-nb"/> + <tau> + <iota xml:lang="no-nb"/> + <sigma title="_blank"> + <green>This text must be green</green> + </sigma> + </tau> + </pi> + </omicron> + </eta> + </tree> + </test> + <test> + <xpath>//*/upsilon[@att="123456789"][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)]/rho[@xml:id="id2"][following-sibling::epsilon[starts-with(concat(@abort,"-"),"100%-")][@xml:lang="en-GB"][following-sibling::iota[@xml:lang="en"][@xml:id="id3"]//theta[contains(concat(@desciption,"$")," 1px green$")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::xi[contains(concat(@desciption,"$"),"content$")][@xml:lang="no-nb"][not(child::node())][following-sibling::delta[contains(@attribute,"s-is-a")][@xml:lang="no-nb"]//xi[@data][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=6]][following-sibling::mu[@attribute="123456789"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::epsilon[@insert="this.nodeValue"][@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 3]][following-sibling::psi[@xml:id="id8"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=3]][not(child::node())][following-sibling::mu[contains(@title,"789")][@xml:id="id9"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::xi[@string="123456789"][not(child::node())][following-sibling::beta[@xml:lang="en-GB"][preceding-sibling::*[position() = 7]]/upsilon[@src="attribute value"][@xml:id="id10"][not(child::node())][following-sibling::eta[contains(concat(@attribute,"$"),"rue$")]//gamma[@object][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[contains(concat(@delete,"$"),"9$")][@xml:id="id12"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]][position() = 1]]][position() = 1]]]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <any> + <upsilon att="123456789" xml:lang="nb" xml:id="id1"> + <rho xml:id="id2"/> + <epsilon abort="100%" xml:lang="en-GB"/> + <iota xml:lang="en" xml:id="id3"> + <theta desciption="solid 1px green" xml:lang="en" xml:id="id4"/> + <theta xml:lang="en-GB"/> + <xi desciption="content" xml:lang="no-nb"/> + <delta attribute="this-is-att-value" xml:lang="no-nb"> + <xi data="attribute-value" xml:id="id5"/> + <delta xml:lang="en-GB"/> + <mu attribute="123456789" xml:id="id6"/> + <epsilon insert="this.nodeValue" xml:lang="no-nb" xml:id="id7"/> + <psi xml:id="id8"/> + <mu title="123456789" xml:id="id9"/> + <xi string="123456789"/> + <beta xml:lang="en-GB"> + <upsilon src="attribute value" xml:id="id10"/> + <eta attribute="true"> + <gamma object="_blank" xml:id="id11"/> + <gamma delete="123456789" xml:id="id12"> + <green>This text must be green</green> + </gamma> + </eta> + </beta> + </delta> + </iota> + </upsilon> + </any> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]/epsilon[@class="false"][@xml:lang="no-nb"][@xml:id="id2"][following-sibling::nu[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[contains(concat(@attrib,"$"),"alue$")][@xml:lang="en-US"]//tau[@xml:id="id3"][not(following-sibling::*)]//beta[@insert="100%"][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/iota[@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]/phi[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[not(following-sibling::*)]//pi[@insert][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:id="id7"][not(following-sibling::*)]//zeta[starts-with(@src,"attribu")][@xml:lang="nb"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <epsilon class="false" xml:lang="no-nb" xml:id="id2"/> + <nu xml:lang="no-nb"> + <sigma attrib="another attribute value" xml:lang="en-US"> + <tau xml:id="id3"> + <beta insert="100%" xml:lang="no-nb" xml:id="id4"> + <iota xml:lang="no" xml:id="id5"> + <phi xml:id="id6"/> + <gamma> + <pi insert="_blank" xml:lang="no"> + <upsilon xml:id="id7"> + <zeta src="attribute-value" xml:lang="nb"> + <green>This text must be green</green> + </zeta> + </upsilon> + </pi> + </gamma> + </iota> + </beta> + </tau> + </sigma> + </nu> + </mu> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no-nb"]//epsilon[@xml:lang="en"][@xml:id="id1"][not(following-sibling::*)]/alpha[@title="_blank"][@xml:lang="en-US"][@xml:id="id2"][following-sibling::omicron[starts-with(@object,"another a")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/xi[starts-with(@attr,"this.nodeVa")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[starts-with(@string,"12")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no-nb"> + <epsilon xml:lang="en" xml:id="id1"> + <alpha title="_blank" xml:lang="en-US" xml:id="id2"/> + <omicron object="another attribute value" xml:lang="en-US"> + <xi attr="this.nodeValue" xml:lang="en-US" xml:id="id3"/> + <phi string="123456789" xml:lang="no-nb"> + <green>This text must be green</green> + </phi> + </omicron> + </epsilon> + </beta> + </tree> + </test> + <test> + <xpath>//eta[@attrib][@xml:id="id1"]/zeta[@xml:lang="en-GB"][not(child::node())][following-sibling::delta[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//theta[contains(@attrib,"een")][@xml:id="id3"]/alpha[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@name][@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)]//xi[starts-with(concat(@att,"-"),"true-")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[contains(concat(@abort,"$"),"3456789$")][@xml:id="id7"][not(following-sibling::*)]//phi[starts-with(@att,"this-is-att-value")][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::xi[@title="true"][not(following-sibling::*)]/chi[not(preceding-sibling::*)]/omicron[starts-with(concat(@true,"-"),"attribute-")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[contains(concat(@src,"$"),"23456789$")][@xml:id="id9"]//lambda[not(preceding-sibling::*)]//delta[@xml:lang="nb"][@xml:id="id10"][not(child::node())][following-sibling::lambda[@xml:lang="en"]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <eta attrib="true" xml:id="id1"> + <zeta xml:lang="en-GB"/> + <delta xml:lang="en" xml:id="id2"> + <theta attrib="solid 1px green" xml:id="id3"> + <alpha xml:lang="en-US"> + <eta xml:lang="no"/> + <psi xml:lang="no" xml:id="id4"/> + <rho name="attribute value" xml:lang="no-nb" xml:id="id5"> + <xi att="true" xml:lang="no-nb" xml:id="id6"> + <kappa abort="123456789" xml:id="id7"> + <phi att="this-is-att-value"/> + <any xml:lang="en-GB" xml:id="id8"/> + <xi title="true"> + <chi> + <omicron true="attribute" xml:lang="en"/> + <tau src="123456789" xml:id="id9"> + <lambda> + <delta xml:lang="nb" xml:id="id10"/> + <lambda xml:lang="en"> + <green>This text must be green</green> + </lambda> + </lambda> + </tau> + </chi> + </xi> + </kappa> + </xi> + </rho> + </alpha> + </theta> + </delta> + </eta> + </tree> + </test> + <test> + <xpath>//tau[@content][@xml:id="id1"]/beta[@xml:lang="en-GB"][not(following-sibling::*)]/upsilon[starts-with(concat(@desciption,"-"),"this-")][@xml:id="id2"]//upsilon[@xml:id="id3"]/xi[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@content][@xml:id="id5"]//*[@xml:lang="nb"][not(preceding-sibling::*)]/psi[contains(@class,"al")][@xml:lang="en"][@xml:id="id6"]/gamma[@insert="100%"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[starts-with(@insert,"attribute-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::tau[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//kappa[@content][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[contains(@attrib,"789")][following-sibling::kappa[contains(concat(@object,"$"),"att-value$")][@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::alpha[@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(following-sibling::alpha)]/xi[following-sibling::*[position()=2]][not(preceding-sibling::xi)][not(child::node())][following-sibling::alpha[@name="_blank"][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//lambda[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::mu[contains(concat(@src,"$"),"s-is-att-value$")][@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]/nu[starts-with(@token,"this.nod")][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@true][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::omicron[starts-with(concat(@or,"-"),"_blank-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:lang="nb"][@xml:id="id12"][not(following-sibling::*)]][position() = 1]]]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <tau content="false" xml:id="id1"> + <beta xml:lang="en-GB"> + <upsilon desciption="this-is-att-value" xml:id="id2"> + <upsilon xml:id="id3"> + <xi xml:lang="en" xml:id="id4"/> + <xi content="attribute value" xml:id="id5"> + <any xml:lang="nb"> + <psi class="this.nodeValue" xml:lang="en" xml:id="id6"> + <gamma insert="100%"/> + <epsilon insert="attribute-value" xml:lang="en"/> + <tau> + <kappa content="another attribute value" xml:lang="nb"> + <eta attrib="123456789"/> + <kappa object="this-is-att-value" xml:lang="no-nb"/> + <alpha xml:id="id7"> + <xi/> + <alpha name="_blank" xml:lang="en-GB"/> + <zeta xml:lang="en-GB" xml:id="id8"> + <lambda/> + <mu src="this-is-att-value" xml:lang="en" xml:id="id9"> + <nu token="this.nodeValue" xml:id="id10"> + <kappa true="this.nodeValue" xml:id="id11"/> + <omicron or="_blank"/> + <iota xml:lang="nb" xml:id="id12"> + <green>This text must be green</green> + </iota> + </nu> + </mu> + </zeta> + </alpha> + </kappa> + </tau> + </psi> + </any> + </xi> + </upsilon> + </upsilon> + </beta> + </tau> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]/mu[@xml:lang="en"]/beta[starts-with(concat(@or,"-"),"123456789-")][@xml:lang="no"][not(following-sibling::*)]/alpha[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@title][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::epsilon[@false="attribute value"][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[not(preceding-sibling::*)][not(child::node())][following-sibling::iota[following-sibling::*[position()=5]][not(child::node())][following-sibling::zeta[@name="123456789"][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::xi[contains(concat(@true,"$"),"nk$")][@xml:id="id4"][preceding-sibling::*[position() = 3]][following-sibling::eta[@xml:lang="no"][preceding-sibling::*[position() = 4]][following-sibling::xi[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::sigma[contains(@insert,"alue")][@xml:lang="en"][preceding-sibling::*[position() = 6]]/iota[@attr][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]//upsilon[contains(concat(@abort,"$"),"ttribute-value$")][not(preceding-sibling::*)]//kappa[starts-with(@or,"_blan")][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(concat(@src,"$"),"ue$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//*[starts-with(@number,"100%")][not(child::node())][following-sibling::omicron//chi[contains(@title,"ru")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omega[@xml:id="id7"]][position() = 1]]]][position() = 1]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <mu xml:lang="en"> + <beta or="123456789" xml:lang="no"> + <alpha xml:lang="en-GB" xml:id="id2"> + <omicron title="attribute" xml:lang="en-GB"/> + <epsilon false="attribute value"/> + <eta> + <omega/> + <iota/> + <zeta name="123456789" xml:lang="no" xml:id="id3"/> + <xi true="_blank" xml:id="id4"/> + <eta xml:lang="no"/> + <xi xml:id="id5"/> + <sigma insert="another attribute value" xml:lang="en"> + <iota attr="this-is-att-value" xml:lang="no" xml:id="id6"> + <upsilon abort="attribute-value"> + <kappa or="_blank"/> + <omega src="this.nodeValue" xml:lang="en-GB"> + <any number="100%"/> + <omicron> + <chi title="true" xml:lang="nb"/> + <omega xml:id="id7"> + <green>This text must be green</green> + </omega> + </omicron> + </omega> + </upsilon> + </iota> + </sigma> + </eta> + </alpha> + </beta> + </mu> + </pi> + </tree> + </test> + <test> + <xpath>//rho[@data="123456789"][@xml:lang="no"]//upsilon[@xml:id="id1"]/omega[not(preceding-sibling::*)][not(following-sibling::*)]//pi[starts-with(concat(@abort,"-"),"this-")][@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//pi[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//chi[not(following-sibling::*)]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <rho data="123456789" xml:lang="no"> + <upsilon xml:id="id1"> + <omega> + <pi abort="this-is-att-value" xml:lang="en-US" xml:id="id2"> + <pi xml:lang="no-nb" xml:id="id3"> + <chi> + <green>This text must be green</green> + </chi> + </pi> + </pi> + </omega> + </upsilon> + </rho> + </tree> + </test> + <test> + <xpath>//omega[@and="another attribute value"][@xml:lang="no-nb"][@xml:id="id1"]/omega[not(preceding-sibling::*)][not(following-sibling::*)]//beta[@attr="this.nodeValue"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[following-sibling::*[position()=6]][following-sibling::iota[@xml:id="id3"][following-sibling::*[position()=5]][not(child::node())][following-sibling::tau[@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::psi[following-sibling::rho[@xml:lang="nb"][@xml:id="id5"][following-sibling::kappa[starts-with(@insert,"100")][@xml:lang="no-nb"][not(child::node())][following-sibling::lambda[@delete][@xml:lang="en"][preceding-sibling::*[position() = 7]]/omicron[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:lang="en-GB"][not(following-sibling::*)]//nu[@true][@xml:lang="no-nb"][not(following-sibling::*)]/sigma[@xml:lang="no-nb"][@xml:id="id6"][not(following-sibling::*)]//sigma[not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@title][@xml:id="id8"]//nu[@xml:id="id9"]/omicron[contains(concat(@insert,"$"),"eValue$")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:lang="nb"][not(preceding-sibling::*)]//pi[not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omega and="another attribute value" xml:lang="no-nb" xml:id="id1"> + <omega> + <beta attr="this.nodeValue" xml:id="id2"/> + <omega/> + <iota xml:id="id3"/> + <tau xml:id="id4"/> + <psi/> + <rho xml:lang="nb" xml:id="id5"/> + <kappa insert="100%" xml:lang="no-nb"/> + <lambda delete="false" xml:lang="en"> + <omicron content="this.nodeValue" xml:lang="en-GB"> + <nu true="another attribute value" xml:lang="no-nb"> + <sigma xml:lang="no-nb" xml:id="id6"> + <sigma/> + <psi xml:lang="en-GB"/> + <iota xml:id="id7"/> + <psi title="solid 1px green" xml:id="id8"> + <nu xml:id="id9"> + <omicron insert="this.nodeValue" xml:lang="en-GB"> + <chi xml:lang="nb"> + <pi> + <green>This text must be green</green> + </pi> + </chi> + </omicron> + </nu> + </psi> + </sigma> + </nu> + </omicron> + </lambda> + </omega> + </omega> + </tree> + </test> + <test> + <xpath>//iota[contains(@number,"ue")]//mu[not(following-sibling::*)]//chi[following-sibling::nu[contains(@and,"00")][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[@src="123456789"][not(following-sibling::delta)][following-sibling::tau[@content][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//sigma[@title][@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/*[@xml:lang="en-GB"][not(following-sibling::*)][not(preceding-sibling::any)]//zeta[@src][not(following-sibling::*)]//chi[starts-with(concat(@src,"-"),"solid 1px green-")][@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::delta[contains(@title,"nt")][@xml:id="id5"][not(child::node())][following-sibling::omicron//upsilon[@true][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@object]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <iota number="this-is-att-value"> + <mu> + <chi/> + <nu and="100%" xml:id="id1"> + <delta src="123456789"/> + <tau content="attribute" xml:lang="no" xml:id="id2"> + <sigma title="this-is-att-value" xml:lang="en-US" xml:id="id3"> + <any xml:lang="en-GB"> + <zeta src="this-is-att-value"> + <chi src="solid 1px green" xml:lang="en" xml:id="id4"/> + <delta title="content" xml:id="id5"/> + <omicron> + <upsilon true="true" xml:lang="no-nb"/> + <lambda xml:lang="en-US" xml:id="id6"> + <psi object="solid 1px green"> + <green>This text must be green</green> + </psi> + </lambda> + </omicron> + </zeta> + </any> + </sigma> + </tau> + </nu> + </mu> + </iota> + </tree> + </test> + <test> + <xpath>//omega/rho[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[@xml:lang="en-GB"][following-sibling::iota[not(following-sibling::*)]//omicron[@xml:id="id2"][not(following-sibling::*)]/eta[starts-with(concat(@true,"-"),"this-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[not(preceding-sibling::*)]//tau[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <rho xml:id="id1"> + <pi xml:lang="en-GB"/> + <iota> + <omicron xml:id="id2"> + <eta true="this-is-att-value" xml:lang="en-GB"/> + <lambda xml:id="id3"> + <xi> + <tau xml:lang="en" xml:id="id4"> + <green>This text must be green</green> + </tau> + </xi> + </lambda> + </omicron> + </iota> + </rho> + </omega> + </tree> + </test> + <test> + <xpath>//rho[@name="this-is-att-value"]/pi[@object][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::delta[starts-with(concat(@src,"-"),"solid 1px green-")][@xml:lang="en-GB"]//tau[@xml:lang="no-nb"][@xml:id="id2"]//nu[@class="123456789"][@xml:id="id3"][not(child::node())][following-sibling::psi[@xml:lang="en-US"][not(preceding-sibling::psi)][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[@xml:lang="en-US"][not(preceding-sibling::*)]//phi[contains(concat(@src,"$"),"ribute value$")][@xml:id="id4"][not(preceding-sibling::*)]//*[@xml:lang="en"][not(preceding-sibling::*)]/zeta[starts-with(@name,"attr")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:lang="no"][@xml:id="id5"]//delta[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@desciption="123456789"][@xml:lang="en"][preceding-sibling::*[position() = 1]]//epsilon[@attr][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/zeta/phi[not(following-sibling::*)]//rho[@title="_blank"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[starts-with(concat(@name,"-"),"this-")][@xml:id="id8"][not(child::node())][following-sibling::psi[starts-with(@attrib,"solid 1px green")][@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]]//tau[starts-with(@and,"another attribu")][position() = 1]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <rho name="this-is-att-value"> + <pi object="attribute-value" xml:id="id1"/> + <delta src="solid 1px green" xml:lang="en-GB"> + <tau xml:lang="no-nb" xml:id="id2"> + <nu class="123456789" xml:id="id3"/> + <psi xml:lang="en-US"/> + <beta> + <mu xml:lang="en-US"> + <phi src="attribute value" xml:id="id4"> + <any xml:lang="en"> + <zeta name="attribute-value" xml:lang="en-GB"/> + <omega xml:lang="no" xml:id="id5"> + <delta xml:id="id6"/> + <any desciption="123456789" xml:lang="en"> + <epsilon attr="attribute" xml:lang="en-GB" xml:id="id7"/> + <gamma xml:lang="no-nb"> + <zeta> + <phi> + <rho title="_blank" xml:lang="no-nb"> + <delta name="this-is-att-value" xml:id="id8"/> + <psi attrib="solid 1px green" xml:lang="nb" xml:id="id9"> + <tau and="another attribute value"> + <green>This text must be green</green> + </tau> + </psi> + </rho> + </phi> + </zeta> + </gamma> + </any> + </omega> + </any> + </phi> + </mu> + </beta> + </tau> + </delta> + </rho> + </tree> + </test> + <test> + <xpath>//tau[@xml:id="id1"]/zeta[@xml:lang="nb"]//upsilon[not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(@data,"e")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[following-sibling::*[position()=5]][following-sibling::kappa[starts-with(@src,"conten")][@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::eta[contains(concat(@title,"$"),"23456789$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::mu[starts-with(concat(@attrib,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=2]][following-sibling::zeta[contains(concat(@attribute,"$"),"-is-att-value$")][@xml:id="id4"][preceding-sibling::*[position() = 4]][following-sibling::gamma[@title="123456789"][not(following-sibling::*)]//iota[starts-with(concat(@attr,"-"),"100%-")]//kappa[@object][@xml:lang="en"][following-sibling::*[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[@string][@xml:lang="no"][@xml:id="id6"][not(following-sibling::omega)][position() = 1]]]]]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:id="id1"> + <zeta xml:lang="nb"> + <upsilon/> + <delta data="true"> + <theta/> + <kappa src="content" xml:lang="en-GB" xml:id="id2"/> + <eta title="123456789" xml:lang="en-GB"/> + <mu attrib="123456789" xml:lang="en-US" xml:id="id3"/> + <zeta attribute="this-is-att-value" xml:id="id4"/> + <gamma title="123456789"> + <iota attr="100%"> + <kappa object="true" xml:lang="en"/> + <any xml:lang="no-nb" xml:id="id5"> + <omega string="true" xml:lang="no" xml:id="id6"> + <green>This text must be green</green> + </omega> + </any> + </iota> + </gamma> + </delta> + </zeta> + </tau> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@object,"$"),"ibute value$")][@xml:lang="nb"][@xml:id="id1"]//delta[not(preceding-sibling::*)]//omicron[not(preceding-sibling::*)][not(following-sibling::*)]//nu[not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@name="solid 1px green"][@xml:id="id2"][following-sibling::lambda[@delete="solid 1px green"][@xml:id="id3"][not(child::node())][following-sibling::delta[preceding-sibling::*[position() = 2]][following-sibling::theta[contains(@att,"onte")][@xml:lang="no"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::chi[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 4]]/omega[@xml:id="id5"][not(child::node())][following-sibling::upsilon[@xml:id="id6"][not(following-sibling::*)]//nu[@title][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::omicron[starts-with(@object,"this-is-att-valu")][preceding-sibling::*[position() = 1]]/beta[@abort][@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@src][@xml:lang="no"][not(following-sibling::*)]//chi[@xml:lang="no-nb"][following-sibling::iota[starts-with(@number,"12345678")][@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:id="id10"][not(child::node())][following-sibling::omicron[@string][preceding-sibling::*[position() = 3]][not(following-sibling::omicron)][following-sibling::nu[@xml:lang="en-US"][@xml:id="id11"][not(following-sibling::*)]/gamma[@class][@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:lang="no-nb"][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>1</nth> + </result> + <tree> + <alpha object="another attribute value" xml:lang="nb" xml:id="id1"> + <delta> + <omicron> + <nu> + <alpha name="solid 1px green" xml:id="id2"/> + <lambda delete="solid 1px green" xml:id="id3"/> + <delta/> + <theta att="content" xml:lang="no"/> + <chi xml:lang="no" xml:id="id4"> + <omega xml:id="id5"/> + <upsilon xml:id="id6"> + <nu title="another attribute value" xml:lang="en-GB" xml:id="id7"/> + <omicron object="this-is-att-value"> + <beta abort="100%" xml:lang="no-nb" xml:id="id8"> + <eta src="attribute value" xml:lang="no"> + <chi xml:lang="no-nb"/> + <iota number="123456789" xml:lang="no" xml:id="id9"/> + <omicron xml:id="id10"/> + <omicron string="100%"/> + <nu xml:lang="en-US" xml:id="id11"> + <gamma class="content" xml:id="id12"> + <psi xml:lang="no-nb"> + <green>This text must be green</green> + </psi> + </gamma> + </nu> + </eta> + </beta> + </omicron> + </upsilon> + </chi> + </nu> + </omicron> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//kappa[@data][@xml:lang="en-GB"]//lambda[starts-with(@insert,"_blan")][@xml:lang="no"][not(preceding-sibling::*)]/sigma[not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[contains(@token,"e")][@xml:lang="no"]/epsilon[starts-with(@or,"cont")][not(preceding-sibling::*)]/delta[@xml:lang="en-US"][not(preceding-sibling::*)]/xi[@object][not(preceding-sibling::*)][following-sibling::beta[contains(@true,"e")][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::delta[starts-with(concat(@object,"-"),"_blank-")][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::iota[contains(concat(@and,"$"),"e value$")][@xml:lang="no"][preceding-sibling::*[position() = 3]][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::theta[preceding-sibling::*[position() = 5]]/sigma[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[contains(@object,"123456789")][@xml:id="id5"][not(following-sibling::*)][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <kappa data="solid 1px green" xml:lang="en-GB"> + <lambda insert="_blank" xml:lang="no"> + <sigma> + <epsilon token="true" xml:lang="no"> + <epsilon or="content"> + <delta xml:lang="en-US"> + <xi object="attribute value"/> + <beta true="attribute" xml:id="id1"/> + <delta object="_blank" xml:lang="no-nb" xml:id="id2"/> + <iota and="attribute value" xml:lang="no"/> + <zeta xml:lang="en-US" xml:id="id3"/> + <theta> + <sigma xml:lang="no-nb" xml:id="id4"> + <sigma xml:lang="no"> + <omicron object="123456789" xml:id="id5"> + <green>This text must be green</green> + </omicron> + </sigma> + </sigma> + </theta> + </delta> + </epsilon> + </epsilon> + </sigma> + </lambda> + </kappa> + </tree> + </test> + <test> + <xpath>//delta[@xml:id="id1"]/nu[@xml:id="id2"][not(following-sibling::*)]//omicron[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="en"][@xml:id="id4"][following-sibling::gamma[not(following-sibling::*)]//rho[starts-with(concat(@string,"-"),"this-")][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:lang="no"][@xml:id="id6"][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::omega[contains(concat(@object,"$"),"nk$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(following-sibling::omega)]/rho[not(child::node())][following-sibling::phi[@att="false"][@xml:lang="en"][@xml:id="id7"][following-sibling::pi[@xml:id="id8"]/zeta[contains(concat(@object,"$"),"e$")][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)]//kappa[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@true][@xml:lang="en-US"][not(child::node())][following-sibling::psi[@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(preceding-sibling::psi)][following-sibling::epsilon[not(child::node())][following-sibling::omega[contains(concat(@string,"$"),"100%$")][not(following-sibling::*)]]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:id="id1"> + <nu xml:id="id2"> + <omicron xml:id="id3"/> + <tau xml:lang="en" xml:id="id4"/> + <gamma> + <rho string="this-is-att-value" xml:lang="en" xml:id="id5"> + <lambda xml:lang="no" xml:id="id6"/> + <chi xml:lang="en-GB"/> + <omega object="_blank"> + <rho/> + <phi att="false" xml:lang="en" xml:id="id7"/> + <pi xml:id="id8"> + <zeta object="false" xml:lang="no" xml:id="id9"> + <kappa xml:lang="en-US"> + <theta true="solid 1px green" xml:lang="en-US"/> + <psi xml:lang="en-US" xml:id="id10"/> + <epsilon/> + <omega string="100%"> + <green>This text must be green</green> + </omega> + </kappa> + </zeta> + </pi> + </omega> + </rho> + </gamma> + </nu> + </delta> + </tree> + </test> + <test> + <xpath>//tau[starts-with(@delete,"_blank")][@xml:lang="no-nb"][@xml:id="id1"]//*[contains(concat(@title,"$"),"tt-value$")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)]//nu/tau[@attribute][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::iota[contains(@title,"e")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/epsilon[not(preceding-sibling::*)][not(following-sibling::*)]/zeta[contains(@attribute,"t")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[contains(concat(@att,"$"),"rue$")][@xml:id="id5"][not(child::node())][following-sibling::omega[starts-with(@attrib,"10")][@xml:lang="en-GB"][not(child::node())][following-sibling::*[not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 4]]/phi[contains(@false,"lid 1px")][following-sibling::mu[@class][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::alpha[starts-with(concat(@and,"-"),"attribute-")][@xml:id="id6"][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>1</nth> + </result> + <tree> + <tau delete="_blank" xml:lang="no-nb" xml:id="id1"> + <any title="this-is-att-value" xml:lang="en-GB" xml:id="id2"> + <nu> + <tau attribute="_blank" xml:lang="en" xml:id="id3"/> + <iota title="false" xml:lang="nb"> + <epsilon> + <zeta attribute="content" xml:lang="en-GB" xml:id="id4"/> + <theta att="true" xml:id="id5"/> + <omega attrib="100%" xml:lang="en-GB"/> + <any/> + <omicron> + <phi false="solid 1px green"/> + <mu class="this.nodeValue" xml:lang="en"/> + <alpha and="attribute" xml:id="id6"> + <green>This text must be green</green> + </alpha> + </omicron> + </epsilon> + </iota> + </nu> + </any> + </tau> + </tree> + </test> + <test> + <xpath>//alpha//mu[@content][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::phi[@token][not(child::node())][following-sibling::pi[@attr][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::alpha[contains(@content,"e")][@xml:lang="en-US"][@xml:id="id2"]/zeta[@xml:id="id3"][not(following-sibling::*)]//kappa[contains(concat(@title,"$"),"ttribute value$")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::delta[starts-with(concat(@desciption,"-"),"attribute-")][preceding-sibling::*[position() = 1]][following-sibling::chi[contains(concat(@token,"$"),"alue$")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@attr][@xml:lang="en-US"][preceding-sibling::*[position() = 3]]/omicron[contains(concat(@and,"$"),"blank$")][@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <alpha> + <mu content="100%" xml:id="id1"/> + <phi token="solid 1px green"/> + <pi attr="this.nodeValue" xml:lang="en-US"/> + <alpha content="false" xml:lang="en-US" xml:id="id2"> + <zeta xml:id="id3"> + <kappa title="attribute value" xml:lang="no" xml:id="id4"/> + <delta desciption="attribute-value"/> + <chi token="attribute value"/> + <psi attr="this-is-att-value" xml:lang="en-US"> + <omicron and="_blank" xml:lang="no-nb" xml:id="id5"> + <green>This text must be green</green> + </omicron> + </psi> + </zeta> + </alpha> + </alpha> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:id="id1"]//omicron[@true][@xml:lang="en-GB"][not(following-sibling::*)]//alpha[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]//theta[@string="solid 1px green"][@xml:lang="nb"][@xml:id="id3"][not(child::node())][following-sibling::beta[@desciption][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[@attr][following-sibling::pi[@xml:lang="en"][preceding-sibling::*[position() = 3]]/psi[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::gamma[@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::psi[@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::lambda[@xml:id="id8"][preceding-sibling::*[position() = 3]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:id="id1"> + <omicron true="content" xml:lang="en-GB"> + <alpha xml:lang="nb" xml:id="id2"> + <theta string="solid 1px green" xml:lang="nb" xml:id="id3"/> + <beta desciption="_blank" xml:lang="nb" xml:id="id4"/> + <phi attr="true"/> + <pi xml:lang="en"> + <psi xml:lang="en-US" xml:id="id5"/> + <gamma xml:id="id6"/> + <psi xml:id="id7"/> + <lambda xml:id="id8"> + <green>This text must be green</green> + </lambda> + </pi> + </alpha> + </omicron> + </upsilon> + </tree> + </test> + <test> + <xpath>//iota//omega[contains(@src,"ibute value")][@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::gamma[@xml:id="id2"][preceding-sibling::*[position() = 1]]/epsilon//omega[@xml:lang="no"]//nu/lambda[@object="content"][@xml:id="id3"][not(following-sibling::*)]//omega[@xml:lang="en"][not(child::node())][following-sibling::eta[starts-with(concat(@number,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::rho[@delete][@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <iota> + <omega src="another attribute value" xml:lang="no-nb" xml:id="id1"/> + <gamma xml:id="id2"> + <epsilon> + <omega xml:lang="no"> + <nu> + <lambda object="content" xml:id="id3"> + <omega xml:lang="en"/> + <eta number="solid 1px green"/> + <delta token="attribute" xml:lang="en-US" xml:id="id4"/> + <rho delete="attribute value" xml:lang="no"> + <green>This text must be green</green> + </rho> + </lambda> + </nu> + </omega> + </epsilon> + </gamma> + </iota> + </tree> + </test> + <test> + <xpath>//upsilon[contains(@insert,"alue")][@xml:lang="no"][@xml:id="id1"]/alpha[@token][@xml:lang="nb"][@xml:id="id2"]/*[@xml:lang="en-GB"][not(following-sibling::*)]/mu[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]//pi[contains(concat(@object,"$"),"ribute-value$")][@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/mu[@or][@xml:lang="en-GB"][@xml:id="id5"][following-sibling::sigma[@token][preceding-sibling::*[position() = 1]]/beta[@xml:lang="no"]/delta[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::delta[starts-with(concat(@delete,"-"),"another attribute value-")][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::pi[following-sibling::*[position()=1]][following-sibling::epsilon[contains(concat(@string,"$"),"tribute$")][@xml:id="id7"][preceding-sibling::*[position() = 3]]//theta[contains(concat(@false,"$"),"een$")]//*[@name="_blank"][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>1</nth> + </result> + <tree> + <upsilon insert="this-is-att-value" xml:lang="no" xml:id="id1"> + <alpha token="false" xml:lang="nb" xml:id="id2"> + <any xml:lang="en-GB"> + <mu xml:lang="en-US" xml:id="id3"> + <pi object="attribute-value" xml:lang="no-nb" xml:id="id4"> + <mu or="content" xml:lang="en-GB" xml:id="id5"/> + <sigma token="false"> + <beta xml:lang="no"> + <delta/> + <delta delete="another attribute value" xml:id="id6"/> + <pi/> + <epsilon string="attribute" xml:id="id7"> + <theta false="solid 1px green"> + <any name="_blank"> + <green>This text must be green</green> + </any> + </theta> + </epsilon> + </beta> + </sigma> + </pi> + </mu> + </any> + </alpha> + </upsilon> + </tree> + </test> + <test> + <xpath>//chi[contains(concat(@insert,"$"),"ttribute$")][@xml:lang="nb"][@xml:id="id1"]//delta[@xml:id="id2"][not(preceding-sibling::*)]/beta[@insert][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/chi[@xml:lang="nb"][@xml:id="id4"][following-sibling::delta[following-sibling::*[position()=3]][following-sibling::*[@false][@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::theta[@xml:lang="no"][not(child::node())][following-sibling::beta[@xml:id="id6"][preceding-sibling::*[position() = 4]]//rho[@xml:id="id7"][not(preceding-sibling::*)][not(parent::*/*[position()=2])][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>1</nth> + </result> + <tree> + <chi insert="attribute" xml:lang="nb" xml:id="id1"> + <delta xml:id="id2"> + <beta insert="another attribute value" xml:lang="no-nb" xml:id="id3"> + <chi xml:lang="nb" xml:id="id4"/> + <delta/> + <any false="attribute" xml:lang="en-US" xml:id="id5"/> + <theta xml:lang="no"/> + <beta xml:id="id6"> + <rho xml:id="id7"> + <green>This text must be green</green> + </rho> + </beta> + </beta> + </delta> + </chi> + </tree> + </test> + <test> + <xpath>//psi[@data][@xml:lang="en-US"]//iota[@xml:lang="nb"][not(following-sibling::*)]//*[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[@title][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="en"][preceding-sibling::*[position() = 1]]//iota[@title][not(preceding-sibling::*)]//sigma[not(preceding-sibling::*)]//iota[@desciption="_blank"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::lambda[starts-with(@abort,"attrib")][@xml:id="id5"][not(following-sibling::*)]/omega[@content][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::omicron[@abort="content"][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <psi data="attribute-value" xml:lang="en-US"> + <iota xml:lang="nb"> + <any xml:id="id1"/> + <delta xml:id="id2"> + <eta title="attribute-value"> + <upsilon xml:id="id3"/> + <rho xml:lang="en"> + <iota title="100%"> + <sigma> + <iota desciption="_blank" xml:id="id4"/> + <lambda abort="attribute value" xml:id="id5"> + <omega content="this.nodeValue" xml:lang="en-GB"/> + <omicron abort="content" xml:lang="en"> + <green>This text must be green</green> + </omicron> + </lambda> + </sigma> + </iota> + </rho> + </eta> + </delta> + </iota> + </psi> + </tree> + </test> + <test> + <xpath>//eta[@false="123456789"][@xml:lang="no-nb"][@xml:id="id1"]/zeta[@xml:id="id2"][not(preceding-sibling::*)]/gamma[@xml:id="id3"]//beta[starts-with(@title,"attr")][following-sibling::xi[contains(@att,"on")][@xml:id="id4"][not(child::node())][following-sibling::sigma[@and][@xml:id="id5"][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/xi[not(following-sibling::*)]/omicron[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta false="123456789" xml:lang="no-nb" xml:id="id1"> + <zeta xml:id="id2"> + <gamma xml:id="id3"> + <beta title="attribute"/> + <xi att="content" xml:id="id4"/> + <sigma and="this-is-att-value" xml:id="id5"/> + <zeta xml:lang="en-GB" xml:id="id6"> + <xi> + <omicron> + <green>This text must be green</green> + </omicron> + </xi> + </zeta> + </gamma> + </zeta> + </eta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]//psi[not(preceding-sibling::*)]/pi[not(preceding-sibling::*)]//nu[contains(@src,"ode")][@xml:id="id2"][not(following-sibling::*)]//delta[@xml:lang="en-US"][not(preceding-sibling::delta)][following-sibling::iota[starts-with(concat(@desciption,"-"),"100%-")][@xml:lang="en-US"][@xml:id="id3"][following-sibling::xi[@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="nb"][preceding-sibling::*[position() = 3]]/gamma[@string="attribute value"][@xml:lang="en"][not(preceding-sibling::*)]//theta[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/eta[@abort][@xml:id="id5"][following-sibling::*[position()=4]][not(child::node())][following-sibling::omicron[@false="this.nodeValue"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="nb"][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:lang="nb"][following-sibling::pi[@delete][@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//xi[starts-with(concat(@number,"-"),"_blank-")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <psi> + <pi> + <nu src="this.nodeValue" xml:id="id2"> + <delta xml:lang="en-US"/> + <iota desciption="100%" xml:lang="en-US" xml:id="id3"/> + <xi xml:lang="en"/> + <omicron xml:lang="nb"> + <gamma string="attribute value" xml:lang="en"> + <theta xml:lang="no-nb" xml:id="id4"> + <eta abort="attribute" xml:id="id5"/> + <omicron false="this.nodeValue"/> + <omicron xml:lang="nb" xml:id="id6"/> + <iota xml:lang="nb"/> + <pi delete="this-is-att-value" xml:lang="no" xml:id="id7"> + <xi number="_blank"> + <green>This text must be green</green> + </xi> + </pi> + </theta> + </gamma> + </omicron> + </nu> + </pi> + </psi> + </sigma> + </tree> + </test> + <test> + <xpath>//lambda//kappa[@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::omega[@xml:lang="no"][following-sibling::*[position()=7]][following-sibling::zeta[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::omicron[contains(concat(@title,"$"),"0%$")][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::delta[@object][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::iota[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::beta[@xml:id="id6"][following-sibling::upsilon[@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 7]][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 8]]/kappa[@and][@xml:id="id8"][following-sibling::beta[@class]//mu[following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@attribute][@xml:lang="no-nb"][@xml:id="id9"][following-sibling::delta[@class][@xml:lang="no"][preceding-sibling::*[position() = 2]]//gamma[starts-with(@object,"soli")][@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[contains(concat(@and,"$"),"nt$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//tau[@class]/nu/epsilon[@or="content"][@xml:lang="no-nb"][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <kappa xml:lang="no-nb" xml:id="id1"/> + <omega xml:lang="no"/> + <zeta xml:lang="nb" xml:id="id2"/> + <omicron title="100%" xml:lang="en-GB" xml:id="id3"/> + <delta object="this.nodeValue" xml:id="id4"/> + <iota xml:lang="en-US" xml:id="id5"/> + <beta xml:id="id6"/> + <upsilon xml:lang="en" xml:id="id7"/> + <sigma> + <kappa and="this-is-att-value" xml:id="id8"/> + <beta class="content"> + <mu/> + <mu attribute="solid 1px green" xml:lang="no-nb" xml:id="id9"/> + <delta class="false" xml:lang="no"> + <gamma object="solid 1px green" xml:lang="no-nb" xml:id="id10"> + <theta xml:id="id11"/> + <zeta and="content" xml:lang="en-US"> + <tau class="100%"> + <nu> + <epsilon or="content" xml:lang="no-nb"> + <green>This text must be green</green> + </epsilon> + </nu> + </tau> + </zeta> + </gamma> + </delta> + </beta> + </sigma> + </lambda> + </tree> + </test> + <test> + <xpath>//psi[contains(@attribute,"alue")][@xml:id="id1"]//eta[@class="content"][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::zeta[@object][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[contains(@title,"0%")][@xml:lang="no"][@xml:id="id2"]//nu[starts-with(concat(@string,"-"),"100%-")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[contains(concat(@att,"$"),"e$")][@xml:lang="no"][@xml:id="id4"]/omega[starts-with(@content,"attribute-va")][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)]/beta[@xml:lang="nb"][not(preceding-sibling::*)]/tau[@delete="_blank"][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[not(child::node())][following-sibling::alpha[@attr][following-sibling::*[position()=3]][following-sibling::pi[starts-with(concat(@attrib,"-"),"false-")][@xml:lang="no-nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id7"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <psi attribute="this.nodeValue" xml:id="id1"> + <eta class="content" xml:lang="no"/> + <zeta object="attribute"> + <chi title="100%" xml:lang="no" xml:id="id2"> + <nu string="100%" xml:id="id3"> + <iota att="attribute-value" xml:lang="no" xml:id="id4"> + <omega content="attribute-value" xml:lang="en-US" xml:id="id5"> + <beta xml:lang="nb"> + <tau delete="_blank" xml:lang="en-GB" xml:id="id6"/> + <gamma/> + <alpha attr="solid 1px green"/> + <pi attrib="false" xml:lang="no-nb"/> + <iota xml:lang="no"/> + <lambda xml:id="id7"> + <green>This text must be green</green> + </lambda> + </beta> + </omega> + </iota> + </nu> + </chi> + </zeta> + </psi> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(@name,"true")][@xml:lang="en-GB"][@xml:id="id1"]/mu[starts-with(@src,"_blank")][not(preceding-sibling::mu)][following-sibling::mu[@xml:lang="nb"][not(following-sibling::*)]/tau[@delete="content"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::phi[preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][following-sibling::chi[@xml:lang="no-nb"][following-sibling::*[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::theta[@true][@xml:id="id3"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::sigma[contains(@desciption,"deVal")][@xml:lang="no-nb"][following-sibling::iota[@xml:id="id4"]/epsilon[@attr][@xml:lang="en"][not(preceding-sibling::*)]//nu[not(following-sibling::*)]//delta[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::psi[@xml:id="id6"][preceding-sibling::*[position() = 1]]/gamma[@xml:lang="en-GB"]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon name="true" xml:lang="en-GB" xml:id="id1"> + <mu src="_blank"/> + <mu xml:lang="nb"> + <tau delete="content" xml:lang="no-nb"/> + <phi/> + <chi xml:lang="no-nb"/> + <any xml:lang="nb" xml:id="id2"/> + <theta true="another attribute value" xml:id="id3"/> + <sigma desciption="this.nodeValue" xml:lang="no-nb"/> + <iota xml:id="id4"> + <epsilon attr="this.nodeValue" xml:lang="en"> + <nu> + <delta xml:id="id5"/> + <psi xml:id="id6"> + <gamma xml:lang="en-GB"> + <green>This text must be green</green> + </gamma> + </psi> + </nu> + </epsilon> + </iota> + </mu> + </upsilon> + </tree> + </test> + <test> + <xpath>//omega[@false][@xml:id="id1"]/omicron[@xml:lang="nb"][@xml:id="id2"]//alpha[@attr][@xml:lang="no"]//lambda[@att][@xml:lang="nb"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[starts-with(concat(@true,"-"),"attribute-")][@xml:id="id4"][preceding-sibling::*[position() = 1]]/eta[contains(@or,"e")][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:lang="no"][not(following-sibling::*)]//tau[not(preceding-sibling::*)]/lambda[@src][@xml:lang="nb"][following-sibling::eta[contains(concat(@false,"$"),"e$")][@xml:id="id5"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <omega false="content" xml:id="id1"> + <omicron xml:lang="nb" xml:id="id2"> + <alpha attr="content" xml:lang="no"> + <lambda att="_blank" xml:lang="nb" xml:id="id3"/> + <omicron true="attribute-value" xml:id="id4"> + <eta or="attribute"> + <kappa xml:lang="no"> + <tau> + <lambda src="another attribute value" xml:lang="nb"/> + <eta false="this-is-att-value" xml:id="id5"> + <green>This text must be green</green> + </eta> + </tau> + </kappa> + </eta> + </omicron> + </alpha> + </omicron> + </omega> + </tree> + </test> + <test> + <xpath>//eta[@xml:id="id1"]/eta[@string][not(preceding-sibling::*)]//tau[@xml:id="id2"][not(child::node())][following-sibling::omicron[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=6]][not(child::node())][following-sibling::alpha[starts-with(concat(@class,"-"),"this-")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::phi[starts-with(concat(@desciption,"-"),"this.nodeValue-")][preceding-sibling::*[position() = 3]][following-sibling::*[position()=4]][following-sibling::phi[@and][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::iota[contains(concat(@number,"$"),"nk$")][@xml:lang="no"][preceding-sibling::*[position() = 5]][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 6]][not(child::node())][following-sibling::*[@and][@xml:lang="en-US"][preceding-sibling::*[position() = 7]][not(following-sibling::*)]/iota[not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id5"][following-sibling::theta[@name][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@attrib][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::eta[@name][@xml:lang="en-US"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::tau[starts-with(@data,"another attribute")][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]/mu[not(preceding-sibling::*)][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[@xml:lang="en-US"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:id="id1"> + <eta string="123456789"> + <tau xml:id="id2"/> + <omicron xml:lang="en"/> + <alpha class="this-is-att-value" xml:lang="no" xml:id="id3"/> + <phi desciption="this.nodeValue"/> + <phi and="attribute" xml:lang="no" xml:id="id4"/> + <iota number="_blank" xml:lang="no"/> + <omega xml:lang="en-GB"/> + <any and="100%" xml:lang="en-US"> + <iota/> + <iota xml:id="id5"/> + <theta name="content"/> + <iota attrib="this.nodeValue"/> + <eta name="solid 1px green" xml:lang="en-US"/> + <tau data="another attribute value" xml:lang="no" xml:id="id6"> + <mu/> + <rho> + <iota xml:lang="en-US"> + <green>This text must be green</green> + </iota> + </rho> + </tau> + </any> + </eta> + </eta> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="nb"][@xml:id="id1"]//theta[starts-with(concat(@false,"-"),"solid 1px green-")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@xml:lang="en"][not(child::node())][following-sibling::gamma[@src][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[@xml:lang="en-GB"][not(child::node())][following-sibling::rho[following-sibling::gamma[@xml:lang="en"][preceding-sibling::*[position() = 2]]/kappa[starts-with(@data,"this-is-a")][@xml:lang="en-US"][@xml:id="id4"]//kappa[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@name][not(preceding-sibling::*)][following-sibling::nu[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::delta[@token][@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 2]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="nb" xml:id="id1"> + <theta false="solid 1px green" xml:id="id2"> + <nu xml:lang="en"/> + <gamma src="content" xml:id="id3"> + <sigma xml:lang="en-GB"/> + <rho/> + <gamma xml:lang="en"> + <kappa data="this-is-att-value" xml:lang="en-US" xml:id="id4"> + <kappa xml:lang="en"> + <sigma name="content"/> + <nu xml:id="id5"/> + <delta token="true" xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </delta> + </kappa> + </kappa> + </gamma> + </gamma> + </theta> + </iota> + </tree> + </test> + <test> + <xpath>//theta/omega[starts-with(@abort,"fal")][not(following-sibling::*)]//rho[@xml:lang="en-GB"][following-sibling::*[position()=4]][following-sibling::sigma[@name="100%"][@xml:lang="en"][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::phi[@xml:lang="en"][@xml:id="id1"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::upsilon[@xml:id="id2"][preceding-sibling::*[position() = 4]][not(following-sibling::*)][not(preceding-sibling::upsilon)]//kappa[@xml:id="id3"][following-sibling::beta[contains(concat(@string,"$"),"ontent$")][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@data="true"][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//lambda[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="nb"][not(following-sibling::*)]//delta[starts-with(concat(@data,"-"),"true-")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::gamma[@xml:id="id7"][following-sibling::pi[starts-with(@content,"12")][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/rho[@xml:lang="en-GB"][@xml:id="id9"]/kappa[@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]]]]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <theta> + <omega abort="false"> + <rho xml:lang="en-GB"/> + <sigma name="100%" xml:lang="en"/> + <rho xml:lang="en-GB"/> + <phi xml:lang="en" xml:id="id1"/> + <upsilon xml:id="id2"> + <kappa xml:id="id3"/> + <beta string="content" xml:id="id4"/> + <theta data="true" xml:lang="en-GB"> + <lambda xml:lang="no-nb" xml:id="id5"/> + <xi xml:lang="nb"> + <delta data="true" xml:id="id6"> + <tau xml:lang="en"/> + <gamma xml:id="id7"/> + <pi content="123456789" xml:lang="no-nb"/> + <eta xml:lang="en-GB" xml:id="id8"> + <rho xml:lang="en-GB" xml:id="id9"> + <kappa xml:lang="no-nb" xml:id="id10"> + <green>This text must be green</green> + </kappa> + </rho> + </eta> + </delta> + </xi> + </theta> + </upsilon> + </omega> + </theta> + </tree> + </test> + <test> + <xpath>//delta[@xml:id="id1"]/pi[contains(concat(@att,"$"),"e$")][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[not(preceding-sibling::*)][not(parent::*/*[position()=2])]/zeta[starts-with(concat(@attr,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@xml:id="id4"][not(following-sibling::*)]//nu[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[starts-with(concat(@false,"-"),"solid 1px green-")][@xml:lang="no"][@xml:id="id5"]//gamma[@or][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[starts-with(concat(@true,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:id="id1"> + <pi att="true"/> + <kappa xml:id="id2"> + <pi> + <zeta attr="123456789" xml:lang="en-US" xml:id="id3"> + <gamma xml:id="id4"> + <nu xml:lang="en-GB"/> + <upsilon false="solid 1px green" xml:lang="no" xml:id="id5"> + <gamma or="true"/> + <nu true="this.nodeValue" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </nu> + </upsilon> + </gamma> + </zeta> + </pi> + </kappa> + </delta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]//eta[contains(concat(@content,"$"),"olid 1px green$")][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::epsilon[@data][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[starts-with(concat(@content,"-"),"true-")][@xml:id="id3"]//nu[@xml:lang="no-nb"][not(child::node())][following-sibling::omega[@attr="123456789"][@xml:lang="en-GB"][not(child::node())][following-sibling::pi[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="no"][not(following-sibling::*)]//zeta[@xml:id="id5"][not(following-sibling::*)]/lambda[@name][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::*[@content][preceding-sibling::*[position() = 2]][not(following-sibling::any)]//epsilon[@attr][@xml:id="id6"][not(child::node())][following-sibling::nu[contains(concat(@attr,"$"),"_blank$")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::nu)]/*[starts-with(concat(@false,"-"),"attribute value-")][@xml:lang="en-GB"][not(preceding-sibling::*)]//eta[starts-with(@src,"thi")][@xml:lang="nb"][not(preceding-sibling::*)]/sigma[@xml:lang="en"][not(child::node())][following-sibling::pi[contains(concat(@attribute,"$"),"bute$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id8"][preceding-sibling::*[position() = 2]]//epsilon[not(preceding-sibling::*)]//rho[contains(concat(@title,"$"),"true$")][@xml:id="id9"][not(following-sibling::*)]/epsilon[@xml:lang="en-GB"][@xml:id="id10"][following-sibling::pi[@xml:id="id11"]/epsilon[@xml:id="id12"]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <eta content="solid 1px green" xml:lang="no" xml:id="id2"/> + <epsilon data="another attribute value" xml:lang="nb"/> + <delta content="true" xml:id="id3"> + <nu xml:lang="no-nb"/> + <omega attr="123456789" xml:lang="en-GB"/> + <pi xml:id="id4"/> + <lambda xml:lang="no"> + <zeta xml:id="id5"> + <lambda name="another attribute value"/> + <epsilon xml:lang="no-nb"/> + <any content="another attribute value"> + <epsilon attr="solid 1px green" xml:id="id6"/> + <nu attr="_blank" xml:lang="no" xml:id="id7"> + <any false="attribute value" xml:lang="en-GB"> + <eta src="this-is-att-value" xml:lang="nb"> + <sigma xml:lang="en"/> + <pi attribute="attribute"/> + <lambda xml:id="id8"> + <epsilon> + <rho title="true" xml:id="id9"> + <epsilon xml:lang="en-GB" xml:id="id10"/> + <pi xml:id="id11"> + <epsilon xml:id="id12"> + <green>This text must be green</green> + </epsilon> + </pi> + </rho> + </epsilon> + </lambda> + </eta> + </any> + </nu> + </any> + </zeta> + </lambda> + </delta> + </sigma> + </tree> + </test> + <test> + <xpath>//delta[contains(concat(@att,"$")," 1px green$")][@xml:lang="no"][@xml:id="id1"]/omicron[@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@delete][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[@xml:lang="nb"][not(parent::*/*[position()=2])]/kappa[contains(@desciption,"deV")][not(preceding-sibling::*)][following-sibling::rho[contains(concat(@object,"$"),"nk$")][preceding-sibling::*[position() = 1]][following-sibling::theta[@true="_blank"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <delta att="solid 1px green" xml:lang="no" xml:id="id1"> + <omicron xml:lang="en"/> + <mu delete="this.nodeValue" xml:id="id2"> + <epsilon xml:lang="nb"> + <kappa desciption="this.nodeValue"/> + <rho object="_blank"/> + <theta true="_blank"> + <theta xml:lang="nb" xml:id="id3"> + <green>This text must be green</green> + </theta> + </theta> + </epsilon> + </mu> + </delta> + </tree> + </test> + <test> + <xpath>//beta[contains(@delete,"lue")]/nu[not(preceding-sibling::*)]/delta[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[contains(concat(@att,"$"),".nodeValue$")][following-sibling::psi[@xml:id="id2"]//tau[@xml:lang="nb"]/rho[starts-with(concat(@token,"-"),"true-")][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 1]]//upsilon[@name="attribute value"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[starts-with(concat(@attribute,"-"),"_blank-")][not(following-sibling::*)]//xi[contains(@and,"ttribute ")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][following-sibling::iota[starts-with(@and,"100")][@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]//tau[@number][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="en-GB"][not(child::node())][following-sibling::iota[@and][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[@xml:id="id5"]/phi[starts-with(concat(@title,"-"),"_blank-")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id7"][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <beta delete="attribute value"> + <nu> + <delta xml:id="id1"> + <psi att="this.nodeValue"/> + <psi xml:id="id2"> + <tau xml:lang="nb"> + <rho token="true"/> + <kappa> + <upsilon name="attribute value"/> + <xi attribute="_blank"> + <xi and="another attribute value" xml:lang="no"/> + <nu xml:lang="en-GB"/> + <iota and="100%" xml:lang="en"/> + <nu xml:lang="en-GB" xml:id="id3"> + <tau number="solid 1px green" xml:lang="no-nb" xml:id="id4"> + <omicron xml:lang="en-GB"/> + <iota and="this.nodeValue" xml:lang="no"/> + <tau xml:id="id5"> + <phi title="_blank" xml:lang="nb" xml:id="id6"/> + <alpha xml:id="id7"> + <green>This text must be green</green> + </alpha> + </tau> + </tau> + </nu> + </xi> + </kappa> + </tau> + </psi> + </delta> + </nu> + </beta> + </tree> + </test> + <test> + <xpath>//gamma[@or][@xml:lang="en"]//nu[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[starts-with(concat(@object,"-"),"solid 1px green-")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[contains(concat(@string,"$")," green$")][following-sibling::kappa[@xml:lang="nb"][@xml:id="id3"][following-sibling::eta[starts-with(@token,"another")][@xml:id="id4"][following-sibling::*[position()=3]][following-sibling::nu[contains(@false,"te-value")][preceding-sibling::*[position() = 3]][following-sibling::iota[preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::epsilon[contains(@attr,"olid 1px gre")][@xml:id="id5"][preceding-sibling::*[position() = 5]]/zeta[@true][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[contains(@abort,"t")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[@xml:id="id7"][following-sibling::omicron[@src][preceding-sibling::*[position() = 1]]//alpha[starts-with(concat(@title,"-"),"content-")][@xml:id="id8"][not(following-sibling::*)]//iota[@abort][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)]/alpha[starts-with(@string,"attribut")][@xml:lang="no-nb"][@xml:id="id10"]/kappa[not(child::node())][following-sibling::alpha[starts-with(@class,"123456789")][@xml:id="id11"]]]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>1</nth> + </result> + <tree> + <gamma or="false" xml:lang="en"> + <nu xml:lang="en-GB" xml:id="id1"> + <sigma object="solid 1px green" xml:lang="no-nb" xml:id="id2"> + <sigma string="solid 1px green"/> + <kappa xml:lang="nb" xml:id="id3"/> + <eta token="another attribute value" xml:id="id4"/> + <nu false="attribute-value"/> + <iota/> + <epsilon attr="solid 1px green" xml:id="id5"> + <zeta true="attribute-value"/> + <alpha abort="true" xml:id="id6"> + <xi xml:id="id7"/> + <omicron src="true"> + <alpha title="content" xml:id="id8"> + <iota abort="attribute"> + <upsilon xml:lang="no-nb" xml:id="id9"> + <alpha string="attribute" xml:lang="no-nb" xml:id="id10"> + <kappa/> + <alpha class="123456789" xml:id="id11"> + <green>This text must be green</green> + </alpha> + </alpha> + </upsilon> + </iota> + </alpha> + </omicron> + </alpha> + </epsilon> + </sigma> + </nu> + </gamma> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]/zeta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::kappa[starts-with(@and,"another att")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:id="id5"][following-sibling::psi[starts-with(concat(@token,"-"),"attribute-")][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::iota[following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[contains(concat(@content,"$"),"3456789$")][@xml:id="id7"][preceding-sibling::*[position() = 4]][following-sibling::rho[@xml:id="id8"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <zeta xml:id="id2"/> + <xi xml:lang="nb" xml:id="id3"/> + <kappa and="another attribute value" xml:lang="nb" xml:id="id4"> + <phi xml:lang="no-nb"/> + <tau xml:id="id5"/> + <psi token="attribute" xml:id="id6"/> + <iota/> + <tau content="123456789" xml:id="id7"/> + <rho xml:id="id8"> + <green>This text must be green</green> + </rho> + </kappa> + </alpha> + </tree> + </test> + <test> + <xpath>//eta[@attr="100%"][@xml:lang="en"]/chi[@string="attribute-value"][@xml:id="id1"][not(following-sibling::*)]/epsilon[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::gamma[contains(@attrib,"ttribut")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 2]]//nu[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@data][@xml:lang="no-nb"][not(following-sibling::*)]/xi[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]//xi[@xml:id="id3"][not(following-sibling::*)]/nu[contains(concat(@name,"$"),"true$")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <eta attr="100%" xml:lang="en"> + <chi string="attribute-value" xml:id="id1"> + <epsilon xml:lang="nb"/> + <gamma attrib="attribute" xml:lang="en"/> + <pi> + <nu xml:lang="nb"> + <iota xml:lang="nb"/> + <tau xml:lang="no"/> + <kappa data="attribute value" xml:lang="no-nb"> + <xi xml:lang="nb"/> + <lambda xml:lang="no" xml:id="id2"> + <xi xml:id="id3"> + <nu name="true" xml:lang="en-GB"> + <green>This text must be green</green> + </nu> + </xi> + </lambda> + </kappa> + </nu> + </pi> + </chi> + </eta> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="no-nb"]//theta[following-sibling::mu[starts-with(concat(@attr,"-"),"attribute-")][@xml:id="id1"][following-sibling::kappa[@xml:id="id2"][not(following-sibling::*)]//theta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//*[contains(concat(@data,"$"),"100%$")][@xml:id="id3"][not(child::node())][following-sibling::delta[@true="123456789"][preceding-sibling::*[position() = 1]]//epsilon[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::zeta/psi[@xml:lang="en-GB"]/kappa[not(preceding-sibling::*)][not(preceding-sibling::kappa)][not(child::node())][following-sibling::nu[starts-with(@abort,"_blan")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[contains(@false,"t")][not(preceding-sibling::*)][not(following-sibling::*)]/chi[following-sibling::omicron[@number="false"][preceding-sibling::*[position() = 1]]/tau[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omega[@class][@xml:lang="en"]//chi[@or][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)]//kappa[starts-with(concat(@or,"-"),"100%-")][@xml:id="id6"]//beta[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][position() = 1]]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="no-nb"> + <theta/> + <mu attr="attribute-value" xml:id="id1"/> + <kappa xml:id="id2"> + <theta xml:lang="en-GB"> + <any data="100%" xml:id="id3"/> + <delta true="123456789"> + <epsilon xml:lang="en-GB" xml:id="id4"/> + <zeta> + <psi xml:lang="en-GB"> + <kappa/> + <nu abort="_blank"> + <lambda false="content"> + <chi/> + <omicron number="false"> + <tau xml:lang="en"/> + <omega class="true" xml:lang="en"> + <chi or="123456789"/> + <eta xml:lang="no-nb" xml:id="id5"> + <kappa or="100%" xml:id="id6"> + <beta xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </beta> + </kappa> + </eta> + </omega> + </omicron> + </lambda> + </nu> + </psi> + </zeta> + </delta> + </theta> + </kappa> + </phi> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no-nb"][@xml:id="id1"]//epsilon[@xml:lang="en-GB"][not(following-sibling::*)]//upsilon[contains(@or,"f")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::tau[@object="123456789"][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[starts-with(concat(@delete,"-"),"123456789-")][@xml:lang="en"]//pi[starts-with(concat(@string,"-"),"false-")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@number][@xml:lang="en-GB"][@xml:id="id4"][not(following-sibling::*)]/nu[contains(concat(@class,"$"),"green$")][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[starts-with(@abort,"tr")][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[starts-with(@src,"at")][@xml:id="id7"][preceding-sibling::*[position() = 2]]/delta[contains(@or,"ute valu")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::upsilon[@object][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa//theta[not(following-sibling::*)]//theta[@xml:lang="no"][not(preceding-sibling::*)]/epsilon[@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[contains(@attrib,"e")][@xml:id="id10"][following-sibling::lambda[preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 2]][following-sibling::iota[not(child::node())][following-sibling::nu[@delete][preceding-sibling::*[position() = 4]][position() = 1]][position() = 1]]]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no-nb" xml:id="id1"> + <epsilon xml:lang="en-GB"> + <upsilon or="false" xml:lang="en-US"/> + <tau object="123456789" xml:lang="nb" xml:id="id2"/> + <any delete="123456789" xml:lang="en"> + <pi string="false" xml:id="id3"/> + <alpha number="100%" xml:lang="en-GB" xml:id="id4"> + <nu class="solid 1px green"> + <eta xml:id="id5"> + <nu abort="true" xml:id="id6"/> + <mu xml:lang="no"/> + <delta src="attribute value" xml:id="id7"> + <delta or="attribute value" xml:lang="en-US"/> + <upsilon object="attribute-value" xml:id="id8"> + <kappa> + <theta> + <theta xml:lang="no"> + <epsilon xml:lang="no" xml:id="id9"> + <gamma attrib="attribute value" xml:id="id10"/> + <lambda/> + <kappa/> + <iota/> + <nu delete="false"> + <green>This text must be green</green> + </nu> + </epsilon> + </theta> + </theta> + </kappa> + </upsilon> + </delta> + </eta> + </nu> + </alpha> + </any> + </epsilon> + </lambda> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en-GB"][@xml:id="id1"]//gamma[@xml:id="id2"][not(preceding-sibling::*)]//kappa[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]/nu[@name="123456789"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@att][following-sibling::gamma[@att][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[starts-with(@or,"attribute")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]//gamma[@xml:id="id5"]//theta[@xml:id="id6"][not(preceding-sibling::*)]/rho[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::nu[starts-with(@content,"another attribute value")][preceding-sibling::*[position() = 1]]/upsilon[@true="100%"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta//alpha[@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]//theta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[starts-with(@class,"fal")][@xml:id="id10"][not(preceding-sibling::*)]//alpha[contains(concat(@src,"$"),"alse$")][@xml:id="id11"][following-sibling::tau[@xml:lang="no"][@xml:id="id12"]/omega[not(following-sibling::*)]//alpha[contains(concat(@attribute,"$"),"content$")][@xml:lang="en"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="en-GB" xml:id="id1"> + <gamma xml:id="id2"> + <kappa xml:lang="no" xml:id="id3"> + <nu name="123456789"> + <theta att="attribute-value"/> + <gamma att="_blank" xml:lang="no" xml:id="id4"/> + <alpha or="attribute" xml:lang="en-GB"> + <gamma xml:id="id5"> + <theta xml:id="id6"> + <rho xml:id="id7"/> + <nu content="another attribute value"> + <upsilon true="100%" xml:lang="no-nb"/> + <delta> + <alpha xml:id="id8"/> + <sigma xml:lang="en-US" xml:id="id9"> + <theta xml:lang="no-nb"> + <omicron class="false" xml:id="id10"> + <alpha src="false" xml:id="id11"/> + <tau xml:lang="no" xml:id="id12"> + <omega> + <alpha attribute="content" xml:lang="en"> + <green>This text must be green</green> + </alpha> + </omega> + </tau> + </omicron> + </theta> + </sigma> + </delta> + </nu> + </theta> + </gamma> + </alpha> + </nu> + </kappa> + </gamma> + </psi> + </tree> + </test> + <test> + <xpath>//gamma[@xml:lang="nb"][@xml:id="id1"]//epsilon[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)]//nu[@and="false"][not(preceding-sibling::*)][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@attr][following-sibling::*[position()=2]][following-sibling::chi[@src="_blank"][not(child::node())][following-sibling::chi[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]/chi[@insert="content"][@xml:lang="no"][@xml:id="id3"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:lang="nb" xml:id="id1"> + <epsilon xml:lang="no-nb" xml:id="id2"> + <nu and="false"/> + <chi> + <nu attr="_blank"/> + <chi src="_blank"/> + <chi xml:lang="en-US"> + <chi insert="content" xml:lang="no" xml:id="id3"> + <green>This text must be green</green> + </chi> + </chi> + </chi> + </epsilon> + </gamma> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="nb"][@xml:id="id1"]//beta[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[not(preceding-sibling::*)][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="en"][not(child::node())][following-sibling::beta[@token][@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//delta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(concat(@abort,"$"),"e$")][@xml:lang="nb"]/epsilon[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::psi[starts-with(@desciption,"tr")][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::tau[starts-with(@object,"attribute")][@xml:id="id5"][preceding-sibling::*[position() = 3]]//omicron[@or][@xml:lang="no-nb"][not(preceding-sibling::*)][not(preceding-sibling::omicron)]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="nb" xml:id="id1"> + <beta xml:lang="en" xml:id="id2"/> + <sigma xml:lang="en-GB"> + <kappa/> + <any/> + <mu xml:lang="en"/> + <beta token="another attribute value" xml:lang="no"> + <delta xml:lang="en-GB"> + <rho abort="attribute value" xml:lang="nb"> + <epsilon xml:lang="en-GB"/> + <beta xml:id="id3"/> + <psi desciption="true" xml:lang="en-GB" xml:id="id4"/> + <tau object="attribute-value" xml:id="id5"> + <omicron or="this-is-att-value" xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </tau> + </rho> + </delta> + </beta> + </sigma> + </nu> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="no"][@xml:id="id1"]/pi[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::tau[@insert][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[@abort="_blank"][@xml:lang="no"][not(child::node())][following-sibling::chi[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[contains(@true,"another attribute")][not(following-sibling::*)]//sigma[@xml:id="id4"][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 1]]//rho[not(preceding-sibling::*)][following-sibling::phi[@xml:id="id5"][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id6"]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="no" xml:id="id1"> + <pi xml:lang="no-nb" xml:id="id2"/> + <tau insert="123456789" xml:lang="no-nb"/> + <eta abort="_blank" xml:lang="no"/> + <chi xml:lang="en-US" xml:id="id3"/> + <epsilon true="another attribute value"> + <sigma xml:id="id4"/> + <lambda> + <rho/> + <phi xml:id="id5"/> + <omicron xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </lambda> + </epsilon> + </alpha> + </tree> + </test> + <test> + <xpath>//phi/epsilon[@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]//iota[@xml:id="id2"][not(following-sibling::*)]/beta[@attrib][@xml:id="id3"][not(preceding-sibling::*)]//lambda[@data="attribute"][@xml:lang="nb"][not(preceding-sibling::*)]/epsilon[starts-with(concat(@string,"-"),"false-")][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)]/xi[@or][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[starts-with(concat(@content,"-"),"123456789-")][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//kappa[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(@att,"10")][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no"][@xml:id="id7"]/upsilon[@content][@xml:lang="no-nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[@and="100%"][following-sibling::*[position()=1]][following-sibling::nu[preceding-sibling::*[position() = 2]]/omicron[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@name="this-is-att-value"][@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]/nu[contains(concat(@and,"$"),"te value$")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id10"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>1</nth> + </result> + <tree> + <phi> + <epsilon xml:lang="en-GB" xml:id="id1"> + <iota xml:id="id2"> + <beta attrib="100%" xml:id="id3"> + <lambda data="attribute" xml:lang="nb"> + <epsilon string="false" xml:lang="nb" xml:id="id4"> + <xi or="_blank"> + <lambda content="123456789" xml:lang="no"/> + <epsilon xml:lang="nb" xml:id="id5"> + <kappa xml:id="id6"> + <psi att="100%"/> + <iota xml:lang="no" xml:id="id7"> + <upsilon content="content" xml:lang="no-nb"/> + <beta and="100%"/> + <nu> + <omicron xml:lang="no-nb" xml:id="id8"> + <theta name="this-is-att-value" xml:lang="en" xml:id="id9"> + <nu and="attribute value" xml:lang="en-GB"> + <beta xml:id="id10"> + <green>This text must be green</green> + </beta> + </nu> + </theta> + </omicron> + </nu> + </iota> + </kappa> + </epsilon> + </xi> + </epsilon> + </lambda> + </beta> + </iota> + </epsilon> + </phi> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@attribute,"$"),"9$")][@xml:lang="nb"]//xi[@xml:id="id1"][following-sibling::*[position()=5]][not(child::node())][following-sibling::pi[@xml:lang="en"][not(child::node())][following-sibling::upsilon[@xml:lang="en"][following-sibling::iota[contains(@title,"lue")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::theta[starts-with(concat(@attribute,"-"),"attribute-")][@xml:id="id2"][preceding-sibling::*[position() = 4]][following-sibling::omega[contains(@delete,"9")][@xml:lang="en"][not(following-sibling::*)]/tau[@xml:lang="no"][not(preceding-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <beta attribute="123456789" xml:lang="nb"> + <xi xml:id="id1"/> + <pi xml:lang="en"/> + <upsilon xml:lang="en"/> + <iota title="this.nodeValue"/> + <theta attribute="attribute-value" xml:id="id2"/> + <omega delete="123456789" xml:lang="en"> + <tau xml:lang="no"> + <green>This text must be green</green> + </tau> + </omega> + </beta> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(concat(@name,"-"),"true-")]//beta[@xml:lang="en"][@xml:id="id1"][following-sibling::nu[contains(concat(@data,"$"),"attribute value$")][@xml:lang="no-nb"]//upsilon[contains(@number,"alue")][following-sibling::delta[@xml:lang="nb"][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id2"][following-sibling::chi[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[@attribute][@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::kappa[@abort="123456789"][@xml:lang="no-nb"][not(following-sibling::*)]//omega[@xml:lang="nb"][following-sibling::epsilon[not(following-sibling::*)]//omicron[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi//lambda[not(following-sibling::*)]]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <lambda name="true"> + <beta xml:lang="en" xml:id="id1"/> + <nu data="attribute value" xml:lang="no-nb"> + <upsilon number="attribute-value"/> + <delta xml:lang="nb"/> + <delta xml:lang="no-nb" xml:id="id2"/> + <chi xml:lang="en-GB"/> + <epsilon attribute="solid 1px green" xml:id="id3"/> + <kappa abort="123456789" xml:lang="no-nb"> + <omega xml:lang="nb"/> + <epsilon> + <omicron xml:lang="en"/> + <pi> + <lambda> + <green>This text must be green</green> + </lambda> + </pi> + </epsilon> + </kappa> + </nu> + </lambda> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en"][@xml:id="id1"]/kappa[@token][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]//iota[following-sibling::*[position()=1]][following-sibling::pi[@class][@xml:lang="nb"]/iota[starts-with(concat(@attribute,"-"),"content-")][@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/zeta[@xml:lang="en"][not(child::node())][following-sibling::epsilon[@content][not(following-sibling::*)]//lambda[@xml:id="id4"]/lambda[@name][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="nb"]/xi[@xml:id="id5"][not(following-sibling::*)]/iota[starts-with(@src,"100")][@xml:id="id6"][not(following-sibling::*)]/rho[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@insert][@xml:lang="no-nb"][@xml:id="id8"][not(child::node())][following-sibling::omicron[starts-with(concat(@name,"-"),"solid 1px green-")][@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en" xml:id="id1"> + <kappa token="attribute" xml:lang="nb"/> + <upsilon xml:lang="en-GB" xml:id="id2"> + <iota/> + <pi class="false" xml:lang="nb"> + <iota attribute="content" xml:lang="en" xml:id="id3"> + <zeta xml:lang="en"/> + <epsilon content="123456789"> + <lambda xml:id="id4"> + <lambda name="100%"/> + <theta xml:lang="nb"> + <xi xml:id="id5"> + <iota src="100%" xml:id="id6"> + <rho xml:lang="en-US" xml:id="id7"> + <nu insert="this.nodeValue" xml:lang="no-nb" xml:id="id8"/> + <omicron name="solid 1px green" xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </rho> + </iota> + </xi> + </theta> + </lambda> + </epsilon> + </iota> + </pi> + </upsilon> + </phi> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]//iota[contains(concat(@number,"$"),"odeValue$")][@xml:id="id2"]//iota[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@content][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[following-sibling::rho[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::iota[following-sibling::theta[@true][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 4]][following-sibling::xi[starts-with(concat(@content,"-"),"solid 1px green-")][@xml:lang="en-US"][not(child::node())][following-sibling::rho[contains(@content,"%")][@xml:id="id5"][not(child::node())][following-sibling::upsilon[@abort][@xml:id="id6"][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>2</nth> + </result> + <tree> + <sigma xml:id="id1"> + <iota number="this.nodeValue" xml:id="id2"> + <iota xml:id="id3"> + <iota content="attribute-value"/> + <delta/> + <rho xml:lang="en-US"/> + <iota/> + <theta true="_blank" xml:lang="nb" xml:id="id4"/> + <xi content="solid 1px green" xml:lang="en-US"/> + <rho content="100%" xml:id="id5"/> + <upsilon abort="false" xml:id="id6"> + <green>This text must be green</green> + </upsilon> + </iota> + </iota> + </sigma> + </tree> + </test> + <test> + <xpath>//iota[starts-with(concat(@or,"-"),"attribute value-")][@xml:id="id1"]/beta[not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:id="id2"]//nu[contains(@class,"e ")][@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//upsilon[not(following-sibling::*)]/tau[@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]//xi[@att="true"][@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="no"][@xml:id="id6"][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <iota or="attribute value" xml:id="id1"> + <beta/> + <lambda xml:id="id2"> + <nu class="attribute value" xml:lang="no" xml:id="id3"> + <upsilon> + <tau xml:lang="no" xml:id="id4"> + <xi att="true" xml:lang="no-nb" xml:id="id5"> + <rho xml:lang="no" xml:id="id6"> + <green>This text must be green</green> + </rho> + </xi> + </tau> + </upsilon> + </nu> + </lambda> + </iota> + </tree> + </test> + <test> + <xpath>//mu//alpha[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::theta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@title][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=4]][not(preceding-sibling::rho)][following-sibling::gamma[contains(concat(@att,"$"),"ute$")][@xml:lang="no-nb"][not(child::node())][following-sibling::tau[contains(@object,"b")][@xml:lang="en-US"][preceding-sibling::*[position() = 4]][following-sibling::zeta[@class][@xml:id="id4"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]//lambda[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <alpha xml:id="id1"/> + <theta xml:id="id2"/> + <rho title="solid 1px green" xml:lang="no" xml:id="id3"/> + <gamma att="attribute" xml:lang="no-nb"/> + <tau object="_blank" xml:lang="en-US"/> + <zeta class="attribute" xml:id="id4"/> + <omicron xml:lang="en-GB" xml:id="id5"> + <lambda xml:lang="nb"> + <green>This text must be green</green> + </lambda> + </omicron> + </mu> + </tree> + </test> + <test> + <xpath>//chi/tau[starts-with(@or,"this.nodeValu")][@xml:id="id1"][not(following-sibling::*)]//delta[contains(concat(@number,"$"),"ribute$")][@xml:lang="no-nb"]//alpha[@xml:id="id2"][not(child::node())][following-sibling::nu[starts-with(@false,"attribu")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@false="attribute-value"][not(preceding-sibling::*)]//mu[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[starts-with(@false,"123")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]/zeta[contains(concat(@and,"$"),"ontent$")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="nb"][@xml:id="id6"]/delta[@title][@xml:lang="en"][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@true][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <chi> + <tau or="this.nodeValue" xml:id="id1"> + <delta number="attribute" xml:lang="no-nb"> + <alpha xml:id="id2"/> + <nu false="attribute-value" xml:lang="no" xml:id="id3"> + <zeta false="attribute-value"> + <mu xml:lang="en" xml:id="id4"/> + <phi false="123456789" xml:lang="nb" xml:id="id5"> + <zeta and="content" xml:lang="en"/> + <alpha xml:lang="nb" xml:id="id6"> + <delta title="attribute" xml:lang="en"/> + <delta xml:lang="no-nb"> + <alpha xml:lang="en-US" xml:id="id7"/> + <psi true="_blank" xml:lang="en-GB"> + <green>This text must be green</green> + </psi> + </delta> + </alpha> + </phi> + </zeta> + </nu> + </delta> + </tau> + </chi> + </tree> + </test> + <test> + <xpath>//mu[contains(concat(@attrib,"$"),"nk$")][@xml:id="id1"]/omicron[following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[starts-with(@token,"another attribute va")]//upsilon[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]/omega[@abort][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@content][not(following-sibling::*)]/zeta[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]//gamma[contains(@true,"is-is-att-val")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[not(following-sibling::*)]//omicron[contains(@attr,"ue")][@xml:lang="no-nb"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <mu attrib="_blank" xml:id="id1"> + <omicron/> + <iota token="another attribute value"> + <upsilon xml:lang="en" xml:id="id2"> + <omega abort="this-is-att-value"> + <delta xml:lang="en-GB"/> + <gamma content="attribute"> + <zeta xml:lang="en-US" xml:id="id3"> + <gamma true="this-is-att-value" xml:lang="en"/> + <sigma> + <omicron attr="true" xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </sigma> + </zeta> + </gamma> + </omega> + </upsilon> + </iota> + </mu> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(concat(@desciption,"-"),"this.nodeValue-")]//chi[contains(concat(@attrib,"$"),"789$")][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="no"][not(following-sibling::*)]/eta[not(child::node())][following-sibling::chi[@and][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[@title][@xml:lang="en-GB"][not(child::node())][following-sibling::beta[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <zeta desciption="this.nodeValue"> + <chi attrib="123456789" xml:id="id1"/> + <alpha xml:lang="no"> + <eta/> + <chi and="another attribute value"> + <eta title="_blank" xml:lang="en-GB"/> + <beta xml:lang="no"> + <green>This text must be green</green> + </beta> + </chi> + </alpha> + </zeta> + </tree> + </test> + <test> + <xpath>//lambda[@att][@xml:lang="en-GB"]/delta[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)]/upsilon[@token][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::delta[starts-with(concat(@att,"-"),"_blank-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/beta[starts-with(concat(@attrib,"-"),"attribute value-")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[@xml:id="id4"][following-sibling::rho[not(following-sibling::*)]/eta[contains(@object,"d 1")][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[contains(concat(@att,"$"),"ank$")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[@xml:lang="en-US"]//nu[@title][@xml:lang="en"][not(preceding-sibling::*)]/gamma[@delete][@xml:lang="en"][not(following-sibling::*)][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <lambda att="attribute" xml:lang="en-GB"> + <delta xml:lang="en-GB" xml:id="id1"> + <upsilon token="_blank" xml:lang="en-US" xml:id="id2"/> + <delta att="_blank" xml:lang="nb"> + <beta attrib="attribute value" xml:id="id3"/> + <tau xml:id="id4"/> + <rho> + <eta object="solid 1px green"/> + <sigma> + <iota/> + <nu/> + <phi att="_blank" xml:lang="en-GB" xml:id="id5"> + <alpha xml:lang="en-US"> + <nu title="attribute value" xml:lang="en"> + <gamma delete="this-is-att-value" xml:lang="en"> + <green>This text must be green</green> + </gamma> + </nu> + </alpha> + </phi> + </sigma> + </rho> + </delta> + </delta> + </lambda> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no-nb"][@xml:id="id1"]//chi[@abort][@xml:lang="nb"][@xml:id="id2"][following-sibling::psi[@false][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::theta[@attrib="attribute-value"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[not(child::node())][following-sibling::upsilon[not(following-sibling::*)]/phi[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::epsilon[contains(concat(@abort,"$"),"e$")][not(following-sibling::*)]//delta[@xml:id="id4"][not(following-sibling::*)]//xi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::theta[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[contains(@src,"-valu")][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="no-nb"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="en-US"][@xml:id="id8"]/zeta[@attribute][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@attr="attribute-value"][@xml:id="id10"][not(following-sibling::*)]//alpha[@xml:lang="no"]/zeta[@xml:lang="no"][not(following-sibling::*)]/zeta[@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)]//tau[contains(concat(@true,"$"),"3456789$")][@xml:id="id12"][not(following-sibling::*)]/pi[@xml:lang="nb"][following-sibling::iota[@xml:id="id13"]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no-nb" xml:id="id1"> + <chi abort="false" xml:lang="nb" xml:id="id2"/> + <psi false="_blank" xml:lang="no-nb"/> + <theta attrib="attribute-value"/> + <upsilon/> + <upsilon> + <phi xml:id="id3"/> + <delta/> + <any xml:lang="en"/> + <epsilon abort="true"> + <delta xml:id="id4"> + <xi xml:lang="no-nb"/> + <theta xml:lang="no-nb" xml:id="id5"> + <omega src="attribute-value" xml:id="id6"/> + <any xml:lang="no-nb" xml:id="id7"/> + <xi xml:lang="en-US" xml:id="id8"> + <zeta attribute="another attribute value" xml:id="id9"/> + <chi attr="attribute-value" xml:id="id10"> + <alpha xml:lang="no"> + <zeta xml:lang="no"> + <zeta xml:lang="no-nb" xml:id="id11"> + <tau true="123456789" xml:id="id12"> + <pi xml:lang="nb"/> + <iota xml:id="id13"> + <green>This text must be green</green> + </iota> + </tau> + </zeta> + </zeta> + </alpha> + </chi> + </xi> + </theta> + </delta> + </epsilon> + </upsilon> + </epsilon> + </tree> + </test> + <test> + <xpath>//nu[contains(concat(@or,"$"),"reen$")][@xml:id="id1"]//epsilon[@xml:lang="en"][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][not(following-sibling::*)]/gamma[@xml:id="id2"][not(following-sibling::*)]//kappa[@abort][@xml:id="id3"][not(child::node())][following-sibling::mu[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[@xml:lang="en"][@xml:id="id5"]/omicron[following-sibling::tau[starts-with(@attr,"attribu")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::rho[contains(concat(@class,"$"),".nodeValue$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/tau[not(preceding-sibling::*)][not(following-sibling::*)]/eta[contains(@title,"d")][@xml:id="id6"][not(following-sibling::*)]/xi[@class][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[contains(@title,"456")][@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@attribute][@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 2]]//epsilon[@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[contains(@desciption,"ue")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::lambda[@xml:id="id11"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::eta[@xml:lang="no"][following-sibling::*[contains(@data,"e")][@xml:lang="no"]/*[@xml:lang="en-GB"][@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[contains(@attr,"ttribute")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::theta or following-sibling::theta)]/chi[@xml:lang="en-US"][@xml:id="id13"][position() = 1]][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <nu or="solid 1px green" xml:id="id1"> + <epsilon xml:lang="en"/> + <epsilon xml:lang="en-US"> + <gamma xml:id="id2"> + <kappa abort="100%" xml:id="id3"/> + <mu xml:lang="no-nb" xml:id="id4"> + <omega xml:lang="en" xml:id="id5"> + <omicron/> + <tau attr="attribute-value" xml:lang="nb"/> + <rho class="this.nodeValue"> + <tau> + <eta title="this.nodeValue" xml:id="id6"> + <xi class="another attribute value" xml:id="id7"/> + <xi title="123456789" xml:lang="no-nb" xml:id="id8"/> + <delta attribute="this-is-att-value" xml:lang="nb" xml:id="id9"> + <epsilon xml:id="id10"/> + <nu desciption="attribute-value" xml:lang="en-US"/> + <lambda xml:id="id11"/> + <eta xml:lang="no"/> + <any data="false" xml:lang="no"> + <any xml:lang="en-GB" xml:id="id12"> + <theta attr="attribute" xml:lang="nb"> + <chi xml:lang="en-US" xml:id="id13"> + <green>This text must be green</green> + </chi> + </theta> + </any> + </any> + </delta> + </eta> + </tau> + </rho> + </omega> + </mu> + </gamma> + </epsilon> + </nu> + </tree> + </test> + <test> + <xpath>//omicron[@data="attribute-value"]/kappa[@xml:lang="en"][@xml:id="id1"]/beta[@and][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::lambda)][following-sibling::upsilon[@xml:lang="nb"][not(following-sibling::*)]/delta[starts-with(concat(@and,"-"),"true-")][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[contains(concat(@data,"$"),"px green$")]//iota[not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::delta[preceding-sibling::*[position() = 1]][following-sibling::chi[starts-with(concat(@number,"-"),"true-")][@xml:lang="no"][not(child::node())][following-sibling::upsilon[contains(concat(@class,"$"),"100%$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//lambda[@xml:id="id6"][not(preceding-sibling::*)]/sigma[@attribute][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omicron data="attribute-value"> + <kappa xml:lang="en" xml:id="id1"> + <beta and="solid 1px green"/> + <iota> + <any xml:lang="en-US" xml:id="id2"> + <lambda xml:lang="en-GB" xml:id="id3"/> + <upsilon xml:lang="nb"> + <delta and="true" xml:id="id4"/> + <epsilon data="solid 1px green"> + <iota/> + <delta/> + <chi number="true" xml:lang="no"/> + <upsilon class="100%" xml:lang="en-GB"/> + <omicron xml:lang="en-GB" xml:id="id5"> + <lambda xml:id="id6"> + <sigma attribute="another attribute value" xml:lang="en-GB"/> + <gamma> + <green>This text must be green</green> + </gamma> + </lambda> + </omicron> + </epsilon> + </upsilon> + </any> + </iota> + </kappa> + </omicron> + </tree> + </test> + <test> + <xpath>//theta[@number="content"][@xml:lang="en-GB"][@xml:id="id1"]//psi[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@attrib="true"][not(following-sibling::*)]//kappa[starts-with(@attrib,"content")][@xml:lang="en-US"][not(following-sibling::*)]//phi[starts-with(concat(@content,"-"),"attribute-")][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(@string,"ue")][@xml:id="id3"][preceding-sibling::*[position() = 1]]/upsilon[@xml:lang="en-US"]//chi[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <theta number="content" xml:lang="en-GB" xml:id="id1"> + <psi xml:lang="no-nb" xml:id="id2"> + <rho attrib="true"> + <kappa attrib="content" xml:lang="en-US"> + <phi content="attribute"/> + <delta string="attribute value" xml:id="id3"> + <upsilon xml:lang="en-US"> + <chi xml:lang="en-US" xml:id="id4"> + <green>This text must be green</green> + </chi> + </upsilon> + </delta> + </kappa> + </rho> + </psi> + </theta> + </tree> + </test> + <test> + <xpath>//delta[@insert][@xml:lang="no-nb"][@xml:id="id1"]//rho[@false="this-is-att-value"][not(following-sibling::*)]//kappa[contains(@and,"3456")][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@true][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:id="id3"]//chi[starts-with(concat(@object,"-"),"another attribute value-")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::gamma[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@title][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]]/chi[contains(concat(@or,"$"),"een$")][@xml:id="id7"][not(preceding-sibling::*)][not(preceding-sibling::chi)][following-sibling::tau[@content][@xml:lang="no"]//omega[starts-with(@number,"solid 1")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(concat(@src,"$"),"alse$")]/alpha[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[not(child::node())][following-sibling::phi[contains(concat(@abort,"$"),"0%$")][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(preceding-sibling::phi)][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id9"][preceding-sibling::*[position() = 2]][following-sibling::chi[@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][not(preceding-sibling::chi)]/eta[@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@token][@xml:lang="en"][not(following-sibling::*)]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <delta insert="this-is-att-value" xml:lang="no-nb" xml:id="id1"> + <rho false="this-is-att-value"> + <kappa and="123456789"/> + <eta true="content" xml:lang="en" xml:id="id2"> + <beta/> + <omega xml:id="id3"> + <chi object="another attribute value" xml:lang="en-GB" xml:id="id4"/> + <gamma xml:id="id5"/> + <any title="false" xml:lang="en-US" xml:id="id6"> + <chi or="solid 1px green" xml:id="id7"/> + <tau content="this-is-att-value" xml:lang="no"> + <omega number="solid 1px green" xml:lang="no-nb"> + <psi src="false"> + <alpha xml:lang="nb"> + <kappa/> + <phi abort="100%" xml:id="id8"/> + <tau xml:lang="no-nb" xml:id="id9"/> + <chi xml:lang="no" xml:id="id10"> + <eta xml:lang="no" xml:id="id11"> + <theta token="_blank" xml:lang="en"> + <green>This text must be green</green> + </theta> + </eta> + </chi> + </alpha> + </psi> + </omega> + </tau> + </any> + </omega> + </eta> + </rho> + </delta> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en"]//omicron[@object][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@att="attribute"][@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[starts-with(concat(@title,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[not(child::node())][following-sibling::psi[contains(@delete,"ib")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]//theta[@xml:id="id2"][following-sibling::rho[not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en"> + <omicron object="100%"/> + <beta att="attribute" xml:lang="en-GB" xml:id="id1"> + <xi title="this.nodeValue"/> + <psi/> + <psi delete="attribute" xml:lang="nb"> + <theta xml:id="id2"/> + <rho/> + <sigma xml:lang="no-nb"> + <green>This text must be green</green> + </sigma> + </psi> + </beta> + </chi> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-US"]/epsilon[contains(concat(@attrib,"$"),"ent$")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::rho[not(following-sibling::*)]/chi[@true][@xml:lang="no"][@xml:id="id1"]//zeta[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::theta[@xml:id="id3"][not(child::node())][following-sibling::delta[@xml:lang="no"][not(following-sibling::*)]//alpha[@or="true"][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//nu[contains(concat(@attrib,"$"),"ue$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[contains(concat(@delete,"$"),"se$")][@xml:lang="en"][@xml:id="id5"][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id6"][following-sibling::chi[contains(@attribute,"d 1px green")]/nu[@xml:lang="en-US"][@xml:id="id7"][not(following-sibling::*)]//phi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::nu[@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en-US"> + <epsilon attrib="content" xml:lang="en"/> + <iota/> + <rho> + <chi true="this-is-att-value" xml:lang="no" xml:id="id1"> + <zeta xml:lang="en-GB" xml:id="id2"/> + <theta xml:id="id3"/> + <delta xml:lang="no"> + <alpha or="true" xml:lang="no" xml:id="id4"/> + <pi xml:lang="no-nb"> + <nu attrib="this.nodeValue" xml:lang="no-nb"> + <lambda delete="false" xml:lang="en" xml:id="id5"/> + <kappa xml:lang="en-GB" xml:id="id6"/> + <chi attribute="solid 1px green"> + <nu xml:lang="en-US" xml:id="id7"> + <phi xml:lang="no"/> + <nu xml:id="id8"> + <green>This text must be green</green> + </nu> + </nu> + </chi> + </nu> + </pi> + </delta> + </chi> + </rho> + </chi> + </tree> + </test> + <test> + <xpath>//beta[starts-with(concat(@object,"-"),"_blank-")]//iota[not(following-sibling::*)]/theta[starts-with(concat(@number,"-"),"123456789-")][@xml:lang="nb"][@xml:id="id1"]//delta[@true][not(following-sibling::*)]//chi[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]/psi[contains(concat(@number,"$"),"ent$")]/beta[contains(concat(@name,"$"),"ribute value$")][@xml:id="id3"][not(preceding-sibling::*)]//omega[@object="attribute"][not(following-sibling::*)]/beta[not(preceding-sibling::*)][not(following-sibling::*)]//nu[@attribute="this-is-att-value"][@xml:lang="no"][not(child::node())][following-sibling::rho[@content][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[not(child::node())][following-sibling::epsilon[starts-with(concat(@false,"-"),"true-")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]//mu[starts-with(@src,"fals")][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[starts-with(@object,"attribute v")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[starts-with(concat(@desciption,"-"),"_blank-")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:id="id6"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <beta object="_blank"> + <iota> + <theta number="123456789" xml:lang="nb" xml:id="id1"> + <delta true="solid 1px green"> + <chi xml:lang="nb" xml:id="id2"> + <psi number="content"> + <beta name="attribute value" xml:id="id3"> + <omega object="attribute"> + <beta> + <nu attribute="this-is-att-value" xml:lang="no"/> + <rho content="attribute" xml:lang="en-US"> + <delta/> + <epsilon false="true" xml:lang="en-US"> + <mu src="false" xml:id="id4"/> + <alpha object="attribute value" xml:lang="en-GB" xml:id="id5"/> + <sigma desciption="_blank"/> + <rho xml:id="id6"> + <green>This text must be green</green> + </rho> + </epsilon> + </rho> + </beta> + </omega> + </beta> + </psi> + </chi> + </delta> + </theta> + </iota> + </beta> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="en-US"]//lambda[@data="123456789"][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:id="id2"][preceding-sibling::*[position() = 2]]//phi[starts-with(concat(@delete,"-"),"true-")][@xml:lang="en"][not(following-sibling::*)]/sigma[contains(@desciption,"lank")][not(following-sibling::*)]//psi[starts-with(@delete,"a")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::delta[starts-with(@attr,"tru")][following-sibling::*[position()=1]][following-sibling::tau[starts-with(concat(@number,"-"),"content-")][preceding-sibling::*[position() = 2]]//gamma[not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=4]][not(child::node())][following-sibling::psi[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::eta[@xml:id="id6"][preceding-sibling::*[position() = 4]][following-sibling::epsilon[@src][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[starts-with(concat(@or,"-"),"false-")][@xml:id="id8"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]//pi[not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@number][@xml:id="id9"]//tau[starts-with(@insert,"tru")][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][@xml:id="id10"][not(child::node())][following-sibling::upsilon[contains(@desciption,"lue")][@xml:id="id11"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="en-US"> + <lambda data="123456789"/> + <tau xml:lang="en-US" xml:id="id1"/> + <phi xml:id="id2"> + <phi delete="true" xml:lang="en"> + <sigma desciption="_blank"> + <psi delete="another attribute value" xml:id="id3"/> + <delta attr="true"/> + <tau number="content"> + <gamma/> + <epsilon xml:id="id4"/> + <omega xml:lang="no-nb"/> + <psi xml:lang="en-US" xml:id="id5"/> + <eta xml:id="id6"/> + <epsilon src="attribute-value" xml:id="id7"/> + <phi or="false" xml:id="id8"> + <pi/> + <upsilon number="content" xml:id="id9"> + <tau insert="true"/> + <upsilon xml:lang="nb" xml:id="id10"/> + <upsilon desciption="this.nodeValue" xml:id="id11"> + <green>This text must be green</green> + </upsilon> + </upsilon> + </phi> + </tau> + </sigma> + </phi> + </phi> + </pi> + </tree> + </test> + <test> + <xpath>//sigma[@true][@xml:lang="en-US"][@xml:id="id1"]/xi[@title][@xml:lang="en-US"][@xml:id="id2"][following-sibling::kappa[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]//omicron[@xml:lang="en-GB"][following-sibling::kappa[not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::omicron[starts-with(concat(@desciption,"-"),"content-")][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]//gamma[@xml:lang="nb"][not(preceding-sibling::*)]/lambda[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::*[starts-with(concat(@string,"-"),"100%-")][not(following-sibling::*)]/tau[@and][not(preceding-sibling::*)]//psi[starts-with(concat(@string,"-"),"_blank-")][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[not(child::node())][following-sibling::beta[contains(concat(@false,"$"),"ttribute value$")][@xml:id="id7"][preceding-sibling::*[position() = 2]]//rho[@xml:lang="en-GB"][following-sibling::omega[@class][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <sigma true="123456789" xml:lang="en-US" xml:id="id1"> + <xi title="attribute-value" xml:lang="en-US" xml:id="id2"/> + <kappa xml:lang="en-US"> + <omicron xml:lang="en-GB"/> + <kappa/> + <omicron xml:lang="no" xml:id="id3"/> + <omicron desciption="content" xml:lang="nb" xml:id="id4"> + <gamma xml:lang="nb"> + <lambda xml:id="id5"/> + <any string="100%"> + <tau and="attribute"> + <psi string="_blank" xml:lang="en-US" xml:id="id6"/> + <theta/> + <beta false="another attribute value" xml:id="id7"> + <rho xml:lang="en-GB"/> + <omega class="true"> + <green>This text must be green</green> + </omega> + </beta> + </tau> + </any> + </gamma> + </omicron> + </kappa> + </sigma> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(@or,"solid 1p")][@xml:id="id1"]/epsilon[starts-with(@or,"100%")][@xml:id="id2"][not(preceding-sibling::*)]/psi[contains(concat(@or,"$"),"alue$")][@xml:id="id3"][not(following-sibling::*)]//theta[starts-with(@insert,"attribute v")][not(preceding-sibling::*)]//theta[contains(concat(@title,"$"),"ibute value$")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>1</nth> + </result> + <tree> + <upsilon or="solid 1px green" xml:id="id1"> + <epsilon or="100%" xml:id="id2"> + <psi or="this-is-att-value" xml:id="id3"> + <theta insert="attribute value"> + <theta title="attribute value"/> + <rho> + <green>This text must be green</green> + </rho> + </theta> + </psi> + </epsilon> + </upsilon> + </tree> + </test> + <test> + <xpath>//nu[contains(concat(@object,"$"),"ue$")][@xml:lang="en-GB"][@xml:id="id1"]//gamma[@xml:lang="no"][not(child::node())][following-sibling::*[@xml:lang="no"]//tau[starts-with(concat(@title,"-"),"true-")][@xml:id="id2"][not(preceding-sibling::*)]/gamma[contains(@name,"10")][not(preceding-sibling::*)][following-sibling::beta[contains(concat(@att,"$"),"s.nodeValue$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="no"][following-sibling::*[position()=4]][not(child::node())][following-sibling::psi[@abort][@xml:id="id3"][not(child::node())][following-sibling::psi[contains(concat(@object,"$"),"true$")][following-sibling::delta[@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::alpha[contains(@title,"e")][@xml:id="id5"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <nu object="this-is-att-value" xml:lang="en-GB" xml:id="id1"> + <gamma xml:lang="no"/> + <any xml:lang="no"> + <tau title="true" xml:id="id2"> + <gamma name="100%"/> + <beta att="this.nodeValue" xml:lang="no-nb"/> + <delta xml:lang="no"/> + <psi abort="true" xml:id="id3"/> + <psi object="true"/> + <delta xml:id="id4"/> + <alpha title="true" xml:id="id5"> + <green>This text must be green</green> + </alpha> + </tau> + </any> + </nu> + </tree> + </test> + <test> + <xpath>//alpha[@data="attribute"][@xml:lang="en-US"][@xml:id="id1"]/iota[starts-with(@att,"this-is-att-v")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="en"][@xml:id="id3"]/eta[@xml:id="id4"][not(following-sibling::*)]/theta[starts-with(concat(@insert,"-"),"attribute-")][@xml:id="id5"][following-sibling::*[position()=4]][following-sibling::delta[@xml:lang="nb"][not(child::node())][following-sibling::beta[following-sibling::*[position()=2]][following-sibling::upsilon[contains(concat(@insert,"$"),"value$")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::delta[starts-with(concat(@abort,"-"),"attribute-")][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//mu[@xml:lang="en"][@xml:id="id7"][not(child::node())][following-sibling::alpha[@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@xml:lang="nb"][not(following-sibling::*)]/tau[@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[contains(concat(@title,"$"),"ue$")]/phi[@string][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <alpha data="attribute" xml:lang="en-US" xml:id="id1"> + <iota att="this-is-att-value" xml:lang="en-GB" xml:id="id2"/> + <xi xml:lang="en" xml:id="id3"> + <eta xml:id="id4"> + <theta insert="attribute" xml:id="id5"/> + <delta xml:lang="nb"/> + <beta/> + <upsilon insert="another attribute value" xml:lang="en-US" xml:id="id6"/> + <delta abort="attribute"> + <mu xml:lang="en" xml:id="id7"/> + <alpha xml:id="id8"> + <pi xml:lang="nb"> + <tau xml:lang="no" xml:id="id9"> + <phi title="true"> + <phi string="_blank" xml:id="id10"> + <green>This text must be green</green> + </phi> + </phi> + </tau> + </pi> + </alpha> + </delta> + </eta> + </xi> + </alpha> + </tree> + </test> + <test> + <xpath>//chi//sigma[starts-with(concat(@src,"-"),"true-")][not(following-sibling::*)]/delta[@xml:id="id1"][following-sibling::kappa[preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/kappa[@or="attribute value"][@xml:lang="no"][not(preceding-sibling::*)]/rho[@xml:lang="no"][@xml:id="id2"]/mu[not(preceding-sibling::*)][following-sibling::nu][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <chi> + <sigma src="true"> + <delta xml:id="id1"/> + <kappa/> + <iota xml:lang="no-nb"> + <kappa or="attribute value" xml:lang="no"> + <rho xml:lang="no" xml:id="id2"> + <mu/> + <nu> + <green>This text must be green</green> + </nu> + </rho> + </kappa> + </iota> + </sigma> + </chi> + </tree> + </test> + <test> + <xpath>//gamma[contains(concat(@class,"$"),"te$")][@xml:lang="en-US"][@xml:id="id1"]//theta[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)]/lambda[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[contains(concat(@content,"$"),"ibute-value$")][@xml:lang="en-GB"][@xml:id="id3"]/mu[@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="en-GB"][@xml:id="id4"][not(following-sibling::*)]//zeta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[not(child::node())][following-sibling::chi[starts-with(@abort,"an")][@xml:lang="no"][@xml:id="id6"][not(child::node())][following-sibling::epsilon[@number="123456789"][@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::iota[contains(concat(@and,"$"),"odeValue$")][@xml:lang="en-US"][following-sibling::mu[starts-with(@string,"this.")][@xml:id="id8"][preceding-sibling::*[position() = 5]][following-sibling::upsilon[contains(concat(@string,"$"),"lank$")][@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 6]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <gamma class="attribute" xml:lang="en-US" xml:id="id1"> + <theta xml:lang="en-GB" xml:id="id2"> + <lambda xml:lang="no"/> + <gamma content="attribute-value" xml:lang="en-GB" xml:id="id3"> + <mu xml:lang="no-nb"/> + <eta xml:lang="en-GB" xml:id="id4"> + <zeta xml:lang="en-GB" xml:id="id5"/> + <epsilon/> + <chi abort="another attribute value" xml:lang="no" xml:id="id6"/> + <epsilon number="123456789" xml:lang="no-nb" xml:id="id7"/> + <iota and="this.nodeValue" xml:lang="en-US"/> + <mu string="this.nodeValue" xml:id="id8"/> + <upsilon string="_blank" xml:lang="en-GB" xml:id="id9"> + <green>This text must be green</green> + </upsilon> + </eta> + </gamma> + </theta> + </gamma> + </tree> + </test> + <test> + <xpath>//eta[@true="100%"]//mu[@xml:lang="no"][not(following-sibling::*)]/omega[@string][@xml:lang="nb"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::xi[@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]/xi[not(following-sibling::*)]//rho[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[following-sibling::kappa[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@delete="attribute"][preceding-sibling::*[position() = 2]][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::nu[starts-with(concat(@abort,"-"),"123456789-")][@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 4]]//eta[contains(concat(@class,"$"),"is-is-att-value$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@attrib][@xml:id="id5"][preceding-sibling::*[position() = 1]]/iota[not(following-sibling::*)]/beta[@string][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]/omega[not(preceding-sibling::*)]][position() = 1]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <eta true="100%"> + <mu xml:lang="no"> + <omega string="solid 1px green" xml:lang="nb"/> + <nu/> + <omega xml:lang="en-GB"/> + <xi xml:lang="nb" xml:id="id1"> + <xi> + <rho xml:lang="en"> + <omicron/> + <kappa xml:id="id2"/> + <nu delete="attribute"/> + <alpha xml:id="id3"/> + <nu abort="123456789" xml:lang="en" xml:id="id4"> + <eta class="this-is-att-value"/> + <beta attrib="100%" xml:id="id5"> + <iota> + <beta string="123456789" xml:lang="en" xml:id="id6"> + <omega> + <green>This text must be green</green> + </omega> + </beta> + </iota> + </beta> + </nu> + </rho> + </xi> + </xi> + </mu> + </eta> + </tree> + </test> + <test> + <xpath>//zeta[@attribute][@xml:lang="en-GB"]//gamma[@string][@xml:lang="en"][not(preceding-sibling::*)]//mu[starts-with(@name,"tru")][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::nu[starts-with(concat(@content,"-"),"true-")][@xml:id="id2"][following-sibling::iota[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[@true][not(child::node())][following-sibling::omicron[@abort][@xml:id="id4"][preceding-sibling::*[position() = 4]]//theta[starts-with(@insert,"at")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:id="id6"]//mu[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::eta[contains(concat(@desciption,"$"),"reen$")][@xml:lang="no-nb"][not(child::node())][following-sibling::eta[starts-with(concat(@attrib,"-"),"attribute-")][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::mu[@xml:id="id8"][following-sibling::lambda[not(following-sibling::*)]/sigma[@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="no"][@xml:id="id9"]/omega[@token][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="nb"]//lambda[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi[contains(@token,"x ")][preceding-sibling::*[position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta attribute="attribute-value" xml:lang="en-GB"> + <gamma string="this.nodeValue" xml:lang="en"> + <mu name="true" xml:id="id1"/> + <nu content="true" xml:id="id2"/> + <iota xml:id="id3"/> + <iota true="solid 1px green"/> + <omicron abort="another attribute value" xml:id="id4"> + <theta insert="attribute-value" xml:lang="en-GB" xml:id="id5"> + <theta xml:id="id6"> + <mu xml:lang="no"/> + <eta desciption="solid 1px green" xml:lang="no-nb"/> + <eta attrib="attribute" xml:id="id7"/> + <mu xml:id="id8"/> + <lambda> + <sigma xml:lang="nb"/> + <theta xml:lang="no" xml:id="id9"> + <omega token="attribute value" xml:lang="no-nb"/> + <psi xml:lang="nb"> + <lambda/> + <pi token="solid 1px green"> + <green>This text must be green</green> + </pi> + </psi> + </theta> + </lambda> + </theta> + </theta> + </omicron> + </gamma> + </zeta> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="nb"][@xml:id="id1"]//iota[contains(concat(@token,"$"),"lank$")][@xml:lang="en"][following-sibling::sigma[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][not(child::node())][following-sibling::sigma[@abort][@xml:lang="no"][not(child::node())][following-sibling::rho[not(child::node())][following-sibling::kappa[@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::gamma[@string="100%"][preceding-sibling::*[position() = 5]][following-sibling::epsilon[preceding-sibling::*[position() = 6]]//tau[@xml:id="id3"][not(following-sibling::*)]/beta[starts-with(@and,"fa")][not(following-sibling::*)]/nu[@class][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[contains(concat(@insert,"$"),"this.nodeValue$")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::mu[preceding-sibling::*[position() = 1]][following-sibling::chi[contains(concat(@attrib,"$"),"ute$")][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=4]][following-sibling::*[@xml:id="id7"][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[@xml:lang="no"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=2]][following-sibling::kappa[@xml:lang="en-US"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]/kappa[starts-with(concat(@string,"-"),"100%-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[contains(concat(@content,"$"),"deValue$")][@xml:lang="no"][@xml:id="id9"][not(following-sibling::*)]/theta[contains(@object,"0")][not(following-sibling::*)]//lambda[starts-with(concat(@class,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[starts-with(@insert,"_blan")][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="nb" xml:id="id1"> + <iota token="_blank" xml:lang="en"/> + <sigma token="another attribute value" xml:id="id2"/> + <sigma abort="solid 1px green" xml:lang="no"/> + <rho/> + <kappa xml:lang="nb"/> + <gamma string="100%"/> + <epsilon> + <tau xml:id="id3"> + <beta and="false"> + <nu class="_blank" xml:lang="en" xml:id="id4"> + <phi insert="this.nodeValue" xml:lang="en-GB" xml:id="id5"/> + <mu/> + <chi attrib="attribute" xml:lang="no" xml:id="id6"/> + <any xml:id="id7"/> + <rho xml:lang="no"/> + <kappa xml:lang="en-US"/> + <lambda xml:lang="en-US" xml:id="id8"> + <kappa string="100%" xml:lang="no-nb"> + <omicron content="this.nodeValue" xml:lang="no" xml:id="id9"> + <theta object="100%"> + <lambda class="this.nodeValue"/> + <xi insert="_blank"> + <green>This text must be green</green> + </xi> + </theta> + </omicron> + </kappa> + </lambda> + </nu> + </beta> + </tau> + </epsilon> + </beta> + </tree> + </test> + <test> + <xpath>//theta[contains(concat(@content,"$"),"is.nodeValue$")][@xml:lang="en-US"][@xml:id="id1"]//gamma[starts-with(@or,"t")][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::beta[@xml:id="id2"][not(following-sibling::*)]//iota[starts-with(@and,"s")][not(preceding-sibling::*)]/psi[starts-with(@attr,"solid 1px")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::kappa[@desciption="attribute"][@xml:lang="nb"][@xml:id="id4"]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <theta content="this.nodeValue" xml:lang="en-US" xml:id="id1"> + <gamma or="true" xml:lang="en"/> + <beta xml:id="id2"> + <iota and="solid 1px green"> + <psi attr="solid 1px green" xml:id="id3"/> + <kappa desciption="attribute" xml:lang="nb" xml:id="id4"> + <green>This text must be green</green> + </kappa> + </iota> + </beta> + </theta> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="nb"]/omicron[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]//xi[contains(concat(@data,"$"),"e$")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[contains(@attribute,"tt-value")][@xml:lang="nb"]/beta[@xml:id="id3"][not(preceding-sibling::*)]/mu[@src][@xml:id="id4"][not(following-sibling::*)]/kappa[@number][@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::eta[@xml:id="id6"][not(following-sibling::*)]/theta[@xml:id="id7"][not(child::node())][following-sibling::theta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::lambda[starts-with(concat(@or,"-"),"another attribute value-")][@xml:lang="en"][following-sibling::xi[@false][@xml:id="id8"][preceding-sibling::*[position() = 3]]//upsilon[@number][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="en"][not(child::node())][following-sibling::eta[@xml:lang="no-nb"]//eta[not(child::node())][following-sibling::eta[@number][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[@src][@xml:id="id10"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="nb"> + <omicron xml:lang="nb"/> + <rho xml:lang="en-US" xml:id="id1"> + <xi data="this-is-att-value" xml:lang="no-nb" xml:id="id2"/> + <zeta attribute="this-is-att-value" xml:lang="nb"> + <beta xml:id="id3"> + <mu src="this-is-att-value" xml:id="id4"> + <kappa number="true" xml:lang="nb" xml:id="id5"/> + <eta xml:id="id6"> + <theta xml:id="id7"/> + <theta xml:lang="en-US"/> + <lambda or="another attribute value" xml:lang="en"/> + <xi false="content" xml:id="id8"> + <upsilon number="content" xml:id="id9"/> + <iota xml:lang="en"/> + <eta xml:lang="no-nb"> + <eta/> + <eta number="content"/> + <tau src="100%" xml:id="id10"> + <green>This text must be green</green> + </tau> + </eta> + </xi> + </eta> + </mu> + </beta> + </zeta> + </rho> + </theta> + </tree> + </test> + <test> + <xpath>//mu[contains(concat(@name,"$"),"se$")][@xml:lang="no-nb"][@xml:id="id1"]//alpha[@or]/phi[@att="true"][@xml:lang="no-nb"][not(child::node())][following-sibling::beta/gamma[@att][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@insert][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@true][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id3"][following-sibling::omega[contains(concat(@attrib,"$")," value$")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::mu[@abort][@xml:id="id5"][following-sibling::delta[@xml:lang="nb"][preceding-sibling::*[position() = 3]]/iota[@abort][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]//sigma[@data][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[starts-with(@attrib,"12")][@xml:id="id9"]/pi[@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::delta[@xml:lang="en"][@xml:id="id11"][not(child::node())][following-sibling::gamma[@xml:id="id12"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <mu name="false" xml:lang="no-nb" xml:id="id1"> + <alpha or="attribute-value"> + <phi att="true" xml:lang="no-nb"/> + <beta> + <gamma att="content" xml:id="id2"/> + <omicron insert="this.nodeValue" xml:lang="no"> + <chi true="100%" xml:lang="en-GB"> + <chi xml:id="id3"/> + <omega attrib="another attribute value" xml:id="id4"/> + <mu abort="attribute" xml:id="id5"/> + <delta xml:lang="nb"> + <iota abort="false" xml:lang="en" xml:id="id6"> + <sigma data="100%" xml:lang="no" xml:id="id7"> + <phi xml:lang="en" xml:id="id8"> + <zeta attrib="123456789" xml:id="id9"> + <pi xml:lang="en" xml:id="id10"> + <omega/> + <delta xml:lang="en" xml:id="id11"/> + <gamma xml:id="id12"> + <green>This text must be green</green> + </gamma> + </pi> + </zeta> + </phi> + </sigma> + </iota> + </delta> + </chi> + </omicron> + </beta> + </alpha> + </mu> + </tree> + </test> + <test> + <xpath>//rho/nu[not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][not(following-sibling::*)]/mu[@xml:lang="no-nb"][not(preceding-sibling::*)]//theta[contains(concat(@number,"$"),".nodeValue$")][@xml:lang="nb"][@xml:id="id1"][not(child::node())][following-sibling::beta[@and="attribute value"][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 2]]//sigma[@attr][@xml:lang="nb"][not(following-sibling::*)]//pi[@content][@xml:id="id3"][not(preceding-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <nu/> + <psi xml:lang="en-GB"> + <mu xml:lang="no-nb"> + <theta number="this.nodeValue" xml:lang="nb" xml:id="id1"/> + <beta and="attribute value" xml:lang="en-US"/> + <delta xml:id="id2"> + <sigma attr="content" xml:lang="nb"> + <pi content="100%" xml:id="id3"> + <green>This text must be green</green> + </pi> + </sigma> + </delta> + </mu> + </psi> + </rho> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]/mu[@xml:id="id2"]/sigma[not(following-sibling::*)]//epsilon[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@and="attribute"][@xml:id="id4"][following-sibling::sigma[contains(@false,"ue")][@xml:id="id5"][preceding-sibling::*[position() = 1]]//iota[@insert][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[starts-with(concat(@attr,"-"),"100%-")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/zeta[@delete][@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[@xml:id="id10"][not(following-sibling::*)]/pi[contains(concat(@string,"$"),"d 1px green$")][@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)]//psi[@xml:id="id12"]//zeta[not(preceding-sibling::*)][not(preceding-sibling::zeta or following-sibling::zeta)]/eta[@attribute][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:id="id13"]//kappa[@and][@xml:lang="en"][not(following-sibling::*)]/alpha[@abort][@xml:id="id14"]//phi[contains(@title,"ute value")][not(following-sibling::*)]/xi[@xml:lang="no-nb"][@xml:id="id15"][not(following-sibling::*)]/chi[contains(concat(@data,"$"),"ue$")][@xml:lang="no-nb"]//upsilon[@xml:id="id16"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:id="id17"]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <mu xml:id="id2"> + <sigma> + <epsilon xml:lang="nb" xml:id="id3"> + <phi and="attribute" xml:id="id4"/> + <sigma false="attribute-value" xml:id="id5"> + <iota insert="content" xml:id="id6"/> + <chi attr="100%" xml:id="id7"/> + <beta> + <zeta delete="this.nodeValue" xml:lang="no-nb" xml:id="id8"/> + <sigma xml:lang="en-GB" xml:id="id9"> + <tau xml:id="id10"> + <pi string="solid 1px green" xml:lang="no-nb" xml:id="id11"> + <psi xml:id="id12"> + <zeta> + <eta attribute="another attribute value" xml:lang="en-US"/> + <chi xml:id="id13"> + <kappa and="123456789" xml:lang="en"> + <alpha abort="123456789" xml:id="id14"> + <phi title="attribute value"> + <xi xml:lang="no-nb" xml:id="id15"> + <chi data="attribute-value" xml:lang="no-nb"> + <upsilon xml:id="id16"> + <psi xml:id="id17"> + <green>This text must be green</green> + </psi> + </upsilon> + </chi> + </xi> + </phi> + </alpha> + </kappa> + </chi> + </zeta> + </psi> + </pi> + </tau> + </sigma> + </beta> + </sigma> + </epsilon> + </sigma> + </mu> + </sigma> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]/eta[@xml:id="id2"][not(preceding-sibling::*)]//phi[@att="true"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[not(child::node())][following-sibling::omega[@xml:lang="en"][following-sibling::gamma[@xml:id="id4"][following-sibling::alpha[contains(concat(@class,"$"),"lank$")][@xml:lang="en-GB"]/iota[contains(concat(@insert,"$"),"123456789$")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(preceding-sibling::iota)][not(child::node())][following-sibling::rho[contains(@src,"k")][preceding-sibling::*[position() = 1]]/alpha[@string][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::eta[@xml:id="id5"][preceding-sibling::*[position() = 1]]//mu[@insert="this.nodeValue"][not(following-sibling::*)]/pi[contains(concat(@attribute,"$"),"is-att-value$")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id7"][not(preceding-sibling::*)]//epsilon[@xml:lang="en"][@xml:id="id8"]//omicron[not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::omega[@xml:id="id9"][following-sibling::omega[@and="true"][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::delta[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="en-US"][following-sibling::nu[following-sibling::phi[@string][@xml:lang="no-nb"][not(following-sibling::*)]/upsilon[contains(concat(@att,"$")," attribute value$")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)]]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:id="id1"> + <eta xml:id="id2"> + <phi att="true" xml:id="id3"/> + <xi/> + <omega xml:lang="en"/> + <gamma xml:id="id4"/> + <alpha class="_blank" xml:lang="en-GB"> + <iota insert="123456789"/> + <rho src="_blank"> + <alpha string="solid 1px green" xml:lang="en-US"/> + <eta xml:id="id5"> + <mu insert="this.nodeValue"> + <pi attribute="this-is-att-value" xml:lang="no-nb" xml:id="id6"> + <mu xml:lang="no-nb" xml:id="id7"> + <epsilon xml:lang="en" xml:id="id8"> + <omicron/> + <omega xml:id="id9"/> + <omega and="true" xml:id="id10"/> + <delta content="attribute" xml:lang="en-US"/> + <nu/> + <phi string="123456789" xml:lang="no-nb"> + <upsilon att="another attribute value" xml:lang="en-GB"> + <any xml:lang="no-nb"> + <omega xml:lang="nb" xml:id="id11"> + <green>This text must be green</green> + </omega> + </any> + </upsilon> + </phi> + </epsilon> + </mu> + </pi> + </mu> + </eta> + </rho> + </alpha> + </eta> + </kappa> + </tree> + </test> + <test> + <xpath>//omega/rho[starts-with(concat(@content,"-"),"solid 1px green-")][not(preceding-sibling::*)][not(following-sibling::*)]/iota[contains(@or,"a")][@xml:id="id1"][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@false][@xml:lang="en"][following-sibling::zeta[contains(concat(@title,"$"),"this-is-att-value$")][@xml:lang="nb"][not(following-sibling::*)]//theta[@attr][not(preceding-sibling::*)]/beta[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@string][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[contains(@att,"k")][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::alpha[@false="true"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id7"]//delta[contains(@insert,"bute value")][@xml:lang="en-US"][not(following-sibling::*)]/eta[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::xi[@att][preceding-sibling::*[position() = 1]]/xi[@xml:lang="no"][not(child::node())][following-sibling::alpha[@or="this.nodeValue"]//delta[@title="true"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no"]/omega[@xml:id="id9"]/sigma[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <rho content="solid 1px green"> + <iota or="_blank" xml:id="id1"/> + <kappa/> + <beta false="123456789" xml:lang="en"/> + <zeta title="this-is-att-value" xml:lang="nb"> + <theta attr="solid 1px green"> + <beta xml:lang="nb"/> + <gamma string="true" xml:lang="no" xml:id="id2"> + <phi xml:lang="en-US" xml:id="id3"> + <pi att="_blank" xml:id="id4"> + <beta xml:id="id5"/> + <alpha false="true" xml:id="id6"/> + <epsilon xml:lang="no-nb" xml:id="id7"> + <delta insert="attribute value" xml:lang="en-US"> + <eta xml:lang="no"/> + <xi att="attribute value"> + <xi xml:lang="no"/> + <alpha or="this.nodeValue"> + <delta title="true" xml:id="id8"/> + <iota xml:lang="no"> + <omega xml:id="id9"> + <sigma> + <green>This text must be green</green> + </sigma> + </omega> + </iota> + </alpha> + </xi> + </delta> + </epsilon> + </pi> + </phi> + </gamma> + </theta> + </zeta> + </rho> + </omega> + </tree> + </test> + <test> + <xpath>//beta[@xml:id="id1"]//chi[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::theta[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//theta[starts-with(@string,"100")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]//tau[@attr][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@xml:id="id6"][not(preceding-sibling::*)]/zeta[@title="123456789"][@xml:id="id7"][not(preceding-sibling::*)]//xi[@xml:lang="nb"][not(preceding-sibling::*)]//lambda[starts-with(concat(@object,"-"),"false-")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]]/omega[@true][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::delta[@xml:id="id10"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[contains(concat(@true,"$"),"ue$")][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:id="id1"> + <chi xml:lang="en-GB" xml:id="id2"> + <epsilon xml:lang="no"/> + <theta xml:lang="no" xml:id="id3"> + <theta string="100%" xml:lang="en"/> + <chi/> + <omicron xml:lang="en-US" xml:id="id4"> + <tau attr="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <omicron xml:id="id6"> + <zeta title="123456789" xml:id="id7"> + <xi xml:lang="nb"> + <lambda object="false"/> + <omicron xml:lang="en-US" xml:id="id8"> + <omega true="_blank" xml:id="id9"/> + <delta xml:id="id10"/> + <theta true="true"> + <green>This text must be green</green> + </theta> + </omicron> + </xi> + </zeta> + </omicron> + </tau> + </omicron> + </theta> + </chi> + </beta> + </tree> + </test> + <test> + <xpath>//nu[starts-with(@name,"123456")][@xml:lang="nb"]//gamma[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id2"]/lambda[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)]//delta[starts-with(concat(@attr,"-"),"another attribute value-")][@xml:lang="en-US"][not(following-sibling::*)]//zeta[@xml:lang="en"][not(following-sibling::*)]//theta[starts-with(concat(@number,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::epsilon[contains(@src,"t")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@att][@xml:id="id6"][not(child::node())][following-sibling::psi[@xml:lang="en"]//theta[@attribute][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::lambda[@data="attribute value"][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@object]//mu[@xml:lang="en-GB"][@xml:id="id8"]//tau[@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]//delta[@xml:lang="en"][not(preceding-sibling::*)]//*[@xml:lang="en-US"][@xml:id="id10"][not(following-sibling::*)]/pi[@xml:lang="no"][@xml:id="id11"][not(child::node())][following-sibling::zeta[@xml:lang="nb"][@xml:id="id12"][preceding-sibling::*[position() = 1]]//gamma[not(preceding-sibling::*)][not(following-sibling::gamma)]/theta[contains(@attrib,"e")][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[starts-with(concat(@or,"-"),"another attribute value-")][@xml:id="id13"][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <nu name="123456789" xml:lang="nb"> + <gamma xml:lang="nb" xml:id="id1"/> + <delta xml:lang="en-GB" xml:id="id2"> + <lambda xml:lang="no" xml:id="id3"> + <delta attr="another attribute value" xml:lang="en-US"> + <zeta xml:lang="en"> + <theta number="attribute-value" xml:lang="nb" xml:id="id4"/> + <epsilon src="content" xml:id="id5"/> + <omicron att="another attribute value" xml:id="id6"/> + <psi xml:lang="en"> + <theta attribute="123456789" xml:id="id7"/> + <lambda data="attribute value" xml:lang="en-GB"> + <nu object="attribute-value"> + <mu xml:lang="en-GB" xml:id="id8"> + <tau xml:lang="en" xml:id="id9"> + <delta xml:lang="en"> + <any xml:lang="en-US" xml:id="id10"> + <pi xml:lang="no" xml:id="id11"/> + <zeta xml:lang="nb" xml:id="id12"> + <gamma> + <theta attrib="this.nodeValue"/> + <mu or="another attribute value" xml:id="id13"> + <green>This text must be green</green> + </mu> + </gamma> + </zeta> + </any> + </delta> + </tau> + </mu> + </nu> + </lambda> + </psi> + </zeta> + </delta> + </lambda> + </delta> + </nu> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@or,"-"),"_blank-")][@xml:id="id1"]//zeta[@xml:lang="en"][not(following-sibling::*)]//upsilon[@xml:id="id2"][not(preceding-sibling::*)]//eta[@true][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(@content,"on")][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@class][@xml:id="id4"][not(preceding-sibling::iota)][not(child::node())][following-sibling::omega[@false][@xml:lang="en-US"][preceding-sibling::*[position() = 2]]//*[@class][@xml:id="id5"][not(following-sibling::*)]/delta[starts-with(concat(@insert,"-"),"this.nodeValue-")][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="en-US"][@xml:id="id7"][not(following-sibling::*)]//lambda[starts-with(concat(@content,"-"),"this-")][@xml:lang="en-US"][following-sibling::*[position()=4]][not(child::node())][following-sibling::alpha[starts-with(@class,"attribute-v")][preceding-sibling::*[position() = 1]][following-sibling::theta[contains(@false,"bu")][@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::delta[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::beta[@name="_blank"][@xml:id="id9"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//gamma[@xml:lang="en-GB"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::delta[contains(concat(@desciption,"$"),"-is-att-value$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[contains(concat(@attr,"$"),"56789$")][@xml:lang="no"][preceding-sibling::*[position() = 2]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <mu or="_blank" xml:id="id1"> + <zeta xml:lang="en"> + <upsilon xml:id="id2"> + <eta true="true" xml:id="id3"> + <rho content="content"/> + <iota class="attribute" xml:id="id4"/> + <omega false="123456789" xml:lang="en-US"> + <any class="attribute value" xml:id="id5"> + <delta insert="this.nodeValue"/> + <omega xml:lang="en-GB" xml:id="id6"/> + <beta xml:lang="en-US" xml:id="id7"> + <lambda content="this-is-att-value" xml:lang="en-US"/> + <alpha class="attribute-value"/> + <theta false="attribute" xml:lang="nb" xml:id="id8"/> + <delta/> + <beta name="_blank" xml:id="id9"> + <gamma xml:lang="en-GB" xml:id="id10"/> + <delta desciption="this-is-att-value"/> + <kappa attr="123456789" xml:lang="no"> + <green>This text must be green</green> + </kappa> + </beta> + </beta> + </any> + </omega> + </eta> + </upsilon> + </zeta> + </mu> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="no-nb"]/*[contains(@class,"k")][@xml:lang="en-GB"]/beta[@desciption="false"][@xml:lang="en-GB"][not(preceding-sibling::*)][not(preceding-sibling::beta)][not(child::node())][following-sibling::sigma[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::pi[contains(concat(@title,"$"),"t$")][@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]/omega[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@xml:lang="en"][@xml:id="id2"]//mu[contains(@and,"bute va")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[contains(concat(@delete,"$"),"100%$")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::pi[@xml:id="id5"][not(child::node())][following-sibling::phi[contains(@src,"x green")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=6]][following-sibling::tau[contains(@object,"conte")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=5]][following-sibling::phi[following-sibling::xi[@false="content"][@xml:lang="en-GB"][@xml:id="id7"][preceding-sibling::*[position() = 5]][following-sibling::phi[@xml:lang="no"][@xml:id="id8"][preceding-sibling::*[position() = 6]][following-sibling::*[position()=2]][following-sibling::tau[@xml:id="id9"][preceding-sibling::*[position() = 7]][following-sibling::eta[@xml:id="id10"]//chi[@xml:id="id11"][not(preceding-sibling::*)][following-sibling::alpha[@false][@xml:lang="no"][@xml:id="id12"][not(following-sibling::*)]/iota[not(child::node())][following-sibling::zeta[@xml:lang="no"][@xml:id="id13"][not(following-sibling::*)]//beta[contains(@att,"lue")][@xml:lang="en-US"]/chi[@xml:lang="en-US"][@xml:id="id14"][not(preceding-sibling::*)][position() = 1]]]]][position() = 1]]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="no-nb"> + <any class="_blank" xml:lang="en-GB"> + <beta desciption="false" xml:lang="en-GB"/> + <sigma xml:lang="nb"/> + <pi title="content" xml:lang="no" xml:id="id1"> + <omega xml:lang="no-nb"> + <beta xml:lang="en" xml:id="id2"> + <mu and="attribute value" xml:lang="nb" xml:id="id3"> + <lambda delete="100%" xml:lang="en-US" xml:id="id4"/> + <pi xml:id="id5"/> + <phi src="solid 1px green" xml:lang="en-GB"/> + <tau object="content" xml:lang="en" xml:id="id6"/> + <phi/> + <xi false="content" xml:lang="en-GB" xml:id="id7"/> + <phi xml:lang="no" xml:id="id8"/> + <tau xml:id="id9"/> + <eta xml:id="id10"> + <chi xml:id="id11"/> + <alpha false="this.nodeValue" xml:lang="no" xml:id="id12"> + <iota/> + <zeta xml:lang="no" xml:id="id13"> + <beta att="this-is-att-value" xml:lang="en-US"> + <chi xml:lang="en-US" xml:id="id14"> + <green>This text must be green</green> + </chi> + </beta> + </zeta> + </alpha> + </eta> + </mu> + </beta> + </omega> + </pi> + </any> + </any> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="en"][@xml:id="id1"]/eta[@insert][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/delta[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::beta[starts-with(@attribute,"another attr")][@xml:lang="en"][@xml:id="id4"]/alpha[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::zeta[contains(@delete,"78")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@object][@xml:id="id6"]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="en" xml:id="id1"> + <eta insert="false" xml:lang="en-US" xml:id="id2"> + <delta xml:lang="no" xml:id="id3"/> + <beta attribute="another attribute value" xml:lang="en" xml:id="id4"> + <alpha xml:lang="en-US"/> + <zeta delete="123456789" xml:id="id5"/> + <xi object="true" xml:id="id6"> + <green>This text must be green</green> + </xi> + </beta> + </eta> + </mu> + </tree> + </test> + <test> + <xpath>//sigma[@number="content"][@xml:id="id1"]//xi[starts-with(concat(@attr,"-"),"this-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@or][not(preceding-sibling::upsilon)][following-sibling::rho[@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//psi[@xml:lang="en"][@xml:id="id3"]//beta[@xml:lang="en"][@xml:id="id4"][following-sibling::xi[@xml:lang="nb"][preceding-sibling::*[position() = 1]]/alpha[not(preceding-sibling::*)][following-sibling::xi[starts-with(concat(@token,"-"),"attribute-")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[contains(@title,"ibute")][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]/gamma[not(preceding-sibling::*)][following-sibling::pi[starts-with(@attr,"s")][@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/gamma[starts-with(concat(@string,"-"),"_blank-")][not(preceding-sibling::*)]/beta[@desciption][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omega[contains(@title,"ent")][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="en-US"][not(following-sibling::*)]/eta[contains(@src,"tent")][@xml:lang="no"][@xml:id="id9"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <sigma number="content" xml:id="id1"> + <xi attr="this-is-att-value" xml:lang="no-nb"/> + <upsilon or="false"/> + <rho xml:lang="nb" xml:id="id2"> + <psi xml:lang="en" xml:id="id3"> + <beta xml:lang="en" xml:id="id4"/> + <xi xml:lang="nb"> + <alpha/> + <xi token="attribute" xml:id="id5"/> + <xi title="attribute" xml:lang="en" xml:id="id6"> + <gamma/> + <pi attr="solid 1px green" xml:lang="no-nb" xml:id="id7"/> + <psi> + <gamma string="_blank"> + <beta desciption="this-is-att-value" xml:lang="no" xml:id="id8"/> + <omega title="content" xml:lang="no"/> + <phi xml:lang="en-US"> + <eta src="content" xml:lang="no" xml:id="id9"> + <green>This text must be green</green> + </eta> + </phi> + </gamma> + </psi> + </xi> + </xi> + </psi> + </rho> + </sigma> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@string,"tr")][@xml:lang="en-US"]/chi[@attribute="this.nodeValue"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::chi[not(child::node())][following-sibling::chi[starts-with(concat(@insert,"-"),"false-")][@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]/zeta//upsilon[@data][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[starts-with(@delete,"t")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::mu[not(following-sibling::*)]//iota[contains(concat(@desciption,"$"),"lse$")][@xml:lang="en-GB"][not(following-sibling::*)]//pi[@xml:lang="en"]//pi[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="en"][not(child::node())][following-sibling::chi[@xml:lang="en"][not(child::node())][following-sibling::eta//alpha[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[contains(concat(@insert,"$"),"ute$")][@xml:id="id6"][not(child::node())][following-sibling::lambda[contains(@attribute,"ue")][@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]]/mu[starts-with(concat(@attribute,"-"),"attribute-")][not(following-sibling::*)]//zeta[@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[starts-with(concat(@att,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]]]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <omega string="true" xml:lang="en-US"> + <chi attribute="this.nodeValue"/> + <nu xml:lang="nb" xml:id="id1"/> + <chi/> + <chi insert="false" xml:lang="en" xml:id="id2"> + <zeta> + <upsilon data="_blank" xml:id="id3"> + <tau delete="this.nodeValue" xml:lang="en" xml:id="id4"/> + <mu> + <iota desciption="false" xml:lang="en-GB"> + <pi xml:lang="en"> + <pi xml:lang="en-GB" xml:id="id5"> + <rho xml:lang="en"/> + <chi xml:lang="en"/> + <eta> + <alpha xml:lang="nb"> + <phi insert="attribute" xml:id="id6"/> + <lambda attribute="this.nodeValue" xml:lang="no" xml:id="id7"> + <mu attribute="attribute-value"> + <zeta xml:id="id8"/> + <gamma att="solid 1px green"> + <green>This text must be green</green> + </gamma> + </mu> + </lambda> + </alpha> + </eta> + </pi> + </pi> + </iota> + </mu> + </upsilon> + </zeta> + </chi> + </omega> + </tree> + </test> + <test> + <xpath>//beta[@abort="content"]/kappa[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:id="id1"][not(child::node())][following-sibling::rho[contains(@token,"lank")][@xml:lang="no"][preceding-sibling::*[position() = 1]]//nu[@data][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omicron[starts-with(concat(@number,"-"),"attribute-")][not(child::node())][following-sibling::rho[contains(@insert,"1px green")][not(following-sibling::*)]//psi[not(child::node())][following-sibling::beta[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <beta abort="content"> + <kappa src="this.nodeValue" xml:id="id1"/> + <rho token="_blank" xml:lang="no"> + <nu data="this.nodeValue"/> + <omicron number="attribute-value"/> + <rho insert="solid 1px green"> + <psi/> + <beta xml:lang="en-US" xml:id="id2"> + <green>This text must be green</green> + </beta> + </rho> + </rho> + </beta> + </tree> + </test> + <test> + <xpath>//theta[@insert][@xml:lang="en-GB"][@xml:id="id1"]/chi[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]//delta[@or="attribute-value"][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::mu[following-sibling::beta[@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <theta insert="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <chi xml:id="id2"/> + <zeta xml:lang="en-US" xml:id="id3"> + <delta or="attribute-value" xml:lang="en-GB" xml:id="id4"/> + <mu/> + <beta xml:id="id5"> + <green>This text must be green</green> + </beta> + </zeta> + </theta> + </tree> + </test> + <test> + <xpath>//epsilon//lambda[@token][@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::kappa[contains(concat(@att,"$"),"ute$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[@xml:id="id3"][not(following-sibling::*)]//nu[@xml:lang="nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::omega[@string="false"][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 2]]//beta[@number="true"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(@delete,"attr")][@xml:id="id6"][following-sibling::pi[@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]//chi[@xml:id="id8"][not(following-sibling::*)]//zeta[@and="this-is-att-value"][@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)]/kappa[@xml:id="id10"][following-sibling::beta[following-sibling::*[position()=3]][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id11"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::tau[@xml:id="id12"][following-sibling::omega[starts-with(concat(@attr,"-"),"true-")][@xml:lang="en"][@xml:id="id13"]/nu[@attribute="100%"][@xml:lang="no"][@xml:id="id14"][not(following-sibling::*)]/omicron[@xml:lang="en-GB"][@xml:id="id15"]//beta[starts-with(concat(@true,"-"),"attribute value-")][@xml:id="id16"][following-sibling::*[position()=1]][following-sibling::gamma[starts-with(@title,"s")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <epsilon> + <lambda token="solid 1px green" xml:lang="no" xml:id="id1"/> + <kappa att="attribute" xml:id="id2"> + <any xml:id="id3"> + <nu xml:lang="nb"/> + <iota xml:id="id4"/> + <omega string="false" xml:lang="no-nb" xml:id="id5"> + <beta number="true" xml:lang="no-nb"> + <beta delete="attribute value" xml:id="id6"/> + <pi xml:lang="en-US" xml:id="id7"/> + <delta xml:lang="no-nb"> + <chi xml:id="id8"> + <zeta and="this-is-att-value" xml:lang="no-nb" xml:id="id9"> + <kappa xml:id="id10"/> + <beta/> + <sigma xml:lang="en-US" xml:id="id11"/> + <tau xml:id="id12"/> + <omega attr="true" xml:lang="en" xml:id="id13"> + <nu attribute="100%" xml:lang="no" xml:id="id14"> + <omicron xml:lang="en-GB" xml:id="id15"> + <beta true="attribute value" xml:id="id16"/> + <gamma title="solid 1px green" xml:lang="no-nb"> + <green>This text must be green</green> + </gamma> + </omicron> + </nu> + </omega> + </zeta> + </chi> + </delta> + </beta> + </omega> + </any> + </kappa> + </epsilon> + </tree> + </test> + <test> + <xpath>//nu[starts-with(@class,"at")][@xml:lang="nb"][@xml:id="id1"]//mu[@insert][@xml:id="id2"][not(preceding-sibling::*)]/pi[contains(concat(@content,"$"),"k$")]/sigma[not(following-sibling::*)]//rho[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@and][@xml:id="id5"][following-sibling::*[position()=2]][not(preceding-sibling::omicron)][not(child::node())][following-sibling::beta[@class="true"][@xml:lang="nb"][following-sibling::rho[@xml:id="id6"][not(following-sibling::*)]//epsilon[not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/gamma[contains(concat(@src,"$"),"0%$")][@xml:lang="en"][@xml:id="id7"][following-sibling::lambda[starts-with(@desciption,"_bla")][@xml:id="id8"][preceding-sibling::*[position() = 1]]/sigma[@xml:id="id9"][not(following-sibling::*)]//eta[contains(@delete,"nt")][@xml:lang="nb"][@xml:id="id10"][not(following-sibling::*)][not(preceding-sibling::eta)]//alpha[following-sibling::*[position()=3]][following-sibling::upsilon[not(child::node())][following-sibling::omega[@number="solid 1px green"][not(child::node())][following-sibling::omega[@xml:lang="en-US"][@xml:id="id11"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/gamma[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][@xml:id="id12"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <nu class="attribute-value" xml:lang="nb" xml:id="id1"> + <mu insert="solid 1px green" xml:id="id2"> + <pi content="_blank"> + <sigma> + <rho xml:id="id3"/> + <pi xml:id="id4"/> + <omicron and="attribute" xml:id="id5"/> + <beta class="true" xml:lang="nb"/> + <rho xml:id="id6"> + <epsilon/> + <theta xml:lang="no"> + <gamma src="100%" xml:lang="en" xml:id="id7"/> + <lambda desciption="_blank" xml:id="id8"> + <sigma xml:id="id9"> + <eta delete="content" xml:lang="nb" xml:id="id10"> + <alpha/> + <upsilon/> + <omega number="solid 1px green"/> + <omega xml:lang="en-US" xml:id="id11"> + <gamma xml:lang="nb"/> + <nu xml:lang="en-GB" xml:id="id12"> + <green>This text must be green</green> + </nu> + </omega> + </eta> + </sigma> + </lambda> + </theta> + </rho> + </sigma> + </pi> + </mu> + </nu> + </tree> + </test> + <test> + <xpath>//kappa[@class="another attribute value"][@xml:lang="en-GB"][@xml:id="id1"]//nu[contains(concat(@att,"$"),"green$")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]//alpha[contains(@false,"100")][@xml:id="id3"][following-sibling::mu[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::tau[starts-with(concat(@class,"-"),"this.nodeValue-")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::nu[starts-with(@desciption,"f")][@xml:lang="no"][not(following-sibling::*)]/alpha[contains(concat(@content,"$"),"ue$")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::eta[@token][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::delta[starts-with(concat(@class,"-"),"100%-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/iota[starts-with(@true,"thi")][@xml:lang="no"][@xml:id="id8"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[contains(concat(@attrib,"$"),"content$")][@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <kappa class="another attribute value" xml:lang="en-GB" xml:id="id1"> + <nu att="solid 1px green" xml:lang="nb" xml:id="id2"> + <alpha false="100%" xml:id="id3"/> + <mu xml:lang="no" xml:id="id4"/> + <tau class="this.nodeValue" xml:lang="en-US" xml:id="id5"/> + <nu desciption="false" xml:lang="no"> + <alpha content="this.nodeValue" xml:lang="nb"/> + <tau xml:lang="no-nb" xml:id="id6"/> + <eta token="another attribute value" xml:lang="en-US" xml:id="id7"/> + <delta class="100%"> + <iota true="this.nodeValue" xml:lang="no" xml:id="id8"/> + <phi attrib="content" xml:lang="no" xml:id="id9"> + <green>This text must be green</green> + </phi> + </delta> + </nu> + </nu> + </kappa> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="no"][@xml:id="id1"]/gamma[contains(concat(@number,"$"),"ue$")][@xml:id="id2"]//beta[@src="true"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omega[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::kappa//alpha[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::kappa[starts-with(concat(@string,"-"),"attribute-")][not(following-sibling::*)]//zeta[@xml:lang="en-US"]//omicron[contains(@abort,"al")][@xml:lang="no"][not(following-sibling::omicron)][not(child::node())][following-sibling::epsilon[@xml:id="id3"][following-sibling::sigma[starts-with(@class,"100")][@xml:lang="en-US"][not(following-sibling::*)]//upsilon[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[contains(@att,"lid 1px gr")][@xml:lang="no-nb"][@xml:id="id5"]//delta[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::theta[@src][@xml:lang="no"][@xml:id="id6"][not(child::node())][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/tau[@xml:lang="en"][@xml:id="id9"][following-sibling::*[position()=2]][following-sibling::phi[@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@insert][not(following-sibling::*)]]]]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="no" xml:id="id1"> + <gamma number="true" xml:id="id2"> + <beta src="true"/> + <omega src="this.nodeValue" xml:lang="en"/> + <kappa> + <alpha xml:lang="no"/> + <kappa string="attribute"> + <zeta xml:lang="en-US"> + <omicron abort="false" xml:lang="no"/> + <epsilon xml:id="id3"/> + <sigma class="100%" xml:lang="en-US"> + <upsilon xml:lang="nb" xml:id="id4"> + <delta att="solid 1px green" xml:lang="no-nb" xml:id="id5"> + <delta/> + <theta src="attribute value" xml:lang="no" xml:id="id6"/> + <upsilon xml:lang="en-GB" xml:id="id7"/> + <eta xml:lang="en-GB" xml:id="id8"> + <tau xml:lang="en" xml:id="id9"/> + <phi xml:lang="nb" xml:id="id10"/> + <nu insert="true"> + <green>This text must be green</green> + </nu> + </eta> + </delta> + </upsilon> + </sigma> + </zeta> + </kappa> + </kappa> + </gamma> + </eta> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="nb"][@xml:id="id1"]//phi[starts-with(@or,"12345")][@xml:lang="en-US"][following-sibling::*[position()=4]][following-sibling::kappa[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][following-sibling::beta[@xml:id="id3"]/zeta[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@attr="attribute-value"][preceding-sibling::*[position() = 1]]//upsilon[contains(@delete,"e")][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id5"][following-sibling::gamma[@name]//alpha[@xml:id="id6"]/phi[@insert][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id7"]/omicron[@attrib][following-sibling::zeta[@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="no"][@xml:id="id9"][not(following-sibling::*)]/beta[not(child::node())][following-sibling::tau[contains(@class,"89")][@xml:lang="no"][@xml:id="id10"]//iota[@data][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::theta[@token="another attribute value"][@xml:lang="en-US"][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="nb" xml:id="id1"> + <phi or="123456789" xml:lang="en-US"/> + <kappa xml:lang="en"/> + <any xml:lang="nb" xml:id="id2"/> + <iota xml:lang="no-nb"/> + <beta xml:id="id3"> + <zeta xml:lang="en-US"/> + <delta attr="attribute-value"> + <upsilon delete="true" xml:id="id4"/> + <epsilon xml:lang="en-US" xml:id="id5"/> + <gamma name="123456789"> + <alpha xml:id="id6"> + <phi insert="solid 1px green" xml:lang="en-US"/> + <psi xml:lang="en"/> + <nu false="123456789" xml:lang="en-US" xml:id="id7"> + <omicron attrib="123456789"/> + <zeta xml:id="id8"/> + <iota xml:lang="no" xml:id="id9"> + <beta/> + <tau class="123456789" xml:lang="no" xml:id="id10"> + <iota data="123456789" xml:lang="no-nb"/> + <theta token="another attribute value" xml:lang="en-US" xml:id="id11"> + <green>This text must be green</green> + </theta> + </tau> + </iota> + </nu> + </alpha> + </gamma> + </delta> + </beta> + </any> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="nb"]//*[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::lambda[@attrib][preceding-sibling::*[position() = 1]][following-sibling::tau[contains(concat(@desciption,"$"),"789$")][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//rho[not(preceding-sibling::*)]/gamma[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id4"][not(child::node())][following-sibling::nu[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::*[@xml:lang="en-US"][not(child::node())][following-sibling::pi[@xml:id="id5"][following-sibling::omicron[contains(concat(@attrib,"$"),"alse$")][@xml:lang="en"][not(child::node())][following-sibling::xi[@name="content"][@xml:lang="en-US"][preceding-sibling::*[position() = 6]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>1</nth> + </result> + <tree> + <any xml:lang="nb"> + <any xml:id="id1"/> + <lambda attrib="solid 1px green"/> + <tau desciption="123456789" xml:lang="en" xml:id="id2"> + <rho> + <gamma xml:lang="no-nb" xml:id="id3"/> + <beta xml:id="id4"/> + <nu xml:lang="nb"/> + <any xml:lang="en-US"/> + <pi xml:id="id5"/> + <omicron attrib="false" xml:lang="en"/> + <xi name="content" xml:lang="en-US"> + <green>This text must be green</green> + </xi> + </rho> + </tau> + </any> + </tree> + </test> + <test> + <xpath>//kappa[@name][@xml:lang="no"][@xml:id="id1"]/zeta[starts-with(@or,"attribu")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[contains(concat(@and,"$"),"his-is-att-value$")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)]//omicron[@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]//rho[starts-with(concat(@false,"-"),"attribute value-")][@xml:id="id5"][not(preceding-sibling::*)]/omega[starts-with(concat(@attrib,"-"),"attribute-")][following-sibling::*[position()=2]][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::rho[starts-with(concat(@abort,"-"),"content-")][preceding-sibling::*[position() = 2]]//kappa[@false="false"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id7"][preceding-sibling::*[position() = 1]]/delta[@xml:id="id8"]//sigma[contains(@false,"x gree")][@xml:lang="en-US"][@xml:id="id9"][following-sibling::pi[@xml:lang="no-nb"][not(following-sibling::*)]/upsilon[contains(concat(@token,"$"),"solid 1px green$")][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="en"]/upsilon[@xml:lang="no"][not(following-sibling::*)]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <kappa name="solid 1px green" xml:lang="no" xml:id="id1"> + <zeta or="attribute-value" xml:id="id2"> + <iota and="this-is-att-value" xml:lang="no" xml:id="id3"> + <omicron xml:lang="no" xml:id="id4"> + <rho false="attribute value" xml:id="id5"> + <omega attrib="attribute"/> + <delta xml:lang="en-GB" xml:id="id6"/> + <rho abort="content"> + <kappa false="false"/> + <eta xml:id="id7"> + <delta xml:id="id8"> + <sigma false="solid 1px green" xml:lang="en-US" xml:id="id9"/> + <pi xml:lang="no-nb"> + <upsilon token="solid 1px green"/> + <upsilon xml:lang="en"> + <upsilon xml:lang="no"> + <green>This text must be green</green> + </upsilon> + </upsilon> + </pi> + </delta> + </eta> + </rho> + </rho> + </omicron> + </iota> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//gamma[contains(@attrib,"lse")][@xml:lang="en-US"][@xml:id="id1"]//xi[contains(@string,"t")][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[contains(@attr,"ri")][@xml:id="id2"]/theta[contains(@data,"tent")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@true][@xml:lang="no-nb"][not(following-sibling::*)]/kappa[@false][@xml:lang="no"][following-sibling::*[position()=2]][following-sibling::tau[@or][@xml:id="id4"][not(child::node())][following-sibling::omicron[@attrib="content"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/sigma[contains(concat(@object,"$"),"attribute$")][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::chi[not(following-sibling::*)]//*[@xml:lang="en"][@xml:id="id5"]/mu[contains(concat(@name,"$"),"tribute value$")][not(child::node())][following-sibling::xi[@xml:id="id6"][preceding-sibling::*[position() = 1]]/beta[starts-with(@delete,"att")][@xml:id="id7"][not(child::node())][following-sibling::delta[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@title][@xml:id="id10"][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <gamma attrib="false" xml:lang="en-US" xml:id="id1"> + <xi string="this-is-att-value"/> + <xi attr="attribute value" xml:id="id2"> + <theta data="content" xml:id="id3"/> + <psi true="another attribute value" xml:lang="no-nb"> + <kappa false="100%" xml:lang="no"/> + <tau or="100%" xml:id="id4"/> + <omicron attrib="content"> + <sigma object="attribute"/> + <delta xml:lang="en-US"/> + <chi> + <any xml:lang="en" xml:id="id5"> + <mu name="another attribute value"/> + <xi xml:id="id6"> + <beta delete="attribute value" xml:id="id7"/> + <delta xml:lang="en-US" xml:id="id8"> + <kappa xml:id="id9"/> + <pi title="this.nodeValue" xml:id="id10"> + <green>This text must be green</green> + </pi> + </delta> + </xi> + </any> + </chi> + </omicron> + </psi> + </xi> + </gamma> + </tree> + </test> + <test> + <xpath>//tau[@name][@xml:lang="no"][@xml:id="id1"]/nu[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 1]]//pi[@data="attribute"][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::epsilon[starts-with(@src,"this.")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(@token,"a")][@xml:id="id4"][following-sibling::theta[contains(concat(@class,"$"),"100%$")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=3]][following-sibling::alpha[starts-with(@attrib,"at")][following-sibling::*[position()=2]][following-sibling::eta[@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 6]][not(following-sibling::*)]//*[contains(concat(@att,"$"),"true$")][following-sibling::omicron[not(following-sibling::*)][not(preceding-sibling::omicron)]/gamma[@token="solid 1px green"][@xml:lang="no-nb"][not(following-sibling::*)]//xi[starts-with(@att,"attribute-va")][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[starts-with(concat(@token,"-"),"123456789-")][@xml:id="id8"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <tau name="content" xml:lang="no" xml:id="id1"> + <nu xml:lang="nb" xml:id="id2"/> + <pi> + <pi data="attribute" xml:lang="en-GB" xml:id="id3"/> + <epsilon src="this.nodeValue" xml:lang="nb"/> + <delta token="false" xml:id="id4"/> + <theta class="100%" xml:lang="en-US" xml:id="id5"/> + <alpha attrib="attribute-value"/> + <eta xml:lang="nb" xml:id="id6"/> + <tau> + <any att="true"/> + <omicron> + <gamma token="solid 1px green" xml:lang="no-nb"> + <xi att="attribute-value" xml:lang="en" xml:id="id7"/> + <chi token="123456789" xml:id="id8"> + <green>This text must be green</green> + </chi> + </gamma> + </omicron> + </tau> + </pi> + </tau> + </tree> + </test> + <test> + <xpath>//lambda//mu[@attr="true"][@xml:lang="en-US"][@xml:id="id1"][following-sibling::sigma[preceding-sibling::*[position() = 1]][following-sibling::iota[not(child::node())][following-sibling::eta[contains(concat(@true,"$"),"attribute value$")][not(following-sibling::*)]//chi[not(child::node())][following-sibling::psi[@xml:id="id2"][not(child::node())][following-sibling::tau[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//gamma[@true][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=9]][following-sibling::lambda[not(child::node())][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=7]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::*[@xml:lang="en"][not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::zeta[@xml:id="id5"][not(child::node())][following-sibling::kappa[@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::zeta[@xml:id="id7"][not(child::node())][following-sibling::delta[@attr][@xml:lang="en"][preceding-sibling::*[position() = 9]]//omicron[contains(@class,"ttrib")][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <mu attr="true" xml:lang="en-US" xml:id="id1"/> + <sigma/> + <iota/> + <eta true="attribute value"> + <chi/> + <psi xml:id="id2"/> + <tau xml:lang="no" xml:id="id3"> + <gamma true="attribute-value" xml:lang="nb"/> + <lambda/> + <gamma xml:lang="no-nb" xml:id="id4"/> + <rho/> + <any xml:lang="en"/> + <omicron/> + <zeta xml:id="id5"/> + <kappa xml:id="id6"/> + <zeta xml:id="id7"/> + <delta attr="attribute value" xml:lang="en"> + <omicron class="attribute"> + <green>This text must be green</green> + </omicron> + </delta> + </tau> + </eta> + </lambda> + </tree> + </test> + <test> + <xpath>//omicron/upsilon[contains(@token,"56789")][@xml:lang="en"][@xml:id="id1"][following-sibling::*[position()=6]][following-sibling::theta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[@data][@xml:id="id2"][not(child::node())][following-sibling::psi[contains(concat(@name,"$"),"k$")][@xml:id="id3"][preceding-sibling::*[position() = 3]][following-sibling::chi[@object][@xml:id="id4"][not(child::node())][following-sibling::rho[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::eta[@xml:lang="en"][@xml:id="id6"]//alpha[@desciption="content"][@xml:id="id7"][not(preceding-sibling::*)]//pi[@attribute][not(preceding-sibling::*)][not(preceding-sibling::pi)]/zeta[contains(@data,"t")][@xml:lang="en"][@xml:id="id8"][not(child::node())][following-sibling::kappa[@false][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[starts-with(concat(@abort,"-"),"content-")][@xml:lang="en-US"][not(following-sibling::*)]/beta[@or][@xml:lang="en-GB"][following-sibling::mu[@token][@xml:id="id10"]//alpha[contains(concat(@and,"$"),"00%$")]//xi[@number][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:id="id11"][not(following-sibling::*)]//tau[@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[contains(@insert,"so")][@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@xml:id="id14"]][position() = 1]]][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omicron> + <upsilon token="123456789" xml:lang="en" xml:id="id1"/> + <theta/> + <phi data="this.nodeValue" xml:id="id2"/> + <psi name="_blank" xml:id="id3"/> + <chi object="another attribute value" xml:id="id4"/> + <rho xml:lang="en-US" xml:id="id5"/> + <eta xml:lang="en" xml:id="id6"> + <alpha desciption="content" xml:id="id7"> + <pi attribute="true"> + <zeta data="content" xml:lang="en" xml:id="id8"/> + <kappa false="this.nodeValue" xml:id="id9"/> + <nu abort="content" xml:lang="en-US"> + <beta or="attribute value" xml:lang="en-GB"/> + <mu token="attribute" xml:id="id10"> + <alpha and="100%"> + <xi number="content" xml:lang="en-GB"> + <iota xml:id="id11"> + <tau xml:id="id12"> + <sigma insert="solid 1px green" xml:id="id13"> + <mu xml:id="id14"> + <green>This text must be green</green> + </mu> + </sigma> + </tau> + </iota> + </xi> + </alpha> + </mu> + </nu> + </pi> + </alpha> + </eta> + </omicron> + </tree> + </test> + <test> + <xpath>//omicron/phi[@xml:id="id1"][not(following-sibling::*)]/omicron[starts-with(@false,"attri")][@xml:id="id2"][not(child::node())][following-sibling::delta[@xml:id="id3"][preceding-sibling::*[position() = 1]]/gamma[following-sibling::psi[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][following-sibling::chi[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::*[starts-with(concat(@data,"-"),"false-")][@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 5]][following-sibling::epsilon[@xml:lang="no"][@xml:id="id7"][not(following-sibling::*)]//beta[@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id9"]//theta[@number][not(following-sibling::*)]//psi[@xml:lang="nb"][@xml:id="id10"][following-sibling::sigma[@string="solid 1px green"]//epsilon[@xml:lang="en-GB"][@xml:id="id11"][not(following-sibling::*)]/kappa[contains(concat(@class,"$"),"nk$")][@xml:lang="no-nb"][not(preceding-sibling::*)]//sigma[@xml:lang="no-nb"][@xml:id="id12"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>1</nth> + </result> + <tree> + <omicron> + <phi xml:id="id1"> + <omicron false="attribute" xml:id="id2"/> + <delta xml:id="id3"> + <gamma/> + <psi xml:lang="en-GB" xml:id="id4"/> + <tau xml:lang="en-GB"/> + <chi/> + <any data="false" xml:id="id5"/> + <omega xml:lang="en-GB" xml:id="id6"/> + <epsilon xml:lang="no" xml:id="id7"> + <beta xml:lang="nb" xml:id="id8"> + <upsilon xml:id="id9"> + <theta number="123456789"> + <psi xml:lang="nb" xml:id="id10"/> + <sigma string="solid 1px green"> + <epsilon xml:lang="en-GB" xml:id="id11"> + <kappa class="_blank" xml:lang="no-nb"> + <sigma xml:lang="no-nb" xml:id="id12"> + <green>This text must be green</green> + </sigma> + </kappa> + </epsilon> + </sigma> + </theta> + </upsilon> + </beta> + </epsilon> + </delta> + </phi> + </omicron> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-GB"][@xml:id="id1"]/psi[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@title="another attribute value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[starts-with(concat(@token,"-"),"solid 1px green-")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::mu[contains(@delete,"%")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::eta[preceding-sibling::*[position() = 2]][not(following-sibling::eta)][following-sibling::delta[@token][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-GB" xml:id="id1"> + <psi xml:lang="nb"/> + <phi xml:lang="nb" xml:id="id2"/> + <omicron title="another attribute value"> + <lambda token="solid 1px green" xml:lang="en" xml:id="id3"/> + <mu delete="100%" xml:lang="no"/> + <eta/> + <delta token="true" xml:id="id4"> + <green>This text must be green</green> + </delta> + </omicron> + </phi> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="en-GB"]//xi[not(preceding-sibling::*)]//omicron[@xml:lang="en"][@xml:id="id1"][not(following-sibling::*)]/xi[contains(concat(@or,"$"),"lue$")][@xml:lang="en-US"][not(following-sibling::*)]//delta[not(following-sibling::*)][not(preceding-sibling::delta)]/*[@desciption="solid 1px green"][@xml:lang="en-US"]/sigma[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::mu[@xml:lang="no-nb"]/delta[@desciption][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//lambda[starts-with(@title,"10")][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[contains(@class,"fa")][@xml:id="id3"][preceding-sibling::*[position() = 1]]/delta[not(child::node())][following-sibling::zeta[starts-with(concat(@token,"-"),"attribute-")]/kappa[@token="this.nodeValue"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@xml:id="id5"][not(preceding-sibling::*)]//kappa[contains(concat(@string,"$"),"ibute-value$")][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::tau[contains(@desciption,"789")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="en-GB"> + <xi> + <omicron xml:lang="en" xml:id="id1"> + <xi or="this.nodeValue" xml:lang="en-US"> + <delta> + <any desciption="solid 1px green" xml:lang="en-US"> + <sigma xml:lang="en-US" xml:id="id2"/> + <mu xml:lang="no-nb"> + <delta desciption="attribute value" xml:lang="en-GB"/> + <rho xml:lang="no-nb"> + <lambda title="100%"> + <rho xml:lang="en-US"/> + <nu class="false" xml:id="id3"> + <delta/> + <zeta token="attribute-value"> + <kappa token="this.nodeValue" xml:id="id4"/> + <gamma xml:lang="nb"> + <psi xml:id="id5"> + <kappa string="attribute-value" xml:id="id6"/> + <tau desciption="123456789" xml:lang="en-US" xml:id="id7"> + <green>This text must be green</green> + </tau> + </psi> + </gamma> + </zeta> + </nu> + </lambda> + </rho> + </mu> + </any> + </delta> + </xi> + </omicron> + </xi> + </rho> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(@and,"false")][@xml:lang="no"][@xml:id="id1"]/xi[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[not(following-sibling::*)]/lambda[not(following-sibling::*)]/xi[@class="attribute-value"][@xml:id="id3"]/omicron[not(preceding-sibling::*)][following-sibling::omega[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::delta[contains(concat(@true,"$"),"value$")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::xi[@desciption][@xml:id="id7"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon and="false" xml:lang="no" xml:id="id1"> + <xi xml:lang="no" xml:id="id2"/> + <mu> + <lambda> + <xi class="attribute-value" xml:id="id3"> + <omicron/> + <omega xml:id="id4"> + <any xml:lang="nb" xml:id="id5"/> + <delta true="another attribute value" xml:lang="en-US" xml:id="id6"/> + <xi desciption="true" xml:id="id7"> + <green>This text must be green</green> + </xi> + </omega> + </xi> + </lambda> + </mu> + </epsilon> + </tree> + </test> + <test> + <xpath>//sigma//zeta[@xml:lang="no"][not(following-sibling::*)]/beta[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::beta)][not(child::node())][following-sibling::pi[starts-with(concat(@name,"-"),"false-")][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/iota[starts-with(@att,"co")][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(concat(@attribute,"-"),"another attribute value-")][@xml:id="id3"]/alpha[starts-with(concat(@title,"-"),"another attribute value-")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@true="content"][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]//pi[not(preceding-sibling::*)][not(following-sibling::*)]/alpha[not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@attr,"-"),"another attribute value-")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 2]][following-sibling::epsilon[@xml:id="id6"][following-sibling::lambda[@att][@xml:lang="en-GB"][preceding-sibling::*[position() = 4]]/*[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <zeta xml:lang="no"> + <beta xml:lang="en-GB" xml:id="id1"/> + <pi name="false" xml:lang="no-nb" xml:id="id2"> + <iota att="content"/> + <pi attribute="another attribute value" xml:id="id3"> + <alpha title="another attribute value" xml:lang="nb"> + <sigma true="content" xml:lang="nb" xml:id="id4"> + <pi> + <alpha/> + <nu attr="another attribute value" xml:id="id5"/> + <sigma/> + <epsilon xml:id="id6"/> + <lambda att="true" xml:lang="en-GB"> + <any xml:lang="en-US" xml:id="id7"> + <green>This text must be green</green> + </any> + </lambda> + </pi> + </sigma> + </alpha> + </pi> + </pi> + </zeta> + </sigma> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="no-nb"][@xml:id="id1"]/kappa[contains(@object,"co")][not(following-sibling::*)]/xi[@false][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[not(preceding-sibling::*)][following-sibling::rho[@attrib][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no-nb"]/phi[starts-with(@true,"this.nodeVal")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[@xml:id="id4"][not(following-sibling::*)]/lambda[contains(@title,"3456789")][not(preceding-sibling::*)]//epsilon[contains(concat(@false,"$"),"se$")][@xml:id="id5"]/alpha[@src="false"][@xml:lang="en-GB"][following-sibling::beta[not(preceding-sibling::beta)][not(child::node())][following-sibling::zeta[@attr="this.nodeValue"][@xml:id="id6"][not(following-sibling::*)]//phi//kappa[not(following-sibling::*)]//iota[contains(@src,"ue")][not(preceding-sibling::*)][not(following-sibling::*)]/psi[not(preceding-sibling::*)][not(following-sibling::*)]/phi[@object="another attribute value"][not(preceding-sibling::*)][not(following-sibling::phi)]//beta[not(following-sibling::*)]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="no-nb" xml:id="id1"> + <kappa object="content"> + <xi false="_blank" xml:lang="en-US"> + <psi/> + <rho attrib="attribute" xml:lang="no" xml:id="id2"> + <iota xml:lang="no-nb"/> + <iota xml:lang="no-nb"> + <phi true="this.nodeValue" xml:lang="no" xml:id="id3"/> + <chi xml:id="id4"> + <lambda title="123456789"> + <epsilon false="false" xml:id="id5"> + <alpha src="false" xml:lang="en-GB"/> + <beta/> + <zeta attr="this.nodeValue" xml:id="id6"> + <phi> + <kappa> + <iota src="true"> + <psi> + <phi object="another attribute value"> + <beta> + <green>This text must be green</green> + </beta> + </phi> + </psi> + </iota> + </kappa> + </phi> + </zeta> + </epsilon> + </lambda> + </chi> + </iota> + </rho> + </xi> + </kappa> + </xi> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="no"][@xml:id="id1"]//delta[contains(concat(@att,"$"),"ribute-value$")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]//phi[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::*[preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::eta[@xml:id="id5"]//eta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@desciption][@xml:lang="no"][not(following-sibling::*)]/chi[starts-with(@data,"attribut")][not(preceding-sibling::*)]/chi[following-sibling::omega[@xml:lang="nb"][@xml:id="id6"][not(child::node())][following-sibling::beta[@insert="another attribute value"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::rho[starts-with(@src,"true")][preceding-sibling::*[position() = 3]][following-sibling::pi[starts-with(@token,"1")][@xml:lang="en-GB"][@xml:id="id7"][following-sibling::iota[@xml:id="id8"][preceding-sibling::*[position() = 5]]//kappa[contains(@abort,"lue")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@token="false"][@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)][not(preceding-sibling::eta)]/mu[@insert="another attribute value"][@xml:id="id10"][not(child::node())][following-sibling::chi[@attrib][not(following-sibling::*)]/xi[@name][@xml:id="id11"][not(preceding-sibling::*)]/theta[contains(@title,"no")][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]]]]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="no" xml:id="id1"> + <delta att="attribute-value" xml:lang="no" xml:id="id2"> + <phi xml:id="id3"/> + <epsilon xml:id="id4"/> + <any/> + <eta xml:id="id5"> + <eta xml:lang="no-nb"/> + <upsilon desciption="attribute" xml:lang="no"> + <chi data="attribute"> + <chi/> + <omega xml:lang="nb" xml:id="id6"/> + <beta insert="another attribute value"/> + <rho src="true"/> + <pi token="100%" xml:lang="en-GB" xml:id="id7"/> + <iota xml:id="id8"> + <kappa abort="this.nodeValue" xml:lang="no-nb"/> + <eta token="false" xml:lang="no-nb" xml:id="id9"> + <mu insert="another attribute value" xml:id="id10"/> + <chi attrib="100%"> + <xi name="another attribute value" xml:id="id11"> + <theta title="this.nodeValue"> + <green>This text must be green</green> + </theta> + </xi> + </chi> + </eta> + </iota> + </chi> + </upsilon> + </eta> + </delta> + </nu> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en-GB"]/rho[@xml:lang="en"][not(following-sibling::*)]//eta[@token="123456789"][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[starts-with(@or,"tru")][@xml:id="id1"][not(following-sibling::*)]/delta[starts-with(@desciption,"this.")][@xml:id="id2"]//phi[starts-with(@token,"100%")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::alpha[preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:id="id4"][preceding-sibling::*[position() = 2]]//psi[@xml:id="id5"]//zeta[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)]/phi[@src][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(preceding-sibling::tau)]/eta[contains(concat(@title,"$"),"true$")][@xml:id="id7"]//delta[contains(concat(@number,"$"),"attribute value$")][@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)]//chi[@desciption][@xml:id="id9"]//phi[@token][@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@attribute][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id11"]//zeta[@xml:lang="en-US"][@xml:id="id12"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@number][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="no-nb"][@xml:id="id13"][not(child::node())][following-sibling::delta[@data="_blank"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="en-GB"> + <rho xml:lang="en"> + <eta token="123456789" xml:lang="no"/> + <kappa or="true" xml:id="id1"> + <delta desciption="this.nodeValue" xml:id="id2"> + <phi token="100%" xml:lang="no-nb" xml:id="id3"/> + <alpha/> + <mu xml:id="id4"> + <psi xml:id="id5"> + <zeta xml:lang="en" xml:id="id6"> + <phi src="123456789" xml:lang="no"/> + <tau xml:lang="en"> + <eta title="true" xml:id="id7"> + <delta number="attribute value" xml:lang="nb" xml:id="id8"> + <chi desciption="attribute-value" xml:id="id9"> + <phi token="true" xml:lang="en-US" xml:id="id10"> + <xi attribute="123456789"/> + <epsilon xml:id="id11"> + <zeta xml:lang="en-US" xml:id="id12"/> + <pi number="attribute-value"/> + <omicron xml:lang="no-nb" xml:id="id13"/> + <delta data="_blank"> + <green>This text must be green</green> + </delta> + </epsilon> + </phi> + </chi> + </delta> + </eta> + </tau> + </zeta> + </psi> + </mu> + </delta> + </kappa> + </rho> + </psi> + </tree> + </test> + <test> + <xpath>//omega[@true][@xml:lang="en-US"][@xml:id="id1"]/delta[following-sibling::chi[@abort][@xml:lang="en"][following-sibling::kappa[preceding-sibling::*[position() = 2]]//lambda//tau[@xml:lang="nb"][@xml:id="id2"]//beta[contains(concat(@token,"$"),"false$")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="no"][not(following-sibling::*)]//iota[starts-with(@desciption,"_")][@xml:id="id5"][not(following-sibling::*)]//xi[@xml:id="id6"][following-sibling::rho[@attr][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[starts-with(concat(@name,"-"),"100%-")][@xml:lang="en-US"][not(preceding-sibling::*)]//alpha[@xml:lang="no-nb"][@xml:id="id8"]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <omega true="true" xml:lang="en-US" xml:id="id1"> + <delta/> + <chi abort="true" xml:lang="en"/> + <kappa> + <lambda> + <tau xml:lang="nb" xml:id="id2"> + <beta token="false" xml:id="id3"/> + <gamma xml:lang="en"> + <chi xml:id="id4"/> + <xi xml:lang="no"> + <iota desciption="_blank" xml:id="id5"> + <xi xml:id="id6"/> + <rho attr="true" xml:lang="en" xml:id="id7"> + <beta name="100%" xml:lang="en-US"> + <alpha xml:lang="no-nb" xml:id="id8"> + <green>This text must be green</green> + </alpha> + </beta> + </rho> + </iota> + </xi> + </gamma> + </tau> + </lambda> + </kappa> + </omega> + </tree> + </test> + <test> + <xpath>//zeta/kappa[contains(@desciption,"nk")][not(preceding-sibling::*)][following-sibling::omega[@abort="another attribute value"][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@class="true"][@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::iota[contains(@insert,"ute val")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <zeta> + <kappa desciption="_blank"/> + <omega abort="another attribute value" xml:lang="no-nb"/> + <lambda class="true" xml:lang="no-nb" xml:id="id1"/> + <iota insert="another attribute value"/> + <chi xml:lang="no" xml:id="id2"> + <green>This text must be green</green> + </chi> + </zeta> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-GB"]//eta[contains(@attr,"23")][not(following-sibling::*)]/lambda[contains(concat(@true,"$"),"789$")][@xml:lang="en-GB"][@xml:id="id1"]/xi[@xml:lang="en"][@xml:id="id2"]/beta[contains(@data,"%")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::chi[contains(@or,"ibu")][@xml:id="id3"][following-sibling::upsilon[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@number][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//chi[not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@att,"attri")][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[starts-with(concat(@object,"-"),"another attribute value-")][@xml:lang="no"]//omicron[not(preceding-sibling::*)][not(following-sibling::*)]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-GB"> + <eta attr="123456789"> + <lambda true="123456789" xml:lang="en-GB" xml:id="id1"> + <xi xml:lang="en" xml:id="id2"> + <beta data="100%" xml:lang="en"/> + <chi or="another attribute value" xml:id="id3"/> + <upsilon xml:lang="en-GB"/> + <phi number="false" xml:id="id4"> + <chi/> + <lambda att="attribute value"/> + <eta object="another attribute value" xml:lang="no"> + <omicron> + <green>This text must be green</green> + </omicron> + </eta> + </phi> + </xi> + </lambda> + </eta> + </any> + </tree> + </test> + <test> + <xpath>//beta[starts-with(@object,"attribut")][@xml:lang="no-nb"]/mu[@xml:lang="en"][not(following-sibling::*)][not(following-sibling::mu)]/theta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::theta[@true="attribute"][@xml:lang="nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//phi[contains(concat(@string,"$"),"nt$")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::epsilon[@title][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <beta object="attribute" xml:lang="no-nb"> + <mu xml:lang="en"> + <theta xml:lang="en-US"/> + <theta true="attribute" xml:lang="nb" xml:id="id1"/> + <delta xml:lang="en-GB"> + <phi string="content" xml:id="id2"/> + <epsilon title="this.nodeValue" xml:lang="no-nb"> + <green>This text must be green</green> + </epsilon> + </delta> + </mu> + </beta> + </tree> + </test> + <test> + <xpath>//omega[@xml:id="id1"]//tau[contains(@insert,"00%")][@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[starts-with(@object,"attribute ")][@xml:lang="no-nb"][@xml:id="id3"]/beta[starts-with(@desciption,"solid 1px ")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@true][@xml:id="id5"][not(following-sibling::*)]//alpha[contains(concat(@desciption,"$"),"e$")][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]/omicron[contains(concat(@insert,"$"),"0%$")][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)]/kappa[contains(concat(@delete,"$"),"rue$")][@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)]//omega[@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)]//nu[@xml:lang="no"][@xml:id="id10"]/kappa[@insert][@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::kappa[starts-with(concat(@name,"-"),"content-")][@xml:lang="en"][not(following-sibling::*)]/phi[not(preceding-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:id="id1"> + <tau insert="100%" xml:lang="en" xml:id="id2"/> + <beta object="attribute value" xml:lang="no-nb" xml:id="id3"> + <beta desciption="solid 1px green" xml:lang="no" xml:id="id4"> + <nu true="true" xml:id="id5"> + <alpha desciption="false"/> + <gamma xml:lang="en-GB" xml:id="id6"> + <omicron insert="100%" xml:lang="nb" xml:id="id7"> + <kappa delete="true" xml:lang="en-US" xml:id="id8"> + <omega xml:lang="en-GB" xml:id="id9"> + <nu xml:lang="no" xml:id="id10"> + <kappa insert="100%" xml:lang="no-nb" xml:id="id11"/> + <kappa name="content" xml:lang="en"> + <phi> + <green>This text must be green</green> + </phi> + </kappa> + </nu> + </omega> + </kappa> + </omicron> + </gamma> + </nu> + </beta> + </beta> + </omega> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="no"][@xml:id="id1"]/iota[starts-with(@content,"this-is-att-valu")][not(preceding-sibling::iota)]/zeta[@title][not(following-sibling::*)]//sigma[@delete="this-is-att-value"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[following-sibling::*[preceding-sibling::*[position() = 2]]/iota[@xml:id="id3"][not(child::node())][following-sibling::omega[@delete][following-sibling::iota[@desciption][@xml:lang="en"][preceding-sibling::*[position() = 2]]//upsilon[following-sibling::*[position()=2]][not(following-sibling::upsilon)][not(child::node())][following-sibling::chi[@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::alpha[@att][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="no" xml:id="id1"> + <iota content="this-is-att-value"> + <zeta title="123456789"> + <sigma delete="this-is-att-value" xml:id="id2"/> + <any/> + <any> + <iota xml:id="id3"/> + <omega delete="attribute value"/> + <iota desciption="this-is-att-value" xml:lang="en"> + <upsilon/> + <chi xml:id="id4"/> + <alpha att="this-is-att-value" xml:lang="nb"> + <green>This text must be green</green> + </alpha> + </iota> + </any> + </zeta> + </iota> + </nu> + </tree> + </test> + <test> + <xpath>//delta[contains(@title,"his")][@xml:lang="en-US"]/tau[@xml:lang="en"][not(following-sibling::*)]//rho[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::iota[@xml:lang="en"][@xml:id="id2"][following-sibling::theta[@att="123456789"][@xml:id="id3"][following-sibling::gamma[@or="solid 1px green"]/delta[starts-with(concat(@desciption,"-"),"100%-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id4"][following-sibling::*[contains(@attribute,"t")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//delta[@string="attribute-value"][@xml:lang="no-nb"][following-sibling::pi[following-sibling::tau[@att][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[starts-with(@abort,"co")][@xml:lang="no"][not(preceding-sibling::*)][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <delta title="this.nodeValue" xml:lang="en-US"> + <tau xml:lang="en"> + <rho xml:lang="no-nb" xml:id="id1"/> + <iota xml:lang="en" xml:id="id2"/> + <theta att="123456789" xml:id="id3"/> + <gamma or="solid 1px green"> + <delta desciption="100%" xml:lang="en-GB"/> + <delta xml:id="id4"/> + <any attribute="content" xml:lang="en-US"> + <delta string="attribute-value" xml:lang="no-nb"/> + <pi/> + <tau att="_blank" xml:lang="no-nb" xml:id="id5"> + <mu abort="content" xml:lang="no"> + <green>This text must be green</green> + </mu> + </tau> + </any> + </gamma> + </tau> + </delta> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en-GB"][@xml:id="id1"]//rho[contains(@src,"ute va")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::chi[starts-with(concat(@string,"-"),"attribute-")][@xml:lang="en-GB"][following-sibling::*[position()=3]][not(child::node())][following-sibling::chi[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="en-US"][not(child::node())][following-sibling::sigma[@data][preceding-sibling::*[position() = 4]][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en-GB" xml:id="id1"> + <rho src="attribute value" xml:lang="en-GB"/> + <chi string="attribute" xml:lang="en-GB"/> + <chi xml:id="id2"/> + <mu xml:lang="en-US"/> + <sigma data="another attribute value"> + <green>This text must be green</green> + </sigma> + </upsilon> + </tree> + </test> + <test> + <xpath>//mu[@attribute="true"][@xml:lang="no-nb"]/zeta[@and="attribute-value"][not(preceding-sibling::*)]//lambda[starts-with(@class,"attribute")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::sigma[@xml:id="id1"][not(child::node())][following-sibling::*[starts-with(@attribute,"content")][@xml:id="id2"][following-sibling::beta[@token][@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::kappa[@token][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::mu[contains(concat(@title,"$"),"te$")]//phi[@title="false"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::*[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[not(following-sibling::*)]//phi[starts-with(@number,"123")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::*[@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::sigma[starts-with(@content,"this.n")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[not(child::node())][following-sibling::omega[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 4]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <mu attribute="true" xml:lang="no-nb"> + <zeta and="attribute-value"> + <lambda class="attribute-value" xml:lang="en"/> + <sigma xml:id="id1"/> + <any attribute="content" xml:id="id2"/> + <beta token="123456789" xml:lang="en-US"/> + <kappa token="this.nodeValue"/> + <mu title="attribute"> + <phi title="false" xml:id="id3"/> + <any xml:lang="en-GB" xml:id="id4"> + <lambda> + <phi number="123456789" xml:id="id5"> + <chi xml:lang="en-GB" xml:id="id6"/> + <any xml:lang="en-US" xml:id="id7"/> + <sigma content="this.nodeValue"/> + <kappa/> + <omega xml:lang="en-US" xml:id="id8"> + <green>This text must be green</green> + </omega> + </phi> + </lambda> + </any> + </mu> + </zeta> + </mu> + </tree> + </test> + <test> + <xpath>//chi[@attribute]//kappa[starts-with(concat(@number,"-"),"attribute value-")][@xml:id="id1"][not(following-sibling::*)]//lambda[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[starts-with(@attribute,"100")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]]/*[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]//beta[@xml:id="id5"][not(following-sibling::*)]/psi[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[@number][not(child::node())][following-sibling::beta[starts-with(@object,"sol")]//upsilon[starts-with(@or,"false")][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(concat(@abort,"$"),"reen$")][@xml:lang="no-nb"][@xml:id="id6"][not(child::node())][following-sibling::omicron[@or][not(following-sibling::*)]//xi[@insert][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@xml:id="id9"][not(child::node())][following-sibling::eta[@or][@xml:id="id10"][not(child::node())][following-sibling::omicron//iota[@xml:lang="nb"][following-sibling::iota[@xml:lang="en"][@xml:id="id11"]//psi[contains(@attribute,"0")][not(preceding-sibling::*)]//iota[@xml:lang="no-nb"][@xml:id="id12"][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <chi attribute="attribute value"> + <kappa number="attribute value" xml:id="id1"> + <lambda xml:id="id2"/> + <xi attribute="100%"/> + <omicron token="attribute" xml:lang="no" xml:id="id3"> + <any xml:lang="no" xml:id="id4"> + <beta xml:id="id5"> + <psi xml:lang="en-US"/> + <psi number="false"/> + <beta object="solid 1px green"> + <upsilon or="false"> + <psi abort="solid 1px green" xml:lang="no-nb" xml:id="id6"/> + <omicron or="false"> + <xi insert="attribute value" xml:lang="en" xml:id="id7"/> + <phi xml:lang="nb" xml:id="id8"> + <any xml:id="id9"/> + <eta or="this-is-att-value" xml:id="id10"/> + <omicron> + <iota xml:lang="nb"/> + <iota xml:lang="en" xml:id="id11"> + <psi attribute="100%"> + <iota xml:lang="no-nb" xml:id="id12"/> + <zeta> + <green>This text must be green</green> + </zeta> + </psi> + </iota> + </omicron> + </phi> + </omicron> + </upsilon> + </beta> + </beta> + </any> + </omicron> + </kappa> + </chi> + </tree> + </test> + <test> + <xpath>//chi[starts-with(@attr,"another attribu")][@xml:id="id1"]/omicron[@attr="123456789"][not(preceding-sibling::*)]/delta[not(preceding-sibling::*)][not(child::node())][following-sibling::chi[starts-with(@insert,"a")][@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::lambda[contains(@object,"se")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omicron[@xml:lang="no-nb"][not(following-sibling::*)]//*[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[contains(@name,"_blan")][@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::upsilon[@xml:id="id6"][following-sibling::epsilon[@xml:lang="no"][@xml:id="id7"]/*[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::mu[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@delete][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::eta[@xml:id="id9"][preceding-sibling::*[position() = 3]][following-sibling::omega[@desciption="_blank"][@xml:id="id10"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//rho[@att="another attribute value"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@xml:id="id12"][not(preceding-sibling::*)]//theta[@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <chi attr="another attribute value" xml:id="id1"> + <omicron attr="123456789"> + <delta/> + <chi insert="attribute" xml:lang="nb" xml:id="id2"/> + <lambda object="false" xml:lang="no" xml:id="id3"> + <omicron xml:lang="no-nb"> + <any xml:lang="en-US" xml:id="id4"/> + <any name="_blank" xml:lang="en" xml:id="id5"/> + <upsilon xml:id="id6"/> + <epsilon xml:lang="no" xml:id="id7"> + <any attr="attribute" xml:lang="no-nb"/> + <mu/> + <epsilon delete="solid 1px green" xml:lang="en-GB" xml:id="id8"/> + <eta xml:id="id9"/> + <omega desciption="_blank" xml:id="id10"> + <rho att="another attribute value" xml:id="id11"> + <mu xml:id="id12"> + <theta xml:id="id13"> + <green>This text must be green</green> + </theta> + </mu> + </rho> + </omega> + </epsilon> + </omicron> + </lambda> + </omicron> + </chi> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]//theta[@xml:lang="en"]/nu[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[@src="this.nodeValue"][not(child::node())][following-sibling::gamma[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omicron[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <theta xml:lang="en"> + <nu xml:lang="en-GB" xml:id="id2"/> + <zeta src="this.nodeValue"/> + <gamma xml:lang="en-US"> + <omicron xml:lang="en"> + <green>This text must be green</green> + </omicron> + </gamma> + </theta> + </gamma> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@content,"$"),"px green$")][@xml:id="id1"]//lambda[contains(concat(@false,"$"),"0%$")][@xml:lang="en-GB"]//nu[starts-with(concat(@name,"-"),"attribute value-")][@xml:id="id2"][not(preceding-sibling::*)]//nu/beta[contains(concat(@number,"$"),"rue$")][not(preceding-sibling::*)]/chi[@xml:id="id3"]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <iota content="solid 1px green" xml:id="id1"> + <lambda false="100%" xml:lang="en-GB"> + <nu name="attribute value" xml:id="id2"> + <nu> + <beta number="true"> + <chi xml:id="id3"> + <green>This text must be green</green> + </chi> + </beta> + </nu> + </nu> + </lambda> + </iota> + </tree> + </test> + <test> + <xpath>//alpha[contains(@content,"ibute v")][@xml:id="id1"]/kappa[@number][@xml:lang="en-US"][not(preceding-sibling::*)]//*[@xml:lang="nb"][not(following-sibling::*)]/gamma[@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[not(following-sibling::*)]/phi[@string="attribute-value"][@xml:lang="no"][not(child::node())][following-sibling::epsilon[contains(concat(@string,"$"),"56789$")][not(following-sibling::*)]/sigma[@att][@xml:id="id4"]//nu[@xml:lang="en-GB"][following-sibling::pi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[contains(@insert,"ue")][@xml:lang="no-nb"][@xml:id="id5"][following-sibling::delta[@content][@xml:lang="nb"][@xml:id="id6"][following-sibling::sigma[contains(@string,"ls")][@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <alpha content="attribute value" xml:id="id1"> + <kappa number="attribute-value" xml:lang="en-US"> + <any xml:lang="nb"> + <gamma xml:id="id2"/> + <kappa xml:lang="no" xml:id="id3"/> + <kappa> + <phi string="attribute-value" xml:lang="no"/> + <epsilon string="123456789"> + <sigma att="attribute value" xml:id="id4"> + <nu xml:lang="en-GB"/> + <pi> + <omicron insert="true" xml:lang="no-nb" xml:id="id5"/> + <delta content="123456789" xml:lang="nb" xml:id="id6"/> + <sigma string="false" xml:id="id7"> + <green>This text must be green</green> + </sigma> + </pi> + </sigma> + </epsilon> + </kappa> + </any> + </kappa> + </alpha> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en"]/omega[starts-with(concat(@name,"-"),"solid 1px green-")][not(preceding-sibling::*)]/mu[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@attr][not(following-sibling::*)]/eta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[contains(@false,"e")][@xml:lang="no-nb"][not(preceding-sibling::*)]//omicron[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[contains(concat(@att,"$"),"lue$")][not(child::node())][following-sibling::eta[starts-with(concat(@false,"-"),"100%-")][@xml:id="id2"][not(child::node())][following-sibling::mu[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//omicron[@xml:lang="nb"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::zeta[@xml:id="id5"][not(following-sibling::*)]//upsilon[@token][@xml:lang="en-US"]//rho[@xml:lang="nb"]//pi[@xml:lang="en"][@xml:id="id6"]/*[@attr]//omega[@token="attribute value"]/gamma[@src="attribute-value"][@xml:id="id7"]/mu[@xml:id="id8"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>1</nth> + </result> + <tree> + <omicron xml:lang="en"> + <omega name="solid 1px green"> + <mu xml:lang="en-US"> + <eta attr="100%"> + <eta xml:lang="no"> + <xi false="false" xml:lang="no-nb"> + <omicron xml:lang="no-nb"> + <xi xml:id="id1"/> + <rho att="this.nodeValue"/> + <eta false="100%" xml:id="id2"/> + <mu xml:lang="en-US" xml:id="id3"> + <omicron xml:lang="nb" xml:id="id4"/> + <zeta xml:id="id5"> + <upsilon token="another attribute value" xml:lang="en-US"> + <rho xml:lang="nb"> + <pi xml:lang="en" xml:id="id6"> + <any attr="this-is-att-value"> + <omega token="attribute value"> + <gamma src="attribute-value" xml:id="id7"> + <mu xml:id="id8"> + <green>This text must be green</green> + </mu> + </gamma> + </omega> + </any> + </pi> + </rho> + </upsilon> + </zeta> + </mu> + </omicron> + </xi> + </eta> + </eta> + </mu> + </omega> + </omicron> + </tree> + </test> + <test> + <xpath>//eta[starts-with(@att,"tru")][@xml:lang="no-nb"][@xml:id="id1"]//*[@name="false"][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::psi[@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::zeta[not(child::node())][following-sibling::iota[@insert][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::xi[@xml:id="id5"][not(following-sibling::*)]/theta[starts-with(concat(@attrib,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:id="id6"][not(preceding-sibling::*)]/kappa[starts-with(concat(@true,"-"),"solid 1px green-")][@xml:id="id7"][not(child::node())][following-sibling::iota[starts-with(concat(@name,"-"),"attribute value-")][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::omicron[following-sibling::iota[starts-with(@title,"this-is-att-val")][@xml:lang="en-GB"][@xml:id="id9"]/xi[contains(@title,"attribut")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[contains(concat(@att,"$"),"true$")]/*[@src][@xml:lang="en"][following-sibling::*[position()=4]][not(child::node())][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id10"][not(child::node())][following-sibling::nu[@string][following-sibling::delta[starts-with(concat(@insert,"-"),"_blank-")][@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id11"][preceding-sibling::*[position() = 4]]//zeta[@att="100%"][@xml:lang="en-GB"][not(following-sibling::*)]//pi[@xml:id="id12"][following-sibling::lambda[@xml:id="id13"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <eta att="true" xml:lang="no-nb" xml:id="id1"> + <any name="false" xml:lang="en" xml:id="id2"/> + <theta xml:lang="en-GB" xml:id="id3"/> + <psi xml:lang="nb" xml:id="id4"/> + <zeta/> + <iota insert="false"/> + <xi xml:id="id5"> + <theta attrib="attribute"> + <lambda xml:id="id6"> + <kappa true="solid 1px green" xml:id="id7"/> + <iota name="attribute value"/> + <sigma xml:lang="en-GB" xml:id="id8"/> + <omicron/> + <iota title="this-is-att-value" xml:lang="en-GB" xml:id="id9"> + <xi title="attribute" xml:lang="no-nb"/> + <phi att="true"> + <any src="_blank" xml:lang="en"/> + <kappa xml:lang="en-US" xml:id="id10"/> + <nu string="true"/> + <delta insert="_blank" xml:lang="en-US"/> + <lambda xml:id="id11"> + <zeta att="100%" xml:lang="en-GB"> + <pi xml:id="id12"/> + <lambda xml:id="id13"> + <green>This text must be green</green> + </lambda> + </zeta> + </lambda> + </phi> + </iota> + </lambda> + </theta> + </xi> + </eta> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en-GB"]//pi[@xml:id="id1"]/sigma[@xml:lang="no-nb"][@xml:id="id2"][not(child::node())][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id4"]//chi[@xml:lang="en-US"][not(preceding-sibling::chi)]//alpha[starts-with(@insert,"c")][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="en-GB"> + <pi xml:id="id1"> + <sigma xml:lang="no-nb" xml:id="id2"/> + <alpha xml:id="id3"/> + <alpha xml:lang="en-GB" xml:id="id4"> + <chi xml:lang="en-US"> + <alpha insert="content"/> + <mu xml:lang="en-GB"> + <green>This text must be green</green> + </mu> + </chi> + </alpha> + </pi> + </omicron> + </tree> + </test> + <test> + <xpath>//zeta[contains(@delete,"alse")][@xml:lang="en"][@xml:id="id1"]//beta[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota/zeta[@or="true"][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:id="id3"]/tau[contains(@attribute,"ibu")][@xml:lang="en-US"]//pi[@attr][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <zeta delete="false" xml:lang="en" xml:id="id1"> + <beta xml:lang="no-nb" xml:id="id2"/> + <iota> + <zeta or="true" xml:lang="no"/> + <tau xml:id="id3"> + <tau attribute="attribute" xml:lang="en-US"> + <pi attr="solid 1px green"> + <green>This text must be green</green> + </pi> + </tau> + </tau> + </iota> + </zeta> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="nb"][@xml:id="id1"]//alpha[starts-with(@object,"con")][not(preceding-sibling::*)]//rho[starts-with(concat(@true,"-"),"another attribute value-")][@xml:lang="en"][@xml:id="id2"]/eta[@xml:lang="en-GB"][@xml:id="id3"][following-sibling::upsilon[@abort][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/nu[@xml:lang="en"][following-sibling::gamma[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[starts-with(@content,"_")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[@xml:id="id5"][not(child::node())][following-sibling::epsilon[@object="123456789"]//upsilon[@true][not(following-sibling::*)]//*[contains(@att,"123456789")][@xml:lang="nb"][@xml:id="id6"][following-sibling::sigma[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[starts-with(concat(@name,"-"),"this.nodeValue-")][@xml:lang="en-US"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="nb" xml:id="id1"> + <alpha object="content"> + <rho true="another attribute value" xml:lang="en" xml:id="id2"> + <eta xml:lang="en-GB" xml:id="id3"/> + <upsilon abort="this-is-att-value" xml:lang="nb"> + <nu xml:lang="en"/> + <gamma xml:id="id4"> + <psi content="_blank" xml:lang="no"/> + <sigma xml:id="id5"/> + <epsilon object="123456789"> + <upsilon true="this-is-att-value"> + <any att="123456789" xml:lang="nb" xml:id="id6"/> + <sigma xml:lang="en-US"> + <nu name="this.nodeValue" xml:lang="en-US"> + <green>This text must be green</green> + </nu> + </sigma> + </upsilon> + </epsilon> + </gamma> + </upsilon> + </rho> + </alpha> + </omega> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="en-GB"][@xml:id="id1"]/kappa[@and][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:id="id2"]/tau[not(preceding-sibling::*)][following-sibling::zeta[@string="true"][@xml:lang="nb"][following-sibling::theta[@delete="solid 1px green"][@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]//omicron[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="en"][preceding-sibling::*[position() = 1]]//zeta[@and][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[starts-with(@number,"attribute value")][@xml:id="id5"][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="en-GB" xml:id="id1"> + <kappa and="attribute" xml:lang="no-nb"/> + <pi xml:id="id2"> + <tau/> + <zeta string="true" xml:lang="nb"/> + <theta delete="solid 1px green" xml:lang="nb" xml:id="id3"> + <omicron xml:lang="no"/> + <psi xml:lang="en"> + <zeta and="true" xml:id="id4"/> + <rho number="attribute value" xml:id="id5"> + <green>This text must be green</green> + </rho> + </psi> + </theta> + </pi> + </xi> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(@attr,"attribute val")][@xml:id="id1"]/pi[@xml:lang="en-US"][not(preceding-sibling::*)]//upsilon[starts-with(concat(@true,"-"),"attribute-")][following-sibling::nu[@or][@xml:id="id2"][not(following-sibling::*)]//delta[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::xi/omicron[starts-with(concat(@string,"-"),"another attribute value-")]/rho[@false][@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]/*[@xml:lang="no-nb"]/mu[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:id="id6"][preceding-sibling::*[position() = 1]]//lambda[contains(@data,"ttribute-va")][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omicron attr="attribute value" xml:id="id1"> + <pi xml:lang="en-US"> + <upsilon true="attribute-value"/> + <nu or="_blank" xml:id="id2"> + <delta xml:id="id3"/> + <xi> + <omicron string="another attribute value"> + <rho false="attribute value" xml:lang="en-US" xml:id="id4"> + <any xml:lang="no-nb"> + <mu xml:lang="nb" xml:id="id5"/> + <epsilon xml:id="id6"> + <lambda data="attribute-value" xml:id="id7"> + <sigma> + <green>This text must be green</green> + </sigma> + </lambda> + </epsilon> + </any> + </rho> + </omicron> + </xi> + </nu> + </pi> + </omicron> + </tree> + </test> + <test> + <xpath>//zeta[@class][@xml:lang="en"][@xml:id="id1"]/*[contains(concat(@insert,"$"),"attribute-value$")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]//chi[contains(@title,"tt-value")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[not(child::node())][following-sibling::rho[starts-with(@true,"at")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[contains(concat(@and,"$"),"blank$")][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]/eta[@xml:lang="no"][following-sibling::xi[@xml:lang="en-GB"]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <zeta class="_blank" xml:lang="en" xml:id="id1"> + <any insert="attribute-value" xml:lang="no" xml:id="id2"> + <chi title="this-is-att-value" xml:lang="no"/> + <xi/> + <rho true="attribute value" xml:lang="en-GB"/> + <epsilon and="_blank" xml:id="id3"/> + <xi xml:lang="no" xml:id="id4"> + <eta xml:lang="no"/> + <xi xml:lang="en-GB"> + <green>This text must be green</green> + </xi> + </xi> + </any> + </zeta> + </tree> + </test> + <test> + <xpath>//beta//*[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][not(following-sibling::*)]/psi[@xml:lang="en"][@xml:id="id2"]//kappa[starts-with(concat(@abort,"-"),"another attribute value-")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@or][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::nu or following-sibling::nu)]//gamma[@xml:id="id3"][not(following-sibling::*)]/beta[starts-with(@true,"this.node")][@xml:lang="no"][@xml:id="id4"]//omega[@number][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:lang="en-GB"][@xml:id="id6"]/xi[@xml:id="id7"]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <beta> + <any xml:lang="no" xml:id="id1"/> + <lambda xml:lang="en-GB"> + <psi xml:lang="en" xml:id="id2"> + <kappa abort="another attribute value" xml:lang="en-US"/> + <nu or="_blank"> + <gamma xml:id="id3"> + <beta true="this.nodeValue" xml:lang="no" xml:id="id4"> + <omega number="100%" xml:lang="en" xml:id="id5"> + <phi xml:lang="en-US"/> + <tau xml:lang="no"> + <beta xml:lang="en-GB" xml:id="id6"> + <xi xml:id="id7"> + <green>This text must be green</green> + </xi> + </beta> + </tau> + </omega> + </beta> + </gamma> + </nu> + </psi> + </lambda> + </beta> + </tree> + </test> + <test> + <xpath>//*[@name="123456789"][@xml:id="id1"]//iota[@attribute][following-sibling::omicron[@string][not(following-sibling::*)]//mu[not(preceding-sibling::*)][following-sibling::gamma[@and][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::gamma)]//upsilon[not(preceding-sibling::*)][following-sibling::phi[contains(@string,"attribute-value")][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[starts-with(@delete,"solid")][preceding-sibling::*[position() = 2]]//xi[not(following-sibling::*)]/zeta[@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <any name="123456789" xml:id="id1"> + <iota attribute="this-is-att-value"/> + <omicron string="123456789"> + <mu/> + <gamma and="attribute-value" xml:lang="no-nb"> + <upsilon/> + <phi string="attribute-value"/> + <nu delete="solid 1px green"> + <xi> + <zeta xml:lang="en-GB" xml:id="id2"> + <green>This text must be green</green> + </zeta> + </xi> + </nu> + </gamma> + </omicron> + </any> + </tree> + </test> + <test> + <xpath>//psi[starts-with(@or,"this.nodeVa")][@xml:lang="no"]/phi[@xml:lang="nb"][not(child::node())][following-sibling::nu[@data="this.nodeValue"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:id="id1"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/iota[starts-with(@src,"conten")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::iota)][following-sibling::chi[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <psi or="this.nodeValue" xml:lang="no"> + <phi xml:lang="nb"/> + <nu data="this.nodeValue"/> + <beta xml:id="id1"> + <iota src="content" xml:lang="nb"/> + <chi xml:id="id2"/> + <sigma xml:lang="no-nb" xml:id="id3"> + <green>This text must be green</green> + </sigma> + </beta> + </psi> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@and,"-"),"attribute-")]//mu[@xml:id="id1"]//sigma[not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 1]]/chi[starts-with(concat(@attr,"-"),"attribute value-")][@xml:lang="no-nb"][@xml:id="id2"][not(child::node())][following-sibling::eta[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[contains(concat(@or,"$"),"ontent$")][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//upsilon/upsilon[starts-with(concat(@attrib,"-"),"false-")][@xml:lang="no-nb"][@xml:id="id6"][following-sibling::*[position()=4]][following-sibling::epsilon[contains(concat(@name,"$"),"tribute value$")][@xml:lang="en"][@xml:id="id7"][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[contains(concat(@desciption,"$"),"ute$")][preceding-sibling::*[position() = 2]][following-sibling::beta[@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::phi[@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]//kappa[contains(concat(@attrib,"$"),"ribute value$")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@src][@xml:lang="en"][following-sibling::xi[@insert][@xml:id="id10"][following-sibling::zeta[@xml:id="id11"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[starts-with(concat(@name,"-"),"content-")][@xml:lang="en-GB"][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][preceding-sibling::*[position() = 4]]//sigma[@data][@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::*[@xml:id="id12"][preceding-sibling::*[position() = 1]]//kappa[@src][@xml:lang="en-GB"][@xml:id="id13"][not(following-sibling::*)]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <mu and="attribute"> + <mu xml:id="id1"> + <sigma/> + <sigma> + <chi attr="attribute value" xml:lang="no-nb" xml:id="id2"/> + <eta xml:id="id3"> + <zeta or="content" xml:lang="no-nb" xml:id="id4"/> + <alpha/> + <psi xml:lang="en-GB" xml:id="id5"> + <upsilon> + <upsilon attrib="false" xml:lang="no-nb" xml:id="id6"/> + <epsilon name="another attribute value" xml:lang="en" xml:id="id7"/> + <rho desciption="attribute"/> + <beta xml:id="id8"/> + <phi xml:lang="en-US" xml:id="id9"> + <kappa attrib="another attribute value" xml:lang="en"> + <epsilon src="true" xml:lang="en"/> + <xi insert="this.nodeValue" xml:id="id10"/> + <zeta xml:id="id11"/> + <kappa name="content" xml:lang="en-GB"/> + <pi xml:lang="no-nb"> + <sigma data="true" xml:lang="no-nb"/> + <any xml:id="id12"> + <kappa src="_blank" xml:lang="en-GB" xml:id="id13"> + <green>This text must be green</green> + </kappa> + </any> + </pi> + </kappa> + </phi> + </upsilon> + </psi> + </eta> + </sigma> + </mu> + </mu> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(@attr,"this.no")][@xml:id="id1"]//xi[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@insert,"attribu")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[@string="solid 1px green"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::mu[contains(concat(@string,"$"),"e$")][@xml:lang="en-GB"][@xml:id="id4"][following-sibling::lambda[@token="100%"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::beta[@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][following-sibling::upsilon[preceding-sibling::*[position() = 4]][following-sibling::alpha[starts-with(concat(@object,"-"),"100%-")][@xml:id="id5"][preceding-sibling::*[position() = 5]][following-sibling::sigma[@class][@xml:lang="no-nb"][preceding-sibling::*[position() = 6]][not(following-sibling::*)][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <alpha attr="this.nodeValue" xml:id="id1"> + <xi xml:lang="no-nb" xml:id="id2"/> + <lambda insert="attribute-value"> + <rho string="solid 1px green" xml:id="id3"/> + <mu string="true" xml:lang="en-GB" xml:id="id4"/> + <lambda token="100%"/> + <beta xml:lang="no-nb"/> + <upsilon/> + <alpha object="100%" xml:id="id5"/> + <sigma class="this-is-att-value" xml:lang="no-nb"> + <green>This text must be green</green> + </sigma> + </lambda> + </alpha> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="no-nb"]//epsilon[not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:lang="no-nb"][@xml:id="id1"][following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="nb"][following-sibling::*[position()=2]][following-sibling::kappa[@attr="123456789"][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[contains(@title,"e")][@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/psi[starts-with(@content,"attrib")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::pi[contains(concat(@and,"$"),"0%$")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="nb"][preceding-sibling::*[position() = 2]]/zeta[@xml:id="id5"][not(child::node())][following-sibling::lambda[starts-with(@true,"this.nodeVa")][@xml:id="id6"][preceding-sibling::*[position() = 1]]/theta[starts-with(@title,"f")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)]/delta[contains(concat(@name,"$"),"alue$")][@xml:lang="no-nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[contains(@attribute,"ttribu")][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::theta[@or][@xml:id="id9"]//rho[@abort="another attribute value"][not(following-sibling::*)]/phi[not(child::node())][following-sibling::iota[@xml:lang="en"][@xml:id="id10"][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 2]][following-sibling::delta[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/omega[@xml:lang="nb"][not(preceding-sibling::*)]/lambda[starts-with(concat(@content,"-"),"_blank-")][@xml:id="id11"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="no-nb"> + <epsilon> + <delta xml:lang="no-nb" xml:id="id1"/> + <tau false="123456789" xml:lang="nb"/> + <kappa attr="123456789" xml:lang="en" xml:id="id2"/> + <phi title="content" xml:lang="en-US" xml:id="id3"> + <psi content="attribute-value" xml:lang="en" xml:id="id4"/> + <pi and="100%" xml:lang="no"/> + <delta xml:lang="nb"> + <zeta xml:id="id5"/> + <lambda true="this.nodeValue" xml:id="id6"> + <theta title="false" xml:lang="no" xml:id="id7"> + <delta name="attribute value" xml:lang="no-nb"/> + <tau attribute="attribute" xml:id="id8"/> + <theta or="solid 1px green" xml:id="id9"> + <rho abort="another attribute value"> + <phi/> + <iota xml:lang="en" xml:id="id10"/> + <phi/> + <delta> + <omega xml:lang="nb"> + <lambda content="_blank" xml:id="id11"> + <green>This text must be green</green> + </lambda> + </omega> + </delta> + </rho> + </theta> + </theta> + </lambda> + </delta> + </phi> + </epsilon> + </pi> + </tree> + </test> + <test> + <xpath>//rho/iota[contains(concat(@object,"$"),"89$")][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[@xml:lang="nb"][not(following-sibling::*)]//nu[@xml:lang="en-GB"][@xml:id="id3"]//kappa[@number][@xml:lang="en-US"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::*[@att][not(child::node())][following-sibling::iota[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//gamma[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::omicron[@attr][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(following-sibling::omicron)][following-sibling::beta[starts-with(@attrib,"a")]//mu[contains(@content,"se")][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[starts-with(concat(@number,"-"),"another attribute value-")][@xml:id="id5"][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//alpha[starts-with(@insert,"attr")][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::omicron[@xml:id="id8"][preceding-sibling::*[position() = 1]]//iota[@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <iota object="123456789" xml:id="id1"/> + <gamma xml:lang="en-US" xml:id="id2"> + <eta xml:lang="nb"> + <nu xml:lang="en-GB" xml:id="id3"> + <kappa number="attribute-value" xml:lang="en-US" xml:id="id4"/> + <any att="false"/> + <iota xml:lang="en-GB"> + <gamma xml:lang="nb"/> + <omicron attr="_blank" xml:lang="no"/> + <beta attrib="attribute value"> + <mu content="false"/> + <psi number="another attribute value" xml:id="id5"/> + <omega/> + <kappa token="attribute-value" xml:lang="en-US" xml:id="id6"> + <alpha insert="attribute-value" xml:id="id7"/> + <omicron xml:id="id8"> + <iota xml:lang="en-GB" xml:id="id9"> + <green>This text must be green</green> + </iota> + </omicron> + </kappa> + </beta> + </iota> + </nu> + </eta> + </gamma> + </rho> + </tree> + </test> + <test> + <xpath>//chi[contains(concat(@insert,"$"),"ontent$")]//delta[contains(@and,"l")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[contains(concat(@class,"$"),"lse$")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:lang="nb"][following-sibling::delta[starts-with(concat(@token,"-"),"attribute value-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[starts-with(concat(@or,"-"),"this-")][following-sibling::*[position()=7]][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::gamma[@false][@xml:id="id3"][following-sibling::kappa[following-sibling::alpha[contains(@and,"lue")][@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::delta[not(child::node())][following-sibling::pi[@insert][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 7]][not(following-sibling::*)]]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <chi insert="content"> + <delta and="solid 1px green" xml:lang="en-GB"> + <eta class="false" xml:id="id1"> + <theta xml:lang="nb"/> + <delta token="attribute value"> + <delta or="this-is-att-value"/> + <kappa xml:lang="en-US" xml:id="id2"/> + <gamma false="another attribute value" xml:id="id3"/> + <kappa/> + <alpha and="attribute value" xml:lang="en-GB" xml:id="id4"/> + <delta/> + <pi insert="another attribute value" xml:lang="no"/> + <delta xml:lang="no-nb" xml:id="id5"> + <green>This text must be green</green> + </delta> + </delta> + </eta> + </delta> + </chi> + </tree> + </test> + <test> + <xpath>//xi[starts-with(@attr,"thi")]/rho[contains(concat(@title,"$"),"ttribute$")][@xml:lang="no-nb"][following-sibling::epsilon[@xml:lang="en-GB"][@xml:id="id1"][following-sibling::omicron[@xml:lang="en"][not(following-sibling::*)]//beta[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="no"][not(preceding-sibling::*)]/iota[@xml:lang="nb"]/lambda[@xml:id="id2"][not(preceding-sibling::*)]/omega[not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(concat(@false,"-"),"attribute-")][@xml:id="id3"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <xi attr="this-is-att-value"> + <rho title="attribute" xml:lang="no-nb"/> + <epsilon xml:lang="en-GB" xml:id="id1"/> + <omicron xml:lang="en"> + <beta att="attribute-value" xml:lang="no"> + <iota xml:lang="nb"> + <lambda xml:id="id2"> + <omega/> + <kappa false="attribute-value" xml:id="id3"> + <green>This text must be green</green> + </kappa> + </lambda> + </iota> + </beta> + </omicron> + </xi> + </tree> + </test> + <test> + <xpath>//theta[@false]/mu[@attrib][@xml:id="id1"][not(following-sibling::*)]//lambda[@and][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id3"]/epsilon[following-sibling::delta[@xml:id="id4"][preceding-sibling::*[position() = 1]]/mu[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]]//theta[@xml:lang="en-GB"][@xml:id="id7"][following-sibling::pi[contains(@name,"en")][@xml:lang="en-GB"][@xml:id="id8"]//zeta[@title][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[not(following-sibling::*)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <theta false="this-is-att-value"> + <mu attrib="false" xml:id="id1"> + <lambda and="this.nodeValue" xml:lang="en-GB" xml:id="id2"/> + <psi xml:lang="en-GB" xml:id="id3"> + <epsilon/> + <delta xml:id="id4"> + <mu xml:id="id5"/> + <lambda xml:lang="nb" xml:id="id6"> + <theta xml:lang="en-GB" xml:id="id7"/> + <pi name="solid 1px green" xml:lang="en-GB" xml:id="id8"> + <zeta title="this-is-att-value" xml:lang="nb" xml:id="id9"> + <rho> + <green>This text must be green</green> + </rho> + </zeta> + </pi> + </lambda> + </delta> + </psi> + </mu> + </theta> + </tree> + </test> + <test> + <xpath>//psi[starts-with(concat(@name,"-"),"solid 1px green-")][@xml:lang="nb"]//pi[not(preceding-sibling::*)]/xi[starts-with(concat(@src,"-"),"100%-")][@xml:lang="en"][not(child::node())][following-sibling::omicron[contains(@delete,"l")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::upsilon[@src="this-is-att-value"][@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::beta[@xml:id="id2"][preceding-sibling::*[position() = 4]]//nu[@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]/delta[@xml:lang="en-GB"][not(following-sibling::*)]//omega[@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]/gamma[@xml:id="id5"][not(child::node())][following-sibling::lambda[starts-with(concat(@insert,"-"),"true-")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::tau[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@abort="_blank"]//mu[@xml:lang="no-nb"][not(child::node())][following-sibling::pi[not(following-sibling::*)]//chi[@xml:lang="en-US"]/gamma[@false][@xml:lang="en-US"][not(preceding-sibling::*)][not(preceding-sibling::gamma)][following-sibling::rho[contains(concat(@content,"$"),"e$")][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::rho)]//epsilon[@xml:id="id7"][not(following-sibling::*)]/beta[@class][@xml:lang="no"][@xml:id="id8"]//alpha[starts-with(concat(@src,"-"),"solid 1px green-")][@xml:lang="en-US"][not(following-sibling::*)]]]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <psi name="solid 1px green" xml:lang="nb"> + <pi> + <xi src="100%" xml:lang="en"/> + <omicron delete="_blank" xml:lang="en"/> + <xi xml:lang="en-US" xml:id="id1"/> + <upsilon src="this-is-att-value" xml:lang="en-US"/> + <beta xml:id="id2"> + <nu xml:lang="nb" xml:id="id3"> + <delta xml:lang="en-GB"> + <omega xml:lang="en" xml:id="id4"> + <gamma xml:id="id5"/> + <lambda insert="true"/> + <tau xml:lang="en-GB"/> + <delta abort="_blank"> + <mu xml:lang="no-nb"/> + <pi> + <chi xml:lang="en-US"> + <gamma false="true" xml:lang="en-US"/> + <rho content="false" xml:lang="no" xml:id="id6"> + <epsilon xml:id="id7"> + <beta class="100%" xml:lang="no" xml:id="id8"> + <alpha src="solid 1px green" xml:lang="en-US"> + <green>This text must be green</green> + </alpha> + </beta> + </epsilon> + </rho> + </chi> + </pi> + </delta> + </omega> + </delta> + </nu> + </beta> + </pi> + </psi> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]/delta[not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::*[@number][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id4"]/gamma[@xml:lang="no"][not(preceding-sibling::*)]/rho[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa//eta[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::chi[starts-with(concat(@name,"-"),"this.nodeValue-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[contains(concat(@insert,"$"),"false$")][following-sibling::*[position()=1]][following-sibling::alpha[starts-with(@title,"t")][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <delta> + <chi xml:id="id2"/> + <any number="this.nodeValue" xml:id="id3"> + <psi xml:lang="no-nb"/> + <any xml:lang="no"/> + <omicron xml:lang="no" xml:id="id4"> + <gamma xml:lang="no"> + <rho/> + <kappa> + <eta xml:lang="en-US" xml:id="id5"/> + <chi name="this.nodeValue"> + <chi insert="false"/> + <alpha title="this.nodeValue"> + <green>This text must be green</green> + </alpha> + </chi> + </kappa> + </gamma> + </omicron> + </any> + </delta> + </phi> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en"][@xml:id="id1"]//*[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::kappa[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::chi[@desciption][@xml:lang="no-nb"]/*[following-sibling::*[position()=2]][following-sibling::mu[not(child::node())][following-sibling::omicron[@and][@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="en" xml:id="id1"> + <any/> + <kappa xml:id="id2"/> + <upsilon xml:lang="no-nb" xml:id="id3"/> + <chi desciption="100%" xml:lang="no-nb"> + <any/> + <mu/> + <omicron and="false" xml:lang="no-nb" xml:id="id4"> + <green>This text must be green</green> + </omicron> + </chi> + </psi> + </tree> + </test> + <test> + <xpath>//omicron[contains(@title,"lank")][@xml:id="id1"]/theta[starts-with(@data,"10")][@xml:lang="en"][not(child::node())][following-sibling::beta[starts-with(concat(@number,"-"),"another attribute value-")][@xml:id="id2"][following-sibling::*[position()=4]][following-sibling::gamma[starts-with(@token,"solid 1p")][preceding-sibling::*[position() = 2]][following-sibling::alpha[@attribute][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::mu[@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::*[not(following-sibling::*)]//sigma[@xml:lang="no-nb"]/iota[following-sibling::pi[starts-with(concat(@object,"-"),"attribute-")][@xml:lang="en"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <omicron title="_blank" xml:id="id1"> + <theta data="100%" xml:lang="en"/> + <beta number="another attribute value" xml:id="id2"/> + <gamma token="solid 1px green"/> + <alpha attribute="123456789" xml:id="id3"/> + <mu xml:lang="nb" xml:id="id4"/> + <any> + <sigma xml:lang="no-nb"> + <iota/> + <pi object="attribute" xml:lang="en"> + <green>This text must be green</green> + </pi> + </sigma> + </any> + </omicron> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(concat(@content,"-"),"solid 1px green-")][@xml:id="id1"]/kappa[contains(@number,"olid ")][@xml:lang="nb"][not(preceding-sibling::*)]/mu[contains(@true,"ute v")][@xml:id="id2"][following-sibling::phi[@class][preceding-sibling::*[position() = 1]]/sigma[starts-with(@attr,"attribut")][@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]/omicron[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:id="id4"][not(following-sibling::*)]//pi[contains(concat(@object,"$"),"another attribute value$")][not(preceding-sibling::*)][following-sibling::phi[@attr][@xml:id="id5"][following-sibling::omicron[starts-with(@att,"1234")][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon content="solid 1px green" xml:id="id1"> + <kappa number="solid 1px green" xml:lang="nb"> + <mu true="attribute value" xml:id="id2"/> + <phi class="_blank"> + <sigma attr="attribute value" xml:lang="en-GB" xml:id="id3"> + <omicron xml:lang="en-US"/> + <psi xml:id="id4"> + <pi object="another attribute value"/> + <phi attr="false" xml:id="id5"/> + <omicron att="123456789" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </psi> + </sigma> + </phi> + </kappa> + </upsilon> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="no"]//kappa[starts-with(@or,"_b")][@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]//xi[@xml:id="id2"][not(preceding-sibling::*)]//alpha[starts-with(concat(@object,"-"),"123456789-")][@xml:id="id3"][following-sibling::omicron[contains(concat(@attrib,"$"),"nt$")][@xml:lang="no"][not(child::node())][following-sibling::lambda[@insert][@xml:lang="en-US"][@xml:id="id4"][following-sibling::phi[contains(@name,"ut")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//beta[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[contains(@insert,"his.node")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::nu[not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="no"> + <kappa or="_blank" xml:lang="en-US" xml:id="id1"> + <xi xml:id="id2"> + <alpha object="123456789" xml:id="id3"/> + <omicron attrib="content" xml:lang="no"/> + <lambda insert="100%" xml:lang="en-US" xml:id="id4"/> + <phi name="attribute" xml:lang="nb" xml:id="id5"> + <beta xml:lang="en" xml:id="id6"/> + <delta insert="this.nodeValue" xml:id="id7"> + <iota/> + <epsilon xml:lang="en" xml:id="id8"/> + <nu> + <green>This text must be green</green> + </nu> + </delta> + </phi> + </xi> + </kappa> + </mu> + </tree> + </test> + <test> + <xpath>//lambda//iota[@xml:lang="no-nb"][@xml:id="id1"][following-sibling::epsilon[starts-with(concat(@attribute,"-"),"attribute-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@insert][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::*[@attr]/tau[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <iota xml:lang="no-nb" xml:id="id1"/> + <epsilon attribute="attribute-value" xml:lang="nb"/> + <zeta insert="content"/> + <any attr="attribute"> + <tau xml:lang="en-US" xml:id="id2"> + <green>This text must be green</green> + </tau> + </any> + </lambda> + </tree> + </test> + <test> + <xpath>//epsilon[@attrib="attribute value"][@xml:lang="en-US"]//zeta[starts-with(@true,"cont")][@xml:id="id1"][not(following-sibling::*)]//xi[@xml:lang="no"][following-sibling::sigma[preceding-sibling::*[position() = 1]]//xi[starts-with(@desciption,"fa")][not(child::node())][following-sibling::beta[starts-with(@token,"_blank")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::psi[starts-with(@data,"fal")][@xml:id="id3"][following-sibling::zeta[@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::sigma[@string][preceding-sibling::*[position() = 5]][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[starts-with(concat(@true,"-"),"true-")][@xml:id="id5"][preceding-sibling::*[position() = 6]][following-sibling::pi[@xml:lang="en"][@xml:id="id6"]/sigma[contains(concat(@class,"$"),"-att-value$")][@xml:lang="en-GB"]/alpha[not(following-sibling::*)]/mu[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]/lambda[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@att][not(preceding-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 1]]//delta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon attrib="attribute value" xml:lang="en-US"> + <zeta true="content" xml:id="id1"> + <xi xml:lang="no"/> + <sigma> + <xi desciption="false"/> + <beta token="_blank" xml:id="id2"/> + <psi data="false" xml:id="id3"/> + <zeta xml:id="id4"/> + <chi/> + <sigma string="another attribute value"/> + <mu true="true" xml:id="id5"/> + <pi xml:lang="en" xml:id="id6"> + <sigma class="this-is-att-value" xml:lang="en-GB"> + <alpha> + <mu xml:lang="en-GB" xml:id="id7"> + <lambda xml:lang="en"> + <any att="content"> + <mu xml:lang="no-nb" xml:id="id8"/> + <lambda xml:lang="en" xml:id="id9"> + <delta xml:lang="no-nb"/> + <omicron xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </omicron> + </lambda> + </any> + </lambda> + </mu> + </alpha> + </sigma> + </pi> + </sigma> + </zeta> + </epsilon> + </tree> + </test> + <test> + <xpath>//theta[contains(@title,"r")][@xml:id="id1"]//beta[@xml:lang="en-GB"][not(preceding-sibling::*)]/kappa[@xml:lang="en"][@xml:id="id2"][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="nb"][following-sibling::rho[contains(concat(@object,"$"),"nodeValue$")][@xml:lang="en"][not(child::node())][following-sibling::lambda[@data="100%"][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::kappa[contains(concat(@attr,"$"),"-is-att-value$")][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="en-US"][@xml:id="id4"]//phi[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(preceding-sibling::phi)][following-sibling::kappa[contains(@token,"t-va")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::rho[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//psi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[contains(@false,"ue")][@xml:lang="no-nb"][@xml:id="id8"][not(following-sibling::*)]//omicron[@insert][@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <theta title="true" xml:id="id1"> + <beta xml:lang="en-GB"> + <kappa xml:lang="en" xml:id="id2"/> + <iota/> + <lambda xml:lang="nb"/> + <rho object="this.nodeValue" xml:lang="en"/> + <lambda data="100%" xml:lang="no-nb" xml:id="id3"/> + <kappa attr="this-is-att-value" xml:lang="no"/> + <phi xml:lang="en-US" xml:id="id4"> + <phi xml:lang="en" xml:id="id5"/> + <kappa token="this-is-att-value" xml:lang="no"/> + <nu xml:lang="en-US" xml:id="id6"/> + <rho xml:lang="no" xml:id="id7"> + <psi xml:lang="no-nb"> + <mu false="another attribute value" xml:lang="no-nb" xml:id="id8"> + <omicron insert="this-is-att-value" xml:lang="en-GB" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </mu> + </psi> + </rho> + </phi> + </beta> + </theta> + </tree> + </test> + <test> + <xpath>//xi[@insert="100%"]/phi[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[not(preceding-sibling::*)][following-sibling::delta[contains(@title,"ribute")][@xml:lang="en-US"]/eta[starts-with(concat(@desciption,"-"),"true-")][following-sibling::beta[preceding-sibling::*[position() = 1]]/zeta[@class="attribute value"][@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)]//psi[@title="solid 1px green"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[starts-with(@att,"_blank")][@xml:id="id2"]//zeta[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@class][@xml:lang="en-GB"][@xml:id="id3"]//rho[not(preceding-sibling::*)][not(following-sibling::rho)][following-sibling::chi[@xml:lang="en-GB"][@xml:id="id4"][not(following-sibling::*)]//gamma[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::chi[starts-with(@desciption,"con")][@xml:lang="no-nb"][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::eta[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::tau[@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/*[@xml:lang="en"][@xml:id="id9"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>1</nth> + </result> + <tree> + <xi insert="100%"> + <phi xml:lang="no"> + <phi/> + <delta title="attribute" xml:lang="en-US"> + <eta desciption="true"/> + <beta> + <zeta class="attribute value" xml:lang="no" xml:id="id1"> + <psi title="solid 1px green" xml:lang="no-nb"> + <upsilon att="_blank" xml:id="id2"> + <zeta xml:lang="en"> + <beta class="123456789" xml:lang="en-GB" xml:id="id3"> + <rho/> + <chi xml:lang="en-GB" xml:id="id4"> + <gamma xml:lang="no" xml:id="id5"/> + <chi desciption="content" xml:lang="no-nb" xml:id="id6"/> + <eta xml:lang="no-nb" xml:id="id7"/> + <tau xml:id="id8"> + <any xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </any> + </tau> + </chi> + </beta> + </zeta> + </upsilon> + </psi> + </zeta> + </beta> + </delta> + </phi> + </xi> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en"]/upsilon[contains(concat(@attribute,"$"),"ttribute$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(concat(@and,"$"),"00%$")][@xml:lang="nb"][following-sibling::lambda[@xml:lang="no"][@xml:id="id1"][preceding-sibling::*[position() = 2]][following-sibling::phi[contains(@and,"se")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::alpha[following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[contains(@number,"lse")][@xml:lang="no-nb"][@xml:id="id2"]/tau[contains(concat(@name,"$"),"e$")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::epsilon[not(following-sibling::*)]/nu[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::eta[starts-with(concat(@abort,"-"),"false-")][@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]//omicron[contains(@abort,"value")][@xml:lang="en-GB"][@xml:id="id6"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en"> + <upsilon attribute="attribute" xml:lang="no-nb"/> + <omega and="100%" xml:lang="nb"/> + <lambda xml:lang="no" xml:id="id1"/> + <phi and="false" xml:lang="nb"/> + <alpha/> + <alpha number="false" xml:lang="no-nb" xml:id="id2"> + <tau name="true" xml:lang="no" xml:id="id3"/> + <epsilon> + <nu xml:id="id4"> + <phi xml:lang="en-US"/> + <eta abort="false" xml:lang="no" xml:id="id5"> + <omicron abort="attribute-value" xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </eta> + </nu> + </epsilon> + </alpha> + </omega> + </tree> + </test> + <test> + <xpath>//chi[@string][@xml:lang="no-nb"][@xml:id="id1"]//kappa[contains(concat(@att,"$"),"odeValue$")][following-sibling::*[position()=2]][following-sibling::tau[contains(concat(@and,"$"),"ribute$")][@xml:lang="en"][not(child::node())][following-sibling::psi[starts-with(concat(@attrib,"-"),"solid 1px green-")][@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 2]]//delta[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:lang="no-nb"][not(following-sibling::*)]/tau[@true][@xml:id="id4"]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <chi string="content" xml:lang="no-nb" xml:id="id1"> + <kappa att="this.nodeValue"/> + <tau and="attribute" xml:lang="en"/> + <psi attrib="solid 1px green" xml:lang="en-US" xml:id="id2"> + <delta xml:lang="en-GB" xml:id="id3"/> + <beta/> + <omega xml:lang="no-nb"> + <tau true="another attribute value" xml:id="id4"> + <green>This text must be green</green> + </tau> + </omega> + </psi> + </chi> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@abort,"$"),"%$")][@xml:lang="en"][@xml:id="id1"]//epsilon[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]/pi[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(@data,"tru")][not(child::node())][following-sibling::phi[contains(@string,"e")][@xml:id="id4"][following-sibling::theta[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::xi[@xml:lang="no-nb"][@xml:id="id6"]/mu[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="no-nb"]//phi[starts-with(concat(@string,"-"),"attribute-")][not(child::node())][following-sibling::nu[@xml:lang="no-nb"][following-sibling::upsilon[@xml:id="id8"]//nu[@or][@xml:lang="no"][not(preceding-sibling::*)]//theta[contains(concat(@false,"$"),"bute value$")][@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::omega[preceding-sibling::*[position() = 1]][following-sibling::tau[not(following-sibling::*)]/omicron[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::iota[@attribute="true"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en-US"][@xml:id="id11"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/nu[contains(concat(@desciption,"$"),"d 1px green$")][@xml:id="id12"][not(preceding-sibling::*)]/alpha[contains(concat(@attribute,"$"),"ontent$")][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <beta abort="100%" xml:lang="en" xml:id="id1"> + <epsilon xml:lang="no" xml:id="id2"> + <pi xml:lang="en-GB" xml:id="id3"/> + <kappa data="true"/> + <phi string="attribute value" xml:id="id4"/> + <theta xml:lang="no-nb" xml:id="id5"/> + <xi xml:lang="no-nb" xml:id="id6"> + <mu xml:lang="en-GB" xml:id="id7"/> + <upsilon xml:lang="nb"/> + <beta xml:lang="no-nb"> + <phi string="attribute-value"/> + <nu xml:lang="no-nb"/> + <upsilon xml:id="id8"> + <nu or="this.nodeValue" xml:lang="no"> + <theta false="attribute value" xml:lang="en-GB" xml:id="id9"/> + <omega/> + <tau> + <omicron xml:lang="en-US"/> + <iota attribute="true" xml:id="id10"/> + <tau xml:lang="en-US" xml:id="id11"> + <nu desciption="solid 1px green" xml:id="id12"> + <alpha attribute="content"> + <green>This text must be green</green> + </alpha> + </nu> + </tau> + </tau> + </nu> + </upsilon> + </beta> + </xi> + </epsilon> + </beta> + </tree> + </test> + <test> + <xpath>//nu[@attr][@xml:id="id1"]/psi[contains(@insert,"tribute-value")][following-sibling::pi[preceding-sibling::*[position() = 1]]/omicron[@class="true"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@attr="this-is-att-value"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/zeta[@and][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::mu[starts-with(concat(@insert,"-"),"content-")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@true="123456789"][@xml:lang="en"][@xml:id="id4"]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <nu attr="123456789" xml:id="id1"> + <psi insert="attribute-value"/> + <pi> + <omicron class="true"/> + <iota attr="this-is-att-value" xml:id="id2"> + <zeta and="100%" xml:lang="en" xml:id="id3"/> + <mu insert="content" xml:lang="no"/> + <omicron true="123456789" xml:lang="en" xml:id="id4"> + <green>This text must be green</green> + </omicron> + </iota> + </pi> + </nu> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(@insert,"10")][@xml:lang="no"][@xml:id="id1"]/mu[not(preceding-sibling::*)][not(following-sibling::*)]/pi[@class="_blank"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@xml:lang="no-nb"][@xml:id="id2"]//zeta[starts-with(@desciption,"at")][not(following-sibling::*)]/theta/lambda[@content="_blank"][@xml:lang="nb"][@xml:id="id3"][not(child::node())][following-sibling::chi[@xml:lang="no-nb"][not(following-sibling::*)]/delta[@number][@xml:lang="en-US"][not(following-sibling::*)]//iota[contains(@and,"s-att-va")][@xml:id="id4"][not(preceding-sibling::*)]//upsilon[@xml:lang="no-nb"][@xml:id="id5"][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@xml:lang="nb"]//kappa[contains(concat(@title,"$"),"123456789$")][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(@class,"co")][@xml:lang="no"][following-sibling::alpha[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//zeta[@name][@xml:id="id8"][not(following-sibling::*)]/lambda[@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <upsilon insert="100%" xml:lang="no" xml:id="id1"> + <mu> + <pi class="_blank" xml:lang="no-nb"> + <eta xml:lang="no-nb" xml:id="id2"> + <zeta desciption="attribute"> + <theta> + <lambda content="_blank" xml:lang="nb" xml:id="id3"/> + <chi xml:lang="no-nb"> + <delta number="content" xml:lang="en-US"> + <iota and="this-is-att-value" xml:id="id4"> + <upsilon xml:lang="no-nb" xml:id="id5"/> + <chi> + <beta xml:lang="nb"> + <kappa title="123456789" xml:id="id6"/> + <sigma class="content" xml:lang="no"/> + <alpha xml:lang="no" xml:id="id7"> + <zeta name="attribute" xml:id="id8"> + <lambda xml:lang="nb"/> + <psi xml:lang="nb" xml:id="id9"> + <green>This text must be green</green> + </psi> + </zeta> + </alpha> + </beta> + </chi> + </iota> + </delta> + </chi> + </theta> + </zeta> + </eta> + </pi> + </mu> + </upsilon> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en-US"][@xml:id="id1"]//nu[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[contains(@false,"lue")][@xml:lang="nb"][@xml:id="id3"]/gamma[@src][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::eta[starts-with(@and,"another attribute val")]//psi[not(preceding-sibling::*)]/zeta[starts-with(@false,"attribute val")][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::pi)]//gamma[starts-with(@title,"another attribute valu")][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::rho)]/lambda[@xml:lang="no"][@xml:id="id7"][following-sibling::omicron[not(following-sibling::*)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>1</nth> + </result> + <tree> + <psi xml:lang="en-US" xml:id="id1"> + <nu desciption="this.nodeValue" xml:lang="en" xml:id="id2"> + <gamma false="attribute value" xml:lang="nb" xml:id="id3"> + <gamma src="solid 1px green" xml:lang="en-GB"/> + <eta and="another attribute value"> + <psi> + <zeta false="attribute value"/> + <tau> + <pi xml:lang="en" xml:id="id4"> + <gamma title="another attribute value" xml:id="id5"/> + <rho xml:lang="no" xml:id="id6"> + <lambda xml:lang="no" xml:id="id7"/> + <omicron> + <green>This text must be green</green> + </omicron> + </rho> + </pi> + </tau> + </psi> + </eta> + </gamma> + </nu> + </psi> + </tree> + </test> + <test> + <xpath>//nu[starts-with(concat(@src,"-"),"attribute-")][@xml:id="id1"]//chi[contains(@attribute,"_")][@xml:lang="no"][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][@xml:id="id2"]//beta[@xml:id="id3"][not(child::node())][following-sibling::upsilon[@token][@xml:lang="no"][not(following-sibling::*)]//theta[@xml:lang="no"]/lambda[contains(concat(@false,"$"),"bute$")][@xml:lang="no"][not(following-sibling::*)]/delta[not(following-sibling::*)]/gamma[@attribute][@xml:lang="no-nb"][not(preceding-sibling::*)]/sigma[@att="this.nodeValue"][@xml:lang="nb"][@xml:id="id4"][following-sibling::nu[@xml:id="id5"][preceding-sibling::*[position() = 1]]/omega[@xml:lang="en-US"][following-sibling::*[position()=2]][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/eta[starts-with(concat(@object,"-"),"123456789-")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]]/zeta[contains(concat(@attrib,"$"),"e$")][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[@xml:id="id8"][not(child::node())][following-sibling::epsilon/tau[not(preceding-sibling::*)]//kappa[@xml:lang="nb"][following-sibling::rho[@class][@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[starts-with(concat(@string,"-"),"this-")][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@xml:lang="no-nb"][not(following-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <nu src="attribute-value" xml:id="id1"> + <chi attribute="_blank" xml:lang="no"/> + <kappa xml:lang="no-nb" xml:id="id2"> + <beta xml:id="id3"/> + <upsilon token="attribute" xml:lang="no"> + <theta xml:lang="no"> + <lambda false="attribute" xml:lang="no"> + <delta> + <gamma attribute="attribute-value" xml:lang="no-nb"> + <sigma att="this.nodeValue" xml:lang="nb" xml:id="id4"/> + <nu xml:id="id5"> + <omega xml:lang="en-US"/> + <pi xml:lang="en" xml:id="id6"/> + <lambda xml:lang="no-nb"> + <eta object="123456789" xml:lang="en-GB"/> + <iota> + <zeta attrib="attribute" xml:id="id7"> + <zeta xml:id="id8"/> + <epsilon> + <tau> + <kappa xml:lang="nb"/> + <rho class="true" xml:lang="en-GB" xml:id="id9"> + <iota string="this-is-att-value"> + <xi xml:lang="no-nb"> + <green>This text must be green</green> + </xi> + </iota> + </rho> + </tau> + </epsilon> + </zeta> + </iota> + </lambda> + </nu> + </gamma> + </delta> + </lambda> + </theta> + </upsilon> + </kappa> + </nu> + </tree> + </test> + <test> + <xpath>//tau[starts-with(concat(@delete,"-"),"_blank-")]/zeta[starts-with(@attr,"fal")][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//eta[starts-with(@src,"another attribute")][following-sibling::pi[@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 1]]//gamma[@insert][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@content][not(following-sibling::*)]/chi[@object="this-is-att-value"][@xml:lang="no-nb"][not(following-sibling::*)]/gamma[@or][@xml:lang="en-US"][not(following-sibling::*)]//beta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omicron[not(preceding-sibling::*)]/iota[starts-with(concat(@class,"-"),"attribute-")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::chi[starts-with(concat(@src,"-"),"attribute-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <tau delete="_blank"> + <zeta attr="false" xml:lang="no"/> + <iota xml:lang="en-GB"> + <eta src="another attribute value"/> + <pi xml:lang="en-US" xml:id="id1"> + <gamma insert="solid 1px green"/> + <chi content="attribute"> + <chi object="this-is-att-value" xml:lang="no-nb"> + <gamma or="attribute" xml:lang="en-US"> + <beta xml:id="id2"/> + <lambda xml:lang="en-US"> + <omicron> + <iota class="attribute" xml:lang="no-nb"/> + <chi src="attribute" xml:lang="no-nb"> + <green>This text must be green</green> + </chi> + </omicron> + </lambda> + </gamma> + </chi> + </chi> + </pi> + </iota> + </tau> + </tree> + </test> + <test> + <xpath>//psi[contains(@att,"bute val")][@xml:lang="no-nb"]/psi[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[starts-with(concat(@or,"-"),"content-")][preceding-sibling::*[position() = 1]]/xi[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::rho[@false="_blank"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::phi[@xml:lang="en-GB"][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 4]][following-sibling::eta[@attrib][@xml:lang="en-US"][@xml:id="id4"][following-sibling::nu[@xml:lang="en-GB"][preceding-sibling::*[position() = 6]]/upsilon[@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::kappa[@title][preceding-sibling::*[position() = 1]]]]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <psi att="attribute value" xml:lang="no-nb"> + <psi xml:id="id1"> + <nu/> + <pi or="content"> + <xi xml:id="id2"/> + <pi xml:lang="en-GB" xml:id="id3"/> + <rho false="_blank"/> + <phi xml:lang="en-GB"/> + <alpha/> + <eta attrib="true" xml:lang="en-US" xml:id="id4"/> + <nu xml:lang="en-GB"> + <upsilon xml:lang="en" xml:id="id5"/> + <kappa title="attribute value"> + <green>This text must be green</green> + </kappa> + </nu> + </pi> + </psi> + </psi> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@abort,"$"),"te value$")][@xml:lang="en"][@xml:id="id1"]/lambda[following-sibling::*[position()=1]][following-sibling::delta[not(following-sibling::*)]/iota[contains(@attr,"tent")][@xml:lang="en"][not(preceding-sibling::*)]//lambda[@desciption="_blank"][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::xi[@attribute][@xml:id="id3"][preceding-sibling::*[position() = 1]]//nu[@xml:id="id4"][not(child::node())][following-sibling::*[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <phi abort="attribute value" xml:lang="en" xml:id="id1"> + <lambda/> + <delta> + <iota attr="content" xml:lang="en"> + <lambda desciption="_blank" xml:lang="no" xml:id="id2"/> + <xi attribute="attribute" xml:id="id3"> + <nu xml:id="id4"/> + <any xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </any> + </xi> + </iota> + </delta> + </phi> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]/gamma[@content][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]//iota[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[starts-with(concat(@attribute,"-"),"solid 1px green-")][@xml:id="id3"][not(following-sibling::*)]/gamma[not(preceding-sibling::*)][following-sibling::psi[@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::chi[@title][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::sigma[starts-with(@attribute,"at")][@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/phi[@xml:lang="no"][following-sibling::*[position()=2]][not(child::node())][following-sibling::gamma[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@number][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[@name][@xml:lang="en-GB"][@xml:id="id6"]/nu[contains(@class,"tru")][@xml:lang="en-US"][following-sibling::zeta[contains(@abort,"tent")][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:lang="en"][@xml:id="id8"][not(following-sibling::*)]/tau[@att][@xml:lang="en-GB"][not(following-sibling::*)]//alpha[starts-with(concat(@data,"-"),"another attribute value-")][@xml:lang="en-GB"][@xml:id="id9"]/kappa[@string][not(preceding-sibling::*)]]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>1</nth> + </result> + <tree> + <iota xml:id="id1"> + <gamma content="attribute" xml:lang="en-GB" xml:id="id2"> + <iota xml:lang="nb"> + <upsilon attribute="solid 1px green" xml:id="id3"> + <gamma/> + <psi xml:id="id4"/> + <chi title="123456789" xml:lang="no-nb"/> + <sigma attribute="attribute value" xml:lang="no"> + <phi xml:lang="no"/> + <gamma xml:id="id5"/> + <lambda number="content" xml:lang="nb"> + <tau name="content" xml:lang="en-GB" xml:id="id6"> + <nu class="true" xml:lang="en-US"/> + <zeta abort="content" xml:id="id7"/> + <iota xml:lang="en" xml:id="id8"> + <tau att="this-is-att-value" xml:lang="en-GB"> + <alpha data="another attribute value" xml:lang="en-GB" xml:id="id9"> + <kappa string="attribute-value"> + <green>This text must be green</green> + </kappa> + </alpha> + </tau> + </iota> + </tau> + </lambda> + </sigma> + </upsilon> + </iota> + </gamma> + </iota> + </tree> + </test> + <test> + <xpath>//mu[contains(concat(@token,"$"),"%$")]//alpha[starts-with(concat(@src,"-"),"this-")][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(concat(@desciption,"$"),"00%$")][@xml:id="id1"][not(following-sibling::*)]/zeta[@xml:lang="nb"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[not(following-sibling::*)]/pi[starts-with(@abort,"another attribute v")][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::beta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@number]//iota[@xml:lang="no-nb"][@xml:id="id4"][following-sibling::pi[not(child::node())][following-sibling::sigma[@xml:id="id5"][preceding-sibling::*[position() = 2]]/mu[contains(concat(@class,"$"),"t-value$")][@xml:lang="en-GB"][not(following-sibling::*)]//alpha[starts-with(@title,"this-i")][@xml:id="id6"][not(child::node())][following-sibling::iota[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@xml:lang="no-nb"][not(child::node())][following-sibling::eta[@xml:id="id7"][preceding-sibling::*[position() = 1]]//omicron[@and="this.nodeValue"][@xml:id="id8"][not(preceding-sibling::*)]/lambda[@abort][@xml:lang="en"]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <mu token="100%"> + <alpha src="this-is-att-value"/> + <eta desciption="100%" xml:id="id1"> + <zeta xml:lang="nb" xml:id="id2"/> + <delta> + <pi abort="another attribute value" xml:lang="en-GB" xml:id="id3"/> + <beta/> + <iota number="solid 1px green"> + <iota xml:lang="no-nb" xml:id="id4"/> + <pi/> + <sigma xml:id="id5"> + <mu class="this-is-att-value" xml:lang="en-GB"> + <alpha title="this-is-att-value" xml:id="id6"/> + <iota xml:lang="en-US"> + <alpha xml:lang="no-nb"/> + <eta xml:id="id7"> + <omicron and="this.nodeValue" xml:id="id8"> + <lambda abort="attribute" xml:lang="en"> + <green>This text must be green</green> + </lambda> + </omicron> + </eta> + </iota> + </mu> + </sigma> + </iota> + </delta> + </eta> + </mu> + </tree> + </test> + <test> + <xpath>//omega[starts-with(concat(@token,"-"),"true-")]/gamma[@attribute]//pi[starts-with(concat(@desciption,"-"),"_blank-")][@xml:id="id1"][not(child::node())][following-sibling::*[contains(@token,"attrib")][@xml:id="id2"][preceding-sibling::*[position() = 1]]//chi[not(preceding-sibling::*)][following-sibling::nu[@attribute][@xml:lang="en-US"]/epsilon[@false="attribute"][@xml:lang="nb"][not(child::node())][following-sibling::delta[@xml:id="id3"][not(following-sibling::*)]//upsilon[not(child::node())][following-sibling::rho[@xml:lang="en-GB"][following-sibling::xi[contains(concat(@string,"$"),"alue$")][following-sibling::mu[@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//kappa[contains(concat(@and,"$"),"nodeValue$")][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omega token="true"> + <gamma attribute="false"> + <pi desciption="_blank" xml:id="id1"/> + <any token="attribute" xml:id="id2"> + <chi/> + <nu attribute="this-is-att-value" xml:lang="en-US"> + <epsilon false="attribute" xml:lang="nb"/> + <delta xml:id="id3"> + <upsilon/> + <rho xml:lang="en-GB"/> + <xi string="attribute-value"/> + <mu xml:lang="no-nb"> + <kappa and="this.nodeValue"> + <green>This text must be green</green> + </kappa> + </mu> + </delta> + </nu> + </any> + </gamma> + </omega> + </tree> + </test> + <test> + <xpath>//nu[starts-with(@attr,"_")][@xml:lang="nb"]//alpha[not(following-sibling::*)]/phi[not(following-sibling::*)]/theta[contains(concat(@abort,"$"),"k$")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@number,"$"),"-att-value$")][@xml:id="id1"][not(child::node())][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/*[contains(@abort," 1px green")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::rho[@xml:lang="no"][preceding-sibling::*[position() = 1]]//xi[@xml:lang="en"][not(preceding-sibling::*)]//xi[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[contains(concat(@attrib,"$"),"-value$")][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@object,"$"),"alse$")][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/iota[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@att][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 2]]/lambda[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:id="id8"][preceding-sibling::*[position() = 1]]//chi[@number][@xml:lang="en-GB"][following-sibling::mu[@abort][@xml:id="id9"][not(following-sibling::*)]]]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <nu attr="_blank" xml:lang="nb"> + <alpha> + <phi> + <theta abort="_blank" xml:lang="nb"> + <zeta xml:lang="no-nb"/> + <alpha number="this-is-att-value" xml:id="id1"/> + <upsilon xml:lang="en-US" xml:id="id2"> + <any abort="solid 1px green" xml:lang="nb" xml:id="id3"/> + <rho xml:lang="no"> + <xi xml:lang="en"> + <xi xml:lang="no-nb" xml:id="id4"> + <eta attrib="this-is-att-value" xml:lang="no" xml:id="id5"/> + <alpha object="false" xml:lang="no-nb" xml:id="id6"> + <iota xml:lang="en-US" xml:id="id7"/> + <eta att="content"/> + <eta> + <lambda xml:lang="en-US"/> + <pi xml:id="id8"> + <chi number="_blank" xml:lang="en-GB"/> + <mu abort="false" xml:id="id9"> + <green>This text must be green</green> + </mu> + </pi> + </eta> + </alpha> + </xi> + </xi> + </rho> + </upsilon> + </theta> + </phi> + </alpha> + </nu> + </tree> + </test> + <test> + <xpath>//sigma//gamma[not(following-sibling::*)]/kappa[@attr="_blank"][@xml:lang="en-GB"][not(following-sibling::*)]/nu[@xml:lang="en"][@xml:id="id1"][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[not(child::node())][following-sibling::psi[@or][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(preceding-sibling::psi)]//gamma[@true][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::pi[@data][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[@token][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//psi[contains(@false,"se")][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::zeta[@class="attribute"][@xml:lang="no-nb"][@xml:id="id7"][following-sibling::lambda[@title="another attribute value"]/chi[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(concat(@attribute,"-"),"attribute value-")][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::epsilon[@xml:id="id9"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::zeta[@xml:id="id10"][preceding-sibling::*[position() = 3]]/beta[@xml:lang="en-US"][@xml:id="id11"][not(following-sibling::*)]//rho[@xml:id="id12"][not(following-sibling::*)]/iota[@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <gamma> + <kappa attr="_blank" xml:lang="en-GB"> + <nu xml:lang="en" xml:id="id1"/> + <kappa> + <omega/> + <psi or="true" xml:id="id2"> + <gamma true="this-is-att-value" xml:id="id3"/> + <iota xml:id="id4"/> + <pi data="100%" xml:id="id5"/> + <omicron token="another attribute value"> + <psi false="false" xml:lang="no" xml:id="id6"/> + <zeta class="attribute" xml:lang="no-nb" xml:id="id7"/> + <lambda title="another attribute value"> + <chi xml:lang="en"/> + <sigma attribute="attribute value" xml:id="id8"/> + <epsilon xml:id="id9"/> + <zeta xml:id="id10"> + <beta xml:lang="en-US" xml:id="id11"> + <rho xml:id="id12"> + <iota xml:id="id13"> + <green>This text must be green</green> + </iota> + </rho> + </beta> + </zeta> + </lambda> + </omicron> + </psi> + </kappa> + </kappa> + </gamma> + </sigma> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]//theta[starts-with(concat(@true,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::pi[contains(concat(@attr,"$"),"value$")][@xml:lang="en-US"][not(child::node())][following-sibling::phi[following-sibling::*[position()=1]][following-sibling::beta[contains(concat(@true,"$"),"e$")][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//zeta[following-sibling::eta[starts-with(concat(@number,"-"),"attribute-")][preceding-sibling::*[position() = 1]][not(preceding-sibling::eta or following-sibling::eta)]//omicron[not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:id="id4"]/kappa[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[not(preceding-sibling::*)][not(following-sibling::*)]//pi[following-sibling::epsilon[contains(concat(@att,"$"),"e$")][not(following-sibling::*)]/lambda[contains(@true,"00%")][@xml:lang="en-US"][not(following-sibling::*)]/omega[@xml:lang="no"][not(preceding-sibling::*)]]]]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <theta true="123456789" xml:lang="en-US" xml:id="id2"/> + <pi attr="attribute-value" xml:lang="en-US"/> + <phi/> + <beta true="attribute value" xml:lang="en-US" xml:id="id3"> + <zeta/> + <eta number="attribute-value"> + <omicron/> + <nu xml:id="id4"> + <kappa xml:lang="no"> + <epsilon> + <pi/> + <epsilon att="attribute value"> + <lambda true="100%" xml:lang="en-US"> + <omega xml:lang="no"> + <green>This text must be green</green> + </omega> + </lambda> + </epsilon> + </epsilon> + </kappa> + </nu> + </eta> + </beta> + </rho> + </tree> + </test> + <test> + <xpath>//psi[starts-with(concat(@attribute,"-"),"true-")][@xml:lang="en-US"][@xml:id="id1"]//chi[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@or][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::iota[starts-with(concat(@insert,"-"),"123456789-")][@xml:lang="en-GB"][@xml:id="id3"]/epsilon[starts-with(@false,"this-")][not(preceding-sibling::*)]/rho[not(following-sibling::*)]/gamma[@xml:lang="no-nb"]/alpha[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[starts-with(concat(@data,"-"),"attribute-")][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::tau[contains(@desciption," value")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[starts-with(concat(@and,"-"),"attribute-")][@xml:lang="no"][not(child::node())][following-sibling::chi[starts-with(@string,"another at")][@xml:id="id5"][following-sibling::xi[preceding-sibling::*[position() = 2]]/alpha[contains(@class,"s-att-value")][not(following-sibling::*)]//eta[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@content][preceding-sibling::*[position() = 1]]//psi[not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(concat(@true,"-"),"another attribute value-")][@xml:lang="en-US"][@xml:id="id7"][not(following-sibling::*)]/theta[@xml:lang="nb"][position() = 1]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <psi attribute="true" xml:lang="en-US" xml:id="id1"> + <chi xml:id="id2"/> + <zeta or="100%" xml:lang="en-US"/> + <iota insert="123456789" xml:lang="en-GB" xml:id="id3"> + <epsilon false="this-is-att-value"> + <rho> + <gamma xml:lang="no-nb"> + <alpha xml:id="id4"> + <psi data="attribute" xml:lang="en"/> + <tau desciption="attribute value"> + <tau and="attribute" xml:lang="no"/> + <chi string="another attribute value" xml:id="id5"/> + <xi> + <alpha class="this-is-att-value"> + <eta xml:id="id6"/> + <sigma content="this.nodeValue"> + <psi/> + <pi true="another attribute value" xml:lang="en-US" xml:id="id7"> + <theta xml:lang="nb"> + <green>This text must be green</green> + </theta> + </pi> + </sigma> + </alpha> + </xi> + </tau> + </alpha> + </gamma> + </rho> + </epsilon> + </iota> + </psi> + </tree> + </test> + <test> + <xpath>//xi/eta[contains(@content,"bla")][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(concat(@number,"$"),"bute value$")][preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]/epsilon[contains(@delete,"alue")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[contains(concat(@att,"$"),"00%$")][@xml:id="id2"][not(child::node())][following-sibling::iota[following-sibling::*[position()=5]][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][not(child::node())][following-sibling::epsilon[@false="this-is-att-value"][@xml:lang="en"][not(child::node())][following-sibling::omega[following-sibling::chi[starts-with(concat(@desciption,"-"),"content-")][@xml:lang="en"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]/rho[not(preceding-sibling::*)][following-sibling::lambda[preceding-sibling::*[position() = 1]][following-sibling::theta[@attribute="_blank"]//epsilon[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)]//*[starts-with(@object,"conte")][@xml:lang="no"][@xml:id="id5"][following-sibling::*[@attribute][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@content][@xml:lang="en"][following-sibling::upsilon//gamma[starts-with(concat(@class,"-"),"attribute value-")][not(following-sibling::*)]//rho[@src][@xml:id="id6"][not(following-sibling::*)]//beta[@xml:id="id7"][not(preceding-sibling::*)][position() = 1]]]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <xi> + <eta content="_blank" xml:lang="no-nb" xml:id="id1"/> + <omega number="attribute value"/> + <omicron xml:lang="en-GB"> + <epsilon delete="attribute-value" xml:lang="en-GB"> + <lambda att="100%" xml:id="id2"/> + <iota/> + <kappa xml:lang="no-nb"/> + <epsilon false="this-is-att-value" xml:lang="en"/> + <omega/> + <chi desciption="content" xml:lang="en"/> + <tau xml:lang="en-US" xml:id="id3"> + <rho/> + <lambda/> + <theta attribute="_blank"> + <epsilon xml:lang="nb" xml:id="id4"> + <any object="content" xml:lang="no" xml:id="id5"/> + <any attribute="123456789"> + <chi content="true" xml:lang="en"/> + <upsilon> + <gamma class="attribute value"> + <rho src="100%" xml:id="id6"> + <beta xml:id="id7"> + <green>This text must be green</green> + </beta> + </rho> + </gamma> + </upsilon> + </any> + </epsilon> + </theta> + </tau> + </epsilon> + </omicron> + </xi> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="nb"]//upsilon[contains(concat(@number,"$"),"e value$")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[starts-with(concat(@abort,"-"),"attribute value-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[starts-with(@insert,"_")][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id2"][not(child::node())][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::delta[starts-with(concat(@attribute,"-"),"solid 1px green-")][@xml:lang="en"][preceding-sibling::*[position() = 2]]/omega[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::psi[@name][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[@title="attribute value"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//kappa[starts-with(concat(@title,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:id="id5"][not(following-sibling::*)]//alpha[following-sibling::rho[preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:lang="nb"]/nu[@number][not(child::node())][following-sibling::pi[starts-with(@object,"false")][@xml:id="id6"]//psi[@false][@xml:id="id7"][not(preceding-sibling::*)]/epsilon[contains(concat(@false,"$"),"nk$")][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[following-sibling::*[position()=2]][not(child::node())][following-sibling::lambda[contains(@object,"bute value")][@xml:id="id8"][not(child::node())][following-sibling::pi[contains(concat(@desciption,"$"),"s.nodeValue$")][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="nb"> + <upsilon number="attribute value"/> + <nu abort="attribute value" xml:lang="nb"> + <omicron insert="_blank" xml:lang="no-nb" xml:id="id1"> + <beta xml:id="id2"/> + <alpha xml:id="id3"/> + <delta attribute="solid 1px green" xml:lang="en"> + <omega xml:lang="en"/> + <beta xml:lang="nb"/> + <psi name="attribute value"/> + <omicron title="attribute value" xml:id="id4"> + <kappa title="attribute"> + <zeta xml:id="id5"> + <alpha/> + <rho/> + <theta xml:lang="nb"> + <nu number="content"/> + <pi object="false" xml:id="id6"> + <psi false="another attribute value" xml:id="id7"> + <epsilon false="_blank"/> + <rho/> + <lambda object="attribute value" xml:id="id8"/> + <pi desciption="this.nodeValue"> + <green>This text must be green</green> + </pi> + </psi> + </pi> + </theta> + </zeta> + </kappa> + </omicron> + </delta> + </omicron> + </nu> + </omicron> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-US"]/psi[contains(@data,"e")][not(preceding-sibling::*)]//tau[@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::zeta[not(child::node())][following-sibling::iota[@xml:lang="en-GB"][not(child::node())][following-sibling::mu[@attr="attribute-value"][@xml:lang="no"][not(following-sibling::*)]/delta[@xml:id="id2"]//kappa[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::*[starts-with(concat(@abort,"-"),"this-")][@xml:id="id4"][following-sibling::rho[@xml:id="id5"][following-sibling::alpha[@object="this-is-att-value"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 4]]/delta[contains(concat(@content,"$"),"blank$")][not(following-sibling::*)]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-US"> + <psi data="true"> + <tau xml:lang="no-nb" xml:id="id1"/> + <zeta/> + <iota xml:lang="en-GB"/> + <mu attr="attribute-value" xml:lang="no"> + <delta xml:id="id2"> + <kappa xml:id="id3"/> + <any abort="this-is-att-value" xml:id="id4"/> + <rho xml:id="id5"/> + <alpha object="this-is-att-value"/> + <rho xml:lang="no-nb" xml:id="id6"> + <delta content="_blank"> + <green>This text must be green</green> + </delta> + </rho> + </delta> + </mu> + </psi> + </any> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]/theta[@true][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::delta[following-sibling::omicron[contains(concat(@desciption,"$"),"ribute$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]//beta[@attrib][@xml:lang="en"][@xml:id="id4"][not(child::node())][following-sibling::upsilon[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <theta true="attribute-value" xml:lang="no" xml:id="id2"/> + <delta/> + <omicron desciption="attribute" xml:lang="en-GB"/> + <kappa xml:lang="en-US" xml:id="id3"> + <beta attrib="another attribute value" xml:lang="en" xml:id="id4"/> + <upsilon token="attribute-value" xml:lang="nb"> + <green>This text must be green</green> + </upsilon> + </kappa> + </alpha> + </tree> + </test> + <test> + <xpath>//chi[starts-with(concat(@object,"-"),"this.nodeValue-")][@xml:lang="no"]/iota[@attr][following-sibling::eta[preceding-sibling::*[position() = 1]]/psi[following-sibling::*[position()=1]][following-sibling::lambda[@abort][@xml:lang="no"][@xml:id="id1"]/*[@xml:lang="no"][@xml:id="id2"]//phi[starts-with(concat(@abort,"-"),"true-")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:id="id4"][not(child::node())][following-sibling::iota[@xml:id="id5"]//phi[contains(@src,"10")][@xml:id="id6"][not(preceding-sibling::*)][not(preceding-sibling::phi or following-sibling::phi)][following-sibling::tau[not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]//delta[@data][@xml:lang="nb"][not(child::node())][following-sibling::omega[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(@false,"r")]/xi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[position() = 1]][position() = 1]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <chi object="this.nodeValue" xml:lang="no"> + <iota attr="solid 1px green"/> + <eta> + <psi/> + <lambda abort="false" xml:lang="no" xml:id="id1"> + <any xml:lang="no" xml:id="id2"> + <phi abort="true" xml:lang="no-nb" xml:id="id3"> + <xi xml:id="id4"/> + <iota xml:id="id5"> + <phi src="100%" xml:id="id6"/> + <tau/> + <omicron xml:lang="en-GB"> + <delta data="false" xml:lang="nb"/> + <omega xml:id="id7"> + <phi xml:lang="en-GB"/> + <kappa false="true"> + <xi xml:lang="en"/> + <theta> + <green>This text must be green</green> + </theta> + </kappa> + </omega> + </omicron> + </iota> + </phi> + </any> + </lambda> + </eta> + </chi> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="en-GB"]//omicron[@xml:id="id1"][not(preceding-sibling::*)]//*[@true="this-is-att-value"][@xml:id="id2"][following-sibling::chi[@xml:id="id3"][not(following-sibling::*)]//alpha//epsilon[@object][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@src][not(preceding-sibling::*)]/kappa[starts-with(concat(@false,"-"),"another attribute value-")]/xi[starts-with(concat(@number,"-"),"123456789-")][@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::mu[contains(@delete,"r")][not(following-sibling::*)]//xi[starts-with(@name,"_blan")][following-sibling::*[@xml:id="id6"][not(following-sibling::*)]/*[@object][@xml:lang="no-nb"][not(following-sibling::*)]/eta[@xml:lang="no-nb"][not(following-sibling::*)]/epsilon[@or="attribute value"][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::psi[@delete][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::kappa[@xml:id="id8"]//omega[@data][@xml:lang="en-US"][not(preceding-sibling::*)]/mu[starts-with(concat(@attribute,"-"),"true-")][@xml:id="id9"][not(following-sibling::*)]//eta[contains(concat(@number,"$"),"ue$")][@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[starts-with(concat(@attrib,"-"),"attribute-")][@xml:lang="en"][not(preceding-sibling::*)]/eta[@true][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::alpha[@data="100%"][@xml:id="id11"]//omicron[@src="this-is-att-value"][@xml:id="id12"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="en-GB"> + <omicron xml:id="id1"> + <any true="this-is-att-value" xml:id="id2"/> + <chi xml:id="id3"> + <alpha> + <epsilon object="this.nodeValue" xml:lang="en" xml:id="id4"> + <any src="this.nodeValue"> + <kappa false="another attribute value"> + <xi number="123456789" xml:lang="nb" xml:id="id5"/> + <mu delete="true"> + <xi name="_blank"/> + <any xml:id="id6"> + <any object="this.nodeValue" xml:lang="no-nb"> + <eta xml:lang="no-nb"> + <epsilon or="attribute value" xml:lang="en-GB"/> + <psi delete="solid 1px green" xml:id="id7"/> + <kappa xml:id="id8"> + <omega data="attribute" xml:lang="en-US"> + <mu attribute="true" xml:id="id9"> + <eta number="true" xml:lang="en-US" xml:id="id10"> + <alpha attrib="attribute" xml:lang="en"> + <eta true="content" xml:lang="no"/> + <alpha data="100%" xml:id="id11"> + <omicron src="this-is-att-value" xml:id="id12"> + <green>This text must be green</green> + </omicron> + </alpha> + </alpha> + </eta> + </mu> + </omega> + </kappa> + </eta> + </any> + </any> + </mu> + </kappa> + </any> + </epsilon> + </alpha> + </chi> + </omicron> + </xi> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="en-US"]//zeta[@attribute][@xml:id="id1"][not(preceding-sibling::*)]//lambda[@attr="100%"][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]//rho[contains(concat(@src,"$"),"Value$")][@xml:lang="en-US"][not(preceding-sibling::*)]/rho[contains(@name,"e")][not(preceding-sibling::*)]/psi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[@or][@xml:id="id3"][not(following-sibling::*)]//psi//chi[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::tau[@string="false"][preceding-sibling::*[position() = 2]][following-sibling::delta[@xml:id="id4"]/kappa[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::omicron[starts-with(@string,"tr")][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]//kappa[starts-with(@abort,"attr")]//omega[@desciption][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="nb"][preceding-sibling::*[position() = 1]]//delta[starts-with(@attribute,"_b")][@xml:id="id7"][following-sibling::mu[@number][@xml:lang="no"][@xml:id="id8"]/chi[@xml:lang="no-nb"][@xml:id="id9"]/eta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:id="id10"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="en-US"> + <zeta attribute="false" xml:id="id1"> + <lambda attr="100%" xml:lang="en" xml:id="id2"> + <rho src="this.nodeValue" xml:lang="en-US"> + <rho name="true"> + <psi xml:lang="no-nb"/> + <epsilon or="another attribute value" xml:id="id3"> + <psi> + <chi/> + <iota xml:lang="en"/> + <tau string="false"/> + <delta xml:id="id4"> + <kappa xml:lang="en-US" xml:id="id5"/> + <omicron string="true" xml:lang="no" xml:id="id6"> + <kappa abort="attribute"> + <omega desciption="another attribute value" xml:lang="no"/> + <sigma xml:lang="nb"> + <delta attribute="_blank" xml:id="id7"/> + <mu number="false" xml:lang="no" xml:id="id8"> + <chi xml:lang="no-nb" xml:id="id9"> + <eta xml:lang="no"/> + <lambda xml:id="id10"> + <green>This text must be green</green> + </lambda> + </chi> + </mu> + </sigma> + </kappa> + </omicron> + </delta> + </psi> + </epsilon> + </rho> + </rho> + </lambda> + </zeta> + </eta> + </tree> + </test> + <test> + <xpath>//omega[@name][@xml:lang="en-GB"]/lambda[@content][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@xml:lang="no"][@xml:id="id2"]/beta[starts-with(@abort,"1")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:id="id3"][not(child::node())][following-sibling::*[@xml:lang="en-GB"][not(child::node())][following-sibling::rho[starts-with(@true,"th")][@xml:lang="no"][preceding-sibling::*[position() = 2]]//phi[starts-with(concat(@object,"-"),"attribute value-")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::sigma[starts-with(@insert,"tru")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@xml:lang="en"][not(child::node())][following-sibling::delta[@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]//theta[contains(@or,"tribute")][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[starts-with(@and,"_b")][@xml:lang="nb"][following-sibling::psi[contains(@attribute,"att-value")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/phi[@xml:lang="en-US"][position() = 1]][position() = 1]]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <omega name="attribute" xml:lang="en-GB"> + <lambda content="false" xml:id="id1"/> + <eta xml:lang="no" xml:id="id2"> + <beta abort="100%" xml:lang="no-nb"> + <rho xml:id="id3"/> + <any xml:lang="en-GB"/> + <rho true="this-is-att-value" xml:lang="no"> + <phi object="attribute value" xml:lang="nb"/> + <sigma insert="true" xml:lang="no" xml:id="id4"/> + <upsilon xml:lang="en"/> + <delta xml:lang="en" xml:id="id5"> + <theta or="attribute" xml:lang="no" xml:id="id6"/> + <iota/> + <rho and="_blank" xml:lang="nb"/> + <psi attribute="this-is-att-value"> + <phi xml:lang="en-US"> + <green>This text must be green</green> + </phi> + </psi> + </delta> + </rho> + </beta> + </eta> + </omega> + </tree> + </test> + <test> + <xpath>//eta[@xml:id="id1"]/eta[following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[contains(concat(@class,"$"),"er attribute value$")][@xml:lang="en-US"][not(following-sibling::*)]/alpha[@class][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:id="id2"][not(child::node())][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//rho[starts-with(concat(@insert,"-"),"attribute-")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::nu[@number][@xml:lang="no-nb"]/upsilon[@xml:id="id4"][not(following-sibling::*)]/eta[@insert][@xml:id="id5"][not(following-sibling::*)]//alpha[contains(@title,"ttribu")][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@object="true"][@xml:id="id7"][following-sibling::nu[@attr][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//kappa[@token][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::kappa[@true="100%"][@xml:id="id9"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>1</nth> + </result> + <tree> + <eta xml:id="id1"> + <eta/> + <psi class="another attribute value" xml:lang="en-US"> + <alpha class="123456789" xml:lang="no"/> + <chi xml:id="id2"/> + <kappa xml:lang="en-US" xml:id="id3"> + <rho insert="attribute-value" xml:lang="nb"/> + <nu number="123456789" xml:lang="no-nb"> + <upsilon xml:id="id4"> + <eta insert="attribute-value" xml:id="id5"> + <alpha title="attribute value" xml:id="id6"/> + <kappa object="true" xml:id="id7"/> + <nu attr="solid 1px green"> + <kappa token="true" xml:id="id8"/> + <kappa true="100%" xml:id="id9"> + <green>This text must be green</green> + </kappa> + </nu> + </eta> + </upsilon> + </nu> + </kappa> + </psi> + </eta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en"][@xml:id="id1"]//omega[starts-with(concat(@name,"-"),"content-")][not(preceding-sibling::*)]//epsilon[@xml:id="id2"][not(preceding-sibling::*)]/upsilon[@false="content"][@xml:lang="en"][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/sigma[contains(@abort,"t")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::alpha[not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::mu[not(following-sibling::*)]/delta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en" xml:id="id1"> + <omega name="content"> + <epsilon xml:id="id2"> + <upsilon false="content" xml:lang="en"/> + <beta xml:id="id3"/> + <xi xml:id="id4"> + <sigma abort="content" xml:lang="no-nb"> + <pi xml:lang="nb" xml:id="id5"/> + <alpha/> + <kappa/> + <mu> + <delta xml:lang="no"/> + <pi> + <green>This text must be green</green> + </pi> + </mu> + </sigma> + </xi> + </epsilon> + </omega> + </sigma> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="no-nb"][@xml:id="id1"]//omega[starts-with(@number,"soli")][not(preceding-sibling::*)]//mu[@xml:lang="en-GB"][not(child::node())][following-sibling::eta[starts-with(concat(@false,"-"),"_blank-")][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/nu[contains(@false,"%")][not(preceding-sibling::*)]/psi[@and][@xml:lang="en-GB"][following-sibling::eta[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::alpha[following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//nu[@xml:lang="en-GB"][not(preceding-sibling::*)]//pi[contains(concat(@title,"$"),"e$")][following-sibling::theta[starts-with(concat(@attr,"-"),"false-")][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="no-nb" xml:id="id1"> + <omega number="solid 1px green"> + <mu xml:lang="en-GB"/> + <eta false="_blank" xml:id="id2"/> + <phi xml:id="id3"> + <nu false="100%"> + <psi and="this.nodeValue" xml:lang="en-GB"/> + <eta xml:id="id4"/> + <alpha/> + <omicron xml:lang="en-GB" xml:id="id5"> + <nu xml:lang="en-GB"> + <pi title="true"/> + <theta attr="false"> + <green>This text must be green</green> + </theta> + </nu> + </omicron> + </nu> + </phi> + </omega> + </theta> + </tree> + </test> + <test> + <xpath>//alpha[@true][@xml:lang="en-US"]//nu[@xml:lang="nb"]//xi[@xml:lang="no-nb"][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::delta[@object][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//psi[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon//omega[contains(concat(@title,"$"),"id 1px green$")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:id="id4"][not(preceding-sibling::*)]/omicron[@attribute][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:id="id5"]/upsilon[@attribute][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@attribute="attribute-value"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[contains(concat(@delete,"$"),"ibute-value$")][@xml:lang="en-US"][following-sibling::phi[@src="this-is-att-value"][@xml:id="id8"][following-sibling::rho[@xml:lang="en"][@xml:id="id9"][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <alpha true="this.nodeValue" xml:lang="en-US"> + <nu xml:lang="nb"> + <xi xml:lang="no-nb" xml:id="id1"/> + <delta object="solid 1px green" xml:lang="en" xml:id="id2"> + <psi xml:id="id3"/> + <epsilon> + <omega title="solid 1px green" xml:lang="en-US"> + <psi xml:id="id4"> + <omicron attribute="_blank"/> + <xi xml:id="id5"> + <upsilon attribute="content" xml:lang="no" xml:id="id6"/> + <phi attribute="attribute-value" xml:id="id7"/> + <alpha delete="attribute-value" xml:lang="en-US"/> + <phi src="this-is-att-value" xml:id="id8"/> + <rho xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </rho> + </xi> + </psi> + </omega> + </epsilon> + </delta> + </nu> + </alpha> + </tree> + </test> + <test> + <xpath>//pi/tau[@xml:lang="en-US"][not(child::node())][following-sibling::*[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(concat(@number,"$"),"789$")][not(following-sibling::*)]//tau[@xml:lang="nb"]/theta[@xml:lang="en"][not(child::node())][following-sibling::zeta[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@xml:lang="nb"][@xml:id="id1"][following-sibling::lambda[@xml:id="id2"][not(child::node())][following-sibling::nu[contains(concat(@attribute,"$"),"content$")][@xml:lang="en-GB"][not(following-sibling::*)]//omicron[@xml:id="id3"][not(preceding-sibling::*)]/pi[@xml:id="id4"][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(preceding-sibling::nu)][not(child::node())][following-sibling::theta[@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)]//kappa[@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]//kappa[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@token="attribute value"][@xml:id="id7"][not(preceding-sibling::*)]//chi[@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)]/*[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <pi> + <tau xml:lang="en-US"/> + <any xml:lang="no-nb"/> + <sigma number="123456789"> + <tau xml:lang="nb"> + <theta xml:lang="en"/> + <zeta xml:lang="nb"> + <kappa xml:lang="nb" xml:id="id1"/> + <lambda xml:id="id2"/> + <nu attribute="content" xml:lang="en-GB"> + <omicron xml:id="id3"> + <pi xml:id="id4"/> + <nu xml:lang="en-GB"/> + <theta xml:lang="no-nb" xml:id="id5"> + <kappa xml:lang="en" xml:id="id6"> + <kappa xml:lang="en"> + <eta token="attribute value" xml:id="id7"> + <chi xml:lang="nb" xml:id="id8"> + <any xml:id="id9"> + <green>This text must be green</green> + </any> + </chi> + </eta> + </kappa> + </kappa> + </theta> + </omicron> + </nu> + </zeta> + </tau> + </sigma> + </pi> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]/sigma[contains(concat(@abort,"$"),"his.nodeValue$")]//beta[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]/beta[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::beta)][not(child::node())][following-sibling::phi[contains(concat(@delete,"$"),"ute$")][@xml:id="id4"][following-sibling::omega[@class][@xml:lang="en"][following-sibling::iota[starts-with(concat(@data,"-"),"this.nodeValue-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//upsilon[@false="_blank"][@xml:id="id5"][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>1</nth> + </result> + <tree> + <chi xml:id="id1"> + <sigma abort="this.nodeValue"> + <beta xml:lang="en" xml:id="id2"> + <beta xml:lang="no" xml:id="id3"/> + <phi delete="attribute" xml:id="id4"/> + <omega class="this-is-att-value" xml:lang="en"/> + <iota data="this.nodeValue"> + <upsilon false="_blank" xml:id="id5"> + <green>This text must be green</green> + </upsilon> + </iota> + </beta> + </sigma> + </chi> + </tree> + </test> + <test> + <xpath>//xi[@string]//delta[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[starts-with(concat(@delete,"-"),"123456789-")][not(preceding-sibling::*)]/omicron[not(child::node())][following-sibling::zeta[@attrib][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[starts-with(concat(@class,"-"),"true-")][@xml:lang="en"][@xml:id="id2"][not(child::node())][following-sibling::alpha[@desciption][@xml:id="id3"]//lambda[@xml:lang="en-US"][not(following-sibling::*)]/mu[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <xi string="false"> + <delta xml:lang="en" xml:id="id1"> + <psi delete="123456789"> + <omicron/> + <zeta attrib="attribute" xml:lang="en-US"> + <kappa class="true" xml:lang="en" xml:id="id2"/> + <alpha desciption="100%" xml:id="id3"> + <lambda xml:lang="en-US"> + <mu xml:lang="nb" xml:id="id4"/> + <theta> + <green>This text must be green</green> + </theta> + </lambda> + </alpha> + </zeta> + </psi> + </delta> + </xi> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en-US"][@xml:id="id1"]/kappa[@xml:id="id2"][not(preceding-sibling::*)]//sigma[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[contains(@and,"blan")][not(following-sibling::*)]//upsilon[not(child::node())][following-sibling::chi[starts-with(concat(@abort,"-"),"true-")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::epsilon[starts-with(@src,"co")]/pi[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::phi[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 2]]/epsilon[@data="this.nodeValue"][@xml:lang="nb"][not(preceding-sibling::*)]//nu[@xml:lang="no"]//omega[@string="attribute value"][not(following-sibling::*)]/pi[not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[not(preceding-sibling::*)][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en-US" xml:id="id1"> + <kappa xml:id="id2"> + <sigma xml:id="id3"> + <kappa and="_blank"> + <upsilon/> + <chi abort="true" xml:id="id4"/> + <epsilon src="content"> + <pi/> + <phi xml:lang="en" xml:id="id5"/> + <rho> + <epsilon data="this.nodeValue" xml:lang="nb"> + <nu xml:lang="no"> + <omega string="attribute value"> + <pi> + <omicron xml:id="id6"> + <delta/> + <phi> + <green>This text must be green</green> + </phi> + </omicron> + </pi> + </omega> + </nu> + </epsilon> + </rho> + </epsilon> + </kappa> + </sigma> + </kappa> + </sigma> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:id="id1"]//upsilon[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[contains(concat(@src,"$"),"ibute value$")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[not(following-sibling::*)]/gamma[not(preceding-sibling::*)]//phi[not(preceding-sibling::*)][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//sigma[@att="attribute"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[contains(@true,"ttribute v")][@xml:id="id6"][not(following-sibling::*)]/rho//zeta[position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:id="id1"> + <upsilon xml:id="id2"/> + <tau src="attribute value" xml:lang="en" xml:id="id3"> + <chi> + <gamma> + <phi/> + <omega/> + <pi> + <sigma att="attribute" xml:id="id4"/> + <omega xml:id="id5"/> + <lambda true="attribute value" xml:id="id6"> + <rho> + <zeta> + <green>This text must be green</green> + </zeta> + </rho> + </lambda> + </pi> + </gamma> + </chi> + </tau> + </epsilon> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no-nb"][@xml:id="id1"]/xi[@xml:lang="no-nb"][following-sibling::omicron[starts-with(@string,"_")][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]/lambda[@xml:id="id3"][not(preceding-sibling::*)][not(preceding-sibling::lambda)][following-sibling::iota[@true][@xml:lang="en-GB"][following-sibling::kappa[starts-with(concat(@object,"-"),"attribute-")][@xml:lang="nb"][following-sibling::epsilon[starts-with(concat(@title,"-"),"_blank-")][@xml:lang="en-US"][@xml:id="id4"][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no-nb" xml:id="id1"> + <xi xml:lang="no-nb"/> + <omicron string="_blank" xml:lang="en-GB" xml:id="id2"> + <lambda xml:id="id3"/> + <iota true="100%" xml:lang="en-GB"/> + <kappa object="attribute" xml:lang="nb"/> + <epsilon title="_blank" xml:lang="en-US" xml:id="id4"> + <green>This text must be green</green> + </epsilon> + </omicron> + </psi> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@attr,"-"),"123456789-")]//lambda[@xml:lang="nb"][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::delta[contains(@desciption,"ute-value")][not(following-sibling::*)]//xi[contains(concat(@or,"$"),"ank$")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@xml:id="id2"][following-sibling::delta[starts-with(@insert,"this-is-att-valu")][preceding-sibling::*[position() = 1]][following-sibling::*[not(following-sibling::*)]/theta[@number][not(child::node())][following-sibling::xi[@xml:lang="nb"][not(child::node())][following-sibling::psi[@xml:lang="nb"][following-sibling::rho[@token][@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::phi[@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[not(following-sibling::*)]//xi[starts-with(concat(@class,"-"),"_blank-")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[not(following-sibling::*)]/beta[not(preceding-sibling::*)]/chi[@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:id="id7"][not(child::node())][following-sibling::chi[starts-with(@content,"fal")][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::gamma[@class="attribute"][@xml:id="id9"][preceding-sibling::*[position() = 3]]][position() = 1]]]]][position() = 1]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <mu attr="123456789"> + <lambda xml:lang="nb" xml:id="id1"/> + <delta desciption="attribute-value"> + <xi or="_blank" xml:lang="en"> + <omega xml:id="id2"/> + <delta insert="this-is-att-value"/> + <any> + <theta number="content"/> + <xi xml:lang="nb"/> + <psi xml:lang="nb"/> + <rho token="123456789" xml:lang="nb"/> + <phi xml:id="id3"/> + <pi> + <xi class="_blank" xml:id="id4"/> + <pi xml:id="id5"> + <xi> + <beta> + <chi xml:lang="no-nb" xml:id="id6"/> + <gamma xml:id="id7"/> + <chi content="false" xml:lang="en-GB" xml:id="id8"/> + <gamma class="attribute" xml:id="id9"> + <green>This text must be green</green> + </gamma> + </beta> + </xi> + </pi> + </pi> + </any> + </xi> + </delta> + </mu> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en"]//alpha[starts-with(@string,"solid 1px green")][@xml:lang="no"][not(following-sibling::*)]/gamma[@xml:id="id1"][not(child::node())][following-sibling::gamma[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@object][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[contains(concat(@att,"$"),"alse$")][@xml:lang="en-GB"][not(child::node())][following-sibling::rho[@xml:lang="nb"]//tau[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@class][@xml:id="id5"]//mu[@class][not(preceding-sibling::*)][following-sibling::epsilon[contains(concat(@token,"$"),"%$")][@xml:lang="nb"][not(following-sibling::*)]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en"> + <alpha string="solid 1px green" xml:lang="no"> + <gamma xml:id="id1"/> + <gamma xml:lang="no" xml:id="id2"> + <xi object="attribute value" xml:id="id3"/> + <zeta att="false" xml:lang="en-GB"/> + <rho xml:lang="nb"> + <tau xml:lang="no" xml:id="id4"> + <any class="123456789" xml:id="id5"> + <mu class="_blank"/> + <epsilon token="100%" xml:lang="nb"> + <green>This text must be green</green> + </epsilon> + </any> + </tau> + </rho> + </gamma> + </alpha> + </delta> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no"][@xml:id="id1"]//omicron[contains(concat(@true,"$"),"odeValue$")][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::epsilon[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[@class="100%"][not(preceding-sibling::*)][following-sibling::omega[following-sibling::zeta[@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no" xml:id="id1"> + <omicron true="this.nodeValue" xml:id="id2"/> + <epsilon> + <delta class="100%"/> + <omega/> + <zeta xml:lang="nb" xml:id="id3"> + <green>This text must be green</green> + </zeta> + </epsilon> + </beta> + </tree> + </test> + <test> + <xpath>//omicron[@content]//xi[@xml:id="id1"]/omicron[@xml:lang="no-nb"][@xml:id="id2"][following-sibling::nu[@false][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::alpha[preceding-sibling::*[position() = 2]]/gamma[@xml:id="id4"][not(preceding-sibling::*)]//zeta[@number="attribute-value"][@xml:lang="no"][not(child::node())][following-sibling::psi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::omicron[contains(concat(@delete,"$"),"ue$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/upsilon[starts-with(@title,"another attribute value")][@xml:lang="en"][following-sibling::iota[starts-with(@or,"fal")][@xml:id="id5"][preceding-sibling::*[position() = 1]]/beta[@insert][@xml:lang="no-nb"][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::beta[@xml:lang="no"][@xml:id="id7"][not(child::node())][following-sibling::epsilon[@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[starts-with(@true,"this.nodeValu")][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>1</nth> + </result> + <tree> + <omicron content="true"> + <xi xml:id="id1"> + <omicron xml:lang="no-nb" xml:id="id2"/> + <nu false="this.nodeValue" xml:lang="no-nb" xml:id="id3"/> + <alpha> + <gamma xml:id="id4"> + <zeta number="attribute-value" xml:lang="no"/> + <psi xml:lang="no-nb"/> + <omicron delete="this-is-att-value" xml:lang="no-nb"> + <upsilon title="another attribute value" xml:lang="en"/> + <iota or="false" xml:id="id5"> + <beta insert="attribute-value" xml:lang="no-nb" xml:id="id6"/> + <beta xml:lang="no" xml:id="id7"/> + <epsilon xml:id="id8"> + <theta true="this.nodeValue"> + <green>This text must be green</green> + </theta> + </epsilon> + </iota> + </omicron> + </gamma> + </alpha> + </xi> + </omicron> + </tree> + </test> + <test> + <xpath>//chi[@data]/gamma[@data="123456789"][@xml:lang="en-US"][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id2"]//gamma[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)]//chi[@xml:id="id4"][not(child::node())][following-sibling::zeta[contains(concat(@class,"$"),"is-att-value$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[starts-with(concat(@number,"-"),"attribute-")][@xml:lang="en-US"]//pi[@xml:lang="en"]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <chi data="_blank"> + <gamma data="123456789" xml:lang="en-US" xml:id="id1"/> + <upsilon xml:lang="en-US" xml:id="id2"> + <gamma xml:lang="en-GB" xml:id="id3"> + <chi xml:id="id4"/> + <zeta class="this-is-att-value"> + <pi xml:lang="no-nb" xml:id="id5"/> + <chi number="attribute-value" xml:lang="en-US"> + <pi xml:lang="en"> + <green>This text must be green</green> + </pi> + </chi> + </zeta> + </gamma> + </upsilon> + </chi> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]/delta[starts-with(@true,"t")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/theta[starts-with(concat(@and,"-"),"100%-")][not(child::node())][following-sibling::delta[starts-with(@att,"attri")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[contains(concat(@data,"$"),"ue$")][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::phi[starts-with(@insert,"attribute valu")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//omega[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::psi[contains(@desciption,"t-value")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::psi[not(following-sibling::*)]//xi[@insert][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[starts-with(@number,"t")][@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[contains(concat(@src,"$")," 1px green$")][@xml:lang="no"][@xml:id="id9"][not(child::node())][following-sibling::alpha[@token="attribute-value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//iota[@xml:id="id10"][not(preceding-sibling::*)][following-sibling::gamma//alpha[@and][@xml:lang="en-US"]//epsilon[starts-with(concat(@abort,"-"),"attribute-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:id="id11"][preceding-sibling::*[position() = 1]]//rho[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-GB"][@xml:id="id12"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <delta true="true" xml:lang="en-US" xml:id="id2"> + <theta and="100%"/> + <delta att="attribute" xml:id="id3"> + <sigma data="true" xml:id="id4"/> + <phi insert="attribute value" xml:lang="en-US"/> + <nu xml:lang="nb" xml:id="id5"> + <omega xml:lang="en-US"/> + <psi desciption="this-is-att-value" xml:lang="no"/> + <psi> + <xi insert="another attribute value"> + <gamma xml:lang="nb" xml:id="id6"/> + <iota xml:lang="en"> + <chi xml:lang="en-US" xml:id="id7"> + <sigma number="true" xml:lang="nb" xml:id="id8"/> + <chi src="solid 1px green" xml:lang="no" xml:id="id9"/> + <alpha token="attribute-value"> + <iota xml:id="id10"/> + <gamma> + <alpha and="123456789" xml:lang="en-US"> + <epsilon abort="attribute"/> + <theta xml:id="id11"> + <rho xml:lang="en-US"/> + <nu xml:lang="en-GB" xml:id="id12"> + <green>This text must be green</green> + </nu> + </theta> + </alpha> + </gamma> + </alpha> + </chi> + </iota> + </xi> + </psi> + </nu> + </delta> + </delta> + </xi> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@class,"$"),"blank$")][@xml:lang="en-GB"][@xml:id="id1"]/zeta[@string="attribute-value"][@xml:id="id2"][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][not(child::node())][following-sibling::sigma[@attribute="attribute"][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="no-nb"][not(following-sibling::*)]//chi[@data="false"][@xml:id="id5"][not(preceding-sibling::*)]//tau[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:lang="no"][not(following-sibling::upsilon)][following-sibling::chi[@class][@xml:lang="nb"][following-sibling::psi[@xml:id="id7"][following-sibling::*[position()=2]][following-sibling::psi[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::psi[@name="_blank"][@xml:lang="no"][@xml:id="id8"][preceding-sibling::*[position() = 4]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha class="_blank" xml:lang="en-GB" xml:id="id1"> + <zeta string="attribute-value" xml:id="id2"/> + <psi xml:lang="en-GB" xml:id="id3"/> + <epsilon xml:lang="en-GB"/> + <sigma attribute="attribute" xml:lang="no" xml:id="id4"/> + <beta xml:lang="no-nb"> + <chi data="false" xml:id="id5"> + <tau xml:lang="no" xml:id="id6"> + <upsilon xml:lang="no"/> + <chi class="this.nodeValue" xml:lang="nb"/> + <psi xml:id="id7"/> + <psi xml:lang="no"/> + <psi name="_blank" xml:lang="no" xml:id="id8"> + <green>This text must be green</green> + </psi> + </tau> + </chi> + </beta> + </alpha> + </tree> + </test> + <test> + <xpath>//omicron//theta[not(preceding-sibling::*)]/omega[@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]/tau[@xml:lang="en-US"][not(following-sibling::*)]//nu[@xml:lang="nb"]/theta[@desciption="123456789"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::upsilon[@number="content"][@xml:lang="en"][following-sibling::tau[starts-with(@attr,"this-is-att")][@xml:id="id3"][preceding-sibling::*[position() = 2]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>1</nth> + </result> + <tree> + <omicron> + <theta> + <omega xml:lang="en-US" xml:id="id1"> + <tau xml:lang="en-US"> + <nu xml:lang="nb"> + <theta desciption="123456789" xml:id="id2"/> + <upsilon number="content" xml:lang="en"/> + <tau attr="this-is-att-value" xml:id="id3"> + <green>This text must be green</green> + </tau> + </nu> + </tau> + </omega> + </theta> + </omicron> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]/kappa[@false]/phi[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:lang="no"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::omega[@attrib][@xml:lang="nb"][@xml:id="id4"]//sigma[@xml:lang="en-GB"][not(following-sibling::*)]//theta//omicron[not(preceding-sibling::*)]/rho[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en-GB"][not(following-sibling::*)]//rho[@abort][@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]/omega[not(child::node())][following-sibling::sigma[contains(concat(@content,"$"),"e value$")][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::sigma)][following-sibling::lambda[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[contains(@attrib,"e")][@xml:lang="en"][@xml:id="id8"][following-sibling::*[position()=2]][not(child::node())][following-sibling::lambda[@and="solid 1px green"][@xml:lang="no"][@xml:id="id9"][not(child::node())][following-sibling::sigma[@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 5]][position() = 1]]]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <kappa false="100%"> + <phi xml:lang="en-US" xml:id="id2"/> + <xi xml:lang="en-GB"/> + <sigma xml:lang="no" xml:id="id3"/> + <omega attrib="another attribute value" xml:lang="nb" xml:id="id4"> + <sigma xml:lang="en-GB"> + <theta> + <omicron> + <rho xml:id="id5"/> + <lambda xml:lang="en-GB"> + <rho abort="false" xml:lang="en-GB" xml:id="id6"> + <omega/> + <sigma content="attribute value" xml:lang="nb" xml:id="id7"/> + <lambda xml:lang="en-US"/> + <omega attrib="attribute value" xml:lang="en" xml:id="id8"/> + <lambda and="solid 1px green" xml:lang="no" xml:id="id9"/> + <sigma xml:lang="en" xml:id="id10"> + <green>This text must be green</green> + </sigma> + </rho> + </lambda> + </omicron> + </theta> + </sigma> + </omega> + </kappa> + </iota> + </tree> + </test> + <test> + <xpath>//xi[contains(@true,"e")][@xml:id="id1"]//nu[following-sibling::*[position()=5]][following-sibling::mu[@delete][@xml:id="id2"][not(child::node())][following-sibling::gamma[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::*[contains(concat(@false,"$"),"is-is-att-value$")][@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::theta[@and][preceding-sibling::*[position() = 4]][following-sibling::theta[@xml:lang="nb"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//delta[contains(concat(@attrib,"$"),"false$")][@xml:id="id5"][not(preceding-sibling::*)]/mu[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(concat(@content,"$"),"true$")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::iota[@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[not(child::node())][following-sibling::xi[contains(@att,"56789")][@xml:id="id8"][following-sibling::chi[preceding-sibling::*[position() = 5]][position() = 1]][position() = 1]]]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <xi true="solid 1px green" xml:id="id1"> + <nu/> + <mu delete="solid 1px green" xml:id="id2"/> + <gamma xml:lang="en-US" xml:id="id3"/> + <any false="this-is-att-value" xml:lang="en" xml:id="id4"/> + <theta and="attribute"/> + <theta xml:lang="nb"> + <delta attrib="false" xml:id="id5"> + <mu xml:id="id6"/> + <mu content="true"/> + <iota xml:id="id7"/> + <omega/> + <xi att="123456789" xml:id="id8"/> + <chi> + <green>This text must be green</green> + </chi> + </delta> + </theta> + </xi> + </tree> + </test> + <test> + <xpath>//tau[@token][@xml:id="id1"]//theta[starts-with(@insert,"10")][@xml:lang="en-US"][not(following-sibling::*)]/kappa[@and][@xml:id="id2"]//alpha[contains(@data,"nt")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@src][preceding-sibling::*[position() = 1]]//delta[@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::*[@attribute="this.nodeValue"][@xml:id="id4"][not(following-sibling::*)]/omicron[@title][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//phi[starts-with(@string,"this-")][@xml:id="id6"][following-sibling::rho[starts-with(@name,"f")][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::zeta[not(following-sibling::*)]/gamma[contains(@token,"odeValue")][not(following-sibling::*)]/theta[contains(concat(@abort,"$"),"his.nodeValue$")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:id="id8"]//kappa[@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)]//upsilon[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@number][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[contains(concat(@desciption,"$"),"s-is-att-value$")][@xml:lang="en"][@xml:id="id10"][following-sibling::sigma[@xml:id="id11"][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <tau token="attribute value" xml:id="id1"> + <theta insert="100%" xml:lang="en-US"> + <kappa and="100%" xml:id="id2"> + <alpha data="content"/> + <upsilon src="solid 1px green"> + <delta xml:id="id3"/> + <any attribute="this.nodeValue" xml:id="id4"> + <omicron title="attribute-value" xml:id="id5"/> + <chi xml:lang="en-GB"> + <phi string="this-is-att-value" xml:id="id6"/> + <rho name="false" xml:id="id7"/> + <zeta> + <gamma token="this.nodeValue"> + <theta abort="this.nodeValue" xml:lang="en-US"/> + <sigma xml:id="id8"> + <kappa xml:lang="no" xml:id="id9"> + <upsilon xml:lang="nb"> + <tau number="content"/> + <sigma xml:lang="no"> + <tau desciption="this-is-att-value" xml:lang="en" xml:id="id10"/> + <sigma xml:id="id11"> + <green>This text must be green</green> + </sigma> + </sigma> + </upsilon> + </kappa> + </sigma> + </gamma> + </zeta> + </chi> + </any> + </upsilon> + </kappa> + </theta> + </tau> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]/xi[@xml:lang="nb"][@xml:id="id2"]/alpha[@number][not(preceding-sibling::*)][following-sibling::zeta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/delta[@or][not(child::node())][following-sibling::mu[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::lambda[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/xi[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@name][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[starts-with(@att,"soli")][following-sibling::delta[@number="_blank"][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]/beta[@xml:lang="en-GB"]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <xi xml:lang="nb" xml:id="id2"> + <alpha number="attribute-value"/> + <zeta xml:lang="en-US"> + <delta or="_blank"/> + <mu xml:lang="nb" xml:id="id3"/> + <gamma xml:id="id4"/> + <lambda xml:lang="no" xml:id="id5"> + <xi xml:lang="en"> + <mu name="_blank" xml:lang="en"/> + <phi att="solid 1px green"/> + <delta number="_blank" xml:lang="en" xml:id="id6"> + <beta xml:lang="en-GB"> + <green>This text must be green</green> + </beta> + </delta> + </xi> + </lambda> + </zeta> + </xi> + </phi> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-US"]//lambda[not(preceding-sibling::*)]//mu[@xml:lang="no-nb"][not(following-sibling::*)]//pi[@class][@xml:lang="no"][not(following-sibling::*)]/nu[@token][@xml:lang="no"][@xml:id="id1"]//xi[@xml:id="id2"][not(following-sibling::*)]//omega[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::zeta[preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[contains(concat(@attr,"$"),"tribute$")][@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::psi[@attribute="false"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//beta[contains(@false,"ut")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@object][@xml:lang="en"]/*[@xml:lang="no-nb"][not(following-sibling::*)]//zeta[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::upsilon[@true][preceding-sibling::*[position() = 1]]//phi[@xml:id="id7"][following-sibling::iota[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[starts-with(concat(@object,"-"),"solid 1px green-")][preceding-sibling::*[position() = 2]]//pi[@content="this-is-att-value"][@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="no-nb"][not(child::node())][following-sibling::gamma[@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/beta[@att][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@number][@xml:lang="no"][not(following-sibling::*)][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-US"> + <lambda> + <mu xml:lang="no-nb"> + <pi class="another attribute value" xml:lang="no"> + <nu token="this-is-att-value" xml:lang="no" xml:id="id1"> + <xi xml:id="id2"> + <omega xml:lang="en-US" xml:id="id3"/> + <zeta/> + <nu attr="attribute" xml:lang="no-nb" xml:id="id4"/> + <psi attribute="false" xml:id="id5"> + <beta false="another attribute value" xml:id="id6"> + <lambda object="another attribute value" xml:lang="en"> + <any xml:lang="no-nb"> + <zeta xml:lang="nb"/> + <upsilon true="attribute value"> + <phi xml:id="id7"/> + <iota/> + <gamma object="solid 1px green"> + <pi content="this-is-att-value" xml:id="id8"/> + <any xml:lang="no-nb"/> + <gamma xml:lang="en-GB" xml:id="id9"> + <beta att="_blank" xml:lang="en-US"/> + <phi number="true" xml:lang="no"> + <green>This text must be green</green> + </phi> + </gamma> + </gamma> + </upsilon> + </any> + </lambda> + </beta> + </psi> + </xi> + </nu> + </pi> + </mu> + </lambda> + </any> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="en-GB"]/alpha[@xml:id="id1"][following-sibling::phi[contains(@data,"_bl")][@xml:lang="nb"][@xml:id="id2"][following-sibling::rho[@xml:lang="en-GB"][not(following-sibling::*)]/upsilon[contains(concat(@title,"$"),"this.nodeValue$")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::epsilon[@false="another attribute value"][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//pi[@xml:lang="no"][not(child::node())][following-sibling::eta[@desciption="attribute"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:id="id5"]/iota[@data][@xml:id="id6"]/iota[contains(concat(@false,"$"),"e$")][following-sibling::*[position()=3]][not(child::node())][following-sibling::mu[@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::omega[starts-with(concat(@attr,"-"),"attribute value-")][@xml:id="id9"][preceding-sibling::*[position() = 3]]//phi//beta[@xml:lang="en-US"][@xml:id="id10"][not(following-sibling::*)]//sigma[not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::omicron[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[contains(concat(@number,"$"),"e$")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id12"]//mu[contains(@delete,"olid 1px")][@xml:lang="nb"][@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::mu)]/psi[@class="content"][@xml:lang="no"][not(preceding-sibling::psi)][not(child::node())][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id14"][preceding-sibling::*[position() = 1]][following-sibling::tau[@xml:lang="nb"][@xml:id="id15"]]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="en-GB"> + <alpha xml:id="id1"/> + <phi data="_blank" xml:lang="nb" xml:id="id2"/> + <rho xml:lang="en-GB"> + <upsilon title="this.nodeValue" xml:lang="nb"/> + <epsilon false="another attribute value" xml:lang="no-nb" xml:id="id3"> + <pi xml:lang="no"/> + <eta desciption="attribute" xml:id="id4"/> + <omega xml:id="id5"> + <iota data="attribute value" xml:id="id6"> + <iota false="true"/> + <mu xml:lang="en-US" xml:id="id7"/> + <any xml:lang="en-GB" xml:id="id8"/> + <omega attr="attribute value" xml:id="id9"> + <phi> + <beta xml:lang="en-US" xml:id="id10"> + <sigma/> + <omicron xml:id="id11"/> + <xi number="another attribute value"/> + <kappa xml:lang="en-GB" xml:id="id12"> + <mu delete="solid 1px green" xml:lang="nb" xml:id="id13"> + <psi class="content" xml:lang="no"/> + <upsilon xml:lang="en-US" xml:id="id14"/> + <tau xml:lang="nb" xml:id="id15"> + <green>This text must be green</green> + </tau> + </mu> + </kappa> + </beta> + </phi> + </omega> + </iota> + </omega> + </epsilon> + </rho> + </lambda> + </tree> + </test> + <test> + <xpath>//sigma[@att="123456789"][@xml:id="id1"]//omega[not(child::node())][following-sibling::upsilon[@xml:lang="no"]//sigma[@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::lambda[starts-with(concat(@object,"-"),"true-")][@xml:lang="en-US"]//sigma[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//delta[@true][@xml:lang="en-GB"][@xml:id="id3"]/chi[following-sibling::*[position()=1]][following-sibling::beta[contains(@src,"lid 1px gr")][@xml:lang="no-nb"][not(following-sibling::*)]/*[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[contains(@insert,"-at")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::*[@att][@xml:id="id6"][not(following-sibling::*)]//omega[@or="_blank"][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::phi[starts-with(concat(@attrib,"-"),"content-")][following-sibling::omega[not(following-sibling::*)]/kappa[@true="false"][@xml:id="id7"][not(following-sibling::*)]//omega[@xml:id="id8"][not(preceding-sibling::*)]/beta[@string][@xml:id="id9"][following-sibling::kappa[@desciption][@xml:id="id10"][preceding-sibling::*[position() = 1]]/pi[@attrib="false"][@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi[@xml:id="id12"][not(following-sibling::*)]//epsilon[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <sigma att="123456789" xml:id="id1"> + <omega/> + <upsilon xml:lang="no"> + <sigma xml:lang="en"/> + <lambda object="true" xml:lang="en-US"> + <sigma xml:lang="en-US" xml:id="id2"> + <delta true="another attribute value" xml:lang="en-GB" xml:id="id3"> + <chi/> + <beta src="solid 1px green" xml:lang="no-nb"> + <any xml:id="id4"/> + <theta insert="this-is-att-value" xml:id="id5"/> + <any att="content" xml:id="id6"> + <omega or="_blank"/> + <mu xml:lang="no"/> + <phi attrib="content"/> + <omega> + <kappa true="false" xml:id="id7"> + <omega xml:id="id8"> + <beta string="false" xml:id="id9"/> + <kappa desciption="_blank" xml:id="id10"> + <pi attrib="false" xml:lang="no" xml:id="id11"/> + <pi xml:id="id12"> + <epsilon> + <green>This text must be green</green> + </epsilon> + </pi> + </kappa> + </omega> + </kappa> + </omega> + </any> + </beta> + </delta> + </sigma> + </lambda> + </upsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//eta[@attrib="another attribute value"][@xml:lang="en-GB"]//upsilon[@xml:id="id1"][not(preceding-sibling::*)]/tau[starts-with(concat(@token,"-"),"false-")][@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]//delta[@string][not(preceding-sibling::*)][following-sibling::phi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[starts-with(@abort,"conten")][not(preceding-sibling::nu)][following-sibling::epsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::beta[starts-with(@delete,"solid 1px gre")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id5"]/mu[not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-GB"][not(child::node())][following-sibling::epsilon[@xml:lang="en"][@xml:id="id6"][following-sibling::alpha[not(child::node())][following-sibling::rho[@number="true"][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/delta[@xml:lang="no"]//nu[@true="solid 1px green"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::alpha[@desciption][@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 2]]]]]]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <eta attrib="another attribute value" xml:lang="en-GB"> + <upsilon xml:id="id1"> + <tau token="false" xml:lang="no" xml:id="id2"> + <delta string="false"/> + <phi> + <xi xml:lang="nb" xml:id="id3"/> + <alpha xml:id="id4"> + <nu abort="content"/> + <epsilon xml:lang="no-nb"/> + <beta delete="solid 1px green" xml:lang="nb"/> + <tau xml:lang="en-GB" xml:id="id5"> + <mu/> + <omicron xml:lang="en-GB"/> + <epsilon xml:lang="en" xml:id="id6"/> + <alpha/> + <rho number="true" xml:lang="en" xml:id="id7"> + <delta xml:lang="no"> + <nu true="solid 1px green" xml:id="id8"/> + <eta xml:id="id9"/> + <alpha desciption="true" xml:lang="nb" xml:id="id10"> + <green>This text must be green</green> + </alpha> + </delta> + </rho> + </tau> + </alpha> + </phi> + </tau> + </upsilon> + </eta> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(@src,"_bla")][@xml:lang="en-GB"]/nu[@xml:lang="en-US"][@xml:id="id1"]//theta//chi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@number][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@token="_blank"][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[starts-with(@content,"tru")]//omicron[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::nu[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]]//upsilon[not(preceding-sibling::*)][following-sibling::gamma[not(following-sibling::*)]//delta[starts-with(@number,"1")]//psi[@xml:id="id9"][not(following-sibling::*)]//omicron[contains(concat(@class,"$"),"false$")][@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:id="id11"][preceding-sibling::*[position() = 1]]//psi[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <gamma src="_blank" xml:lang="en-GB"> + <nu xml:lang="en-US" xml:id="id1"> + <theta> + <chi xml:id="id2"> + <rho xml:lang="no-nb"> + <psi xml:lang="no" xml:id="id3"> + <lambda xml:id="id4"/> + <any number="_blank" xml:id="id5"> + <xi xml:lang="en-GB" xml:id="id6"/> + <epsilon token="_blank" xml:lang="en" xml:id="id7"> + <chi content="true"> + <omicron/> + <nu xml:lang="en-GB" xml:id="id8"> + <upsilon/> + <gamma> + <delta number="100%"> + <psi xml:id="id9"> + <omicron class="false" xml:id="id10"/> + <iota xml:id="id11"> + <psi> + <green>This text must be green</green> + </psi> + </iota> + </psi> + </delta> + </gamma> + </nu> + </chi> + </epsilon> + </any> + </psi> + </rho> + </chi> + </theta> + </nu> + </gamma> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]//tau[@desciption="attribute"][@xml:lang="en"][not(child::node())][following-sibling::rho[@and="true"][@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:id="id3"][not(preceding-sibling::*)]//epsilon[contains(@content,"ttr")][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::gamma)][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/gamma[@insert][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="no-nb"][@xml:id="id6"][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <tau desciption="attribute" xml:lang="en"/> + <rho and="true" xml:lang="en-GB" xml:id="id2"> + <mu xml:id="id3"> + <epsilon content="attribute"/> + <gamma xml:lang="no-nb" xml:id="id4"/> + <any> + <gamma insert="false" xml:lang="en-US" xml:id="id5"/> + <lambda xml:lang="no-nb" xml:id="id6"> + <green>This text must be green</green> + </lambda> + </any> + </mu> + </rho> + </nu> + </tree> + </test> + <test> + <xpath>//sigma[contains(concat(@class,"$"),"9$")]/nu[@string][@xml:lang="en"][@xml:id="id1"][not(child::node())][following-sibling::iota[starts-with(concat(@abort,"-"),"attribute-")][@xml:lang="en"][@xml:id="id2"][following-sibling::mu[starts-with(concat(@number,"-"),"123456789-")][preceding-sibling::*[position() = 2]][not(preceding-sibling::mu)]//nu[@xml:lang="en-US"][@xml:id="id3"]/upsilon[@or="123456789"][@xml:lang="no"]//phi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::iota[starts-with(concat(@false,"-"),"100%-")][@xml:id="id4"]/chi[@number][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 1]][following-sibling::tau[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 3]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <sigma class="123456789"> + <nu string="_blank" xml:lang="en" xml:id="id1"/> + <iota abort="attribute" xml:lang="en" xml:id="id2"/> + <mu number="123456789"> + <nu xml:lang="en-US" xml:id="id3"> + <upsilon or="123456789" xml:lang="no"> + <phi xml:lang="no"/> + <iota false="100%" xml:id="id4"> + <chi number="another attribute value" xml:lang="no" xml:id="id5"/> + <omega/> + <tau xml:lang="en-US" xml:id="id6"/> + <epsilon> + <green>This text must be green</green> + </epsilon> + </iota> + </upsilon> + </nu> + </mu> + </sigma> + </tree> + </test> + <test> + <xpath>//zeta[starts-with(@desciption,"_blank")]/theta[starts-with(@title,"_bl")][following-sibling::lambda[starts-with(@object,"1234")][not(following-sibling::*)]/phi[@xml:id="id1"]//omicron[not(preceding-sibling::*)][following-sibling::zeta[starts-with(@insert,"_blank")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <zeta desciption="_blank"> + <theta title="_blank"/> + <lambda object="123456789"> + <phi xml:id="id1"> + <omicron/> + <zeta insert="_blank" xml:lang="nb" xml:id="id2"> + <green>This text must be green</green> + </zeta> + </phi> + </lambda> + </zeta> + </tree> + </test> + <test> + <xpath>//beta[@xml:id="id1"]//zeta[contains(@object,"de")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[not(preceding-sibling::*)]//lambda[@xml:lang="en-US"][not(following-sibling::*)]/psi[contains(concat(@number,"$"),"e$")][not(preceding-sibling::*)][not(following-sibling::*)]//xi[contains(concat(@name,"$"),"her attribute value$")][@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="no-nb"]//tau[@xml:id="id3"]/gamma[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:id="id1"> + <zeta object="this.nodeValue" xml:lang="en-US" xml:id="id2"> + <lambda> + <lambda xml:lang="en-US"> + <psi number="false"> + <xi name="another attribute value" xml:lang="en-GB"/> + <omega xml:lang="no-nb"> + <tau xml:id="id3"> + <gamma xml:lang="en-US" xml:id="id4"> + <green>This text must be green</green> + </gamma> + </tau> + </omega> + </psi> + </lambda> + </lambda> + </zeta> + </beta> + </tree> + </test> + <test> + <xpath>//delta[@attr="solid 1px green"][@xml:lang="no"][@xml:id="id1"]//beta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//eta[@src="attribute value"][@xml:id="id2"][not(following-sibling::*)]/phi[@token="true"][@xml:lang="en"][not(child::node())][following-sibling::phi[following-sibling::lambda[@xml:lang="en"][preceding-sibling::*[position() = 2]]/pi[contains(concat(@or,"$"),"lse$")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <delta attr="solid 1px green" xml:lang="no" xml:id="id1"> + <beta xml:lang="en-US"/> + <omega xml:lang="en-GB"> + <eta src="attribute value" xml:id="id2"> + <phi token="true" xml:lang="en"/> + <phi/> + <lambda xml:lang="en"> + <pi or="false" xml:lang="en-US" xml:id="id3"/> + <iota xml:lang="no-nb" xml:id="id4"> + <green>This text must be green</green> + </iota> + </lambda> + </eta> + </omega> + </delta> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en-US"][@xml:id="id1"]/iota[@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:id="id3"]/*[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[following-sibling::*[position()=1]][following-sibling::xi[@number][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[@src][@xml:lang="nb"][not(child::node())][following-sibling::delta[contains(concat(@abort,"$")," green$")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::nu[not(following-sibling::*)]/xi[starts-with(@name,"th")][@xml:lang="no"][not(following-sibling::*)][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>1</nth> + </result> + <tree> + <iota xml:lang="en-US" xml:id="id1"> + <iota xml:id="id2"/> + <omega xml:id="id3"> + <any xml:lang="en" xml:id="id4"/> + <xi/> + <xi number="this.nodeValue"> + <mu src="_blank" xml:lang="nb"/> + <delta abort="solid 1px green" xml:lang="no-nb" xml:id="id5"/> + <nu> + <xi name="this.nodeValue" xml:lang="no"> + <green>This text must be green</green> + </xi> + </nu> + </xi> + </omega> + </iota> + </tree> + </test> + <test> + <xpath>//gamma[@xml:lang="en-US"][@xml:id="id1"]//iota[@data][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::beta[contains(concat(@class,"$"),"x green$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::epsilon[starts-with(concat(@desciption,"-"),"solid 1px green-")][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@object][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::upsilon[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 4]]/psi[@xml:id="id5"][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 1]]//iota[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[not(following-sibling::*)]//theta[@xml:id="id7"][not(preceding-sibling::*)]/omega[contains(concat(@insert,"$"),"deValue$")][@xml:id="id8"][not(preceding-sibling::*)]/theta[@object][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@token][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id11"][not(following-sibling::*)]/pi[contains(concat(@name,"$"),"rue$")][@xml:id="id12"][not(preceding-sibling::pi or following-sibling::pi)][not(child::node())][following-sibling::delta[@xml:lang="en-US"][@xml:id="id13"]//omicron[position() = 1]][position() = 1]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:lang="en-US" xml:id="id1"> + <iota data="_blank" xml:id="id2"/> + <beta class="solid 1px green" xml:lang="en-GB"/> + <epsilon desciption="solid 1px green" xml:id="id3"/> + <psi object="true"/> + <upsilon xml:lang="en" xml:id="id4"> + <psi xml:id="id5"/> + <xi> + <iota xml:lang="no" xml:id="id6"/> + <psi> + <theta xml:id="id7"> + <omega insert="this.nodeValue" xml:id="id8"> + <theta object="_blank" xml:lang="en" xml:id="id9"> + <theta token="another attribute value" xml:id="id10"/> + <gamma xml:lang="no-nb" xml:id="id11"> + <pi name="true" xml:id="id12"/> + <delta xml:lang="en-US" xml:id="id13"> + <omicron> + <green>This text must be green</green> + </omicron> + </delta> + </gamma> + </theta> + </omega> + </theta> + </psi> + </xi> + </upsilon> + </gamma> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en-US"]//sigma[contains(concat(@object,"$"),"reen$")][not(preceding-sibling::*)]//nu[contains(concat(@delete,"$"),"te value$")][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="no"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::chi[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]/mu[starts-with(concat(@name,"-"),"100%-")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[starts-with(concat(@data,"-"),"123456789-")][not(following-sibling::*)]/sigma[@abort][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id3"][not(following-sibling::*)]//psi[@delete="true"][@xml:lang="no-nb"]/epsilon[contains(concat(@attribute,"$"),"ent$")][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@attr="this.nodeValue"][@xml:lang="nb"]/epsilon[@object][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(@attrib,"c")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::beta[@attrib="solid 1px green"][@xml:lang="nb"][not(child::node())][following-sibling::pi[@xml:lang="no-nb"]//delta[contains(concat(@abort,"$"),"00%$")][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@xml:id="id6"][not(child::node())][following-sibling::eta[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@desciption]/delta[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@delete="another attribute value"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="en-US"> + <sigma object="solid 1px green"> + <nu delete="attribute value" xml:lang="en-GB" xml:id="id1"/> + <iota xml:lang="no" xml:id="id2"/> + <chi xml:lang="en-US"> + <mu name="100%" xml:lang="no"/> + <theta xml:lang="no-nb"> + <tau data="123456789"> + <sigma abort="true" xml:lang="en-GB"> + <chi xml:id="id3"> + <psi delete="true" xml:lang="no-nb"> + <epsilon attribute="content" xml:id="id4"/> + <theta attr="this.nodeValue" xml:lang="nb"> + <epsilon object="attribute value" xml:lang="en" xml:id="id5"/> + <pi attrib="content" xml:lang="no-nb"/> + <beta attrib="solid 1px green" xml:lang="nb"/> + <pi xml:lang="no-nb"> + <delta abort="100%"> + <omicron xml:id="id6"/> + <eta xml:lang="no"/> + <lambda desciption="123456789"> + <delta xml:id="id7"/> + <omega delete="another attribute value" xml:id="id8"> + <green>This text must be green</green> + </omega> + </lambda> + </delta> + </pi> + </theta> + </psi> + </chi> + </sigma> + </tau> + </theta> + </chi> + </sigma> + </omicron> + </tree> + </test> + <test> + <xpath>//pi[@and][@xml:lang="nb"]//mu[@content][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/zeta[starts-with(@content,"_b")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::eta[starts-with(concat(@name,"-"),"content-")][preceding-sibling::*[position() = 1]][following-sibling::*[@abort="true"][not(child::node())][following-sibling::eta[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 3]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <pi and="attribute" xml:lang="nb"> + <mu content="100%" xml:lang="en-GB" xml:id="id1"/> + <upsilon xml:id="id2"> + <any xml:lang="en-US" xml:id="id3"> + <zeta content="_blank" xml:lang="en-US"/> + <eta name="content"/> + <any abort="true"/> + <eta xml:lang="en-GB" xml:id="id4"> + <green>This text must be green</green> + </eta> + </any> + </upsilon> + </pi> + </tree> + </test> + <test> + <xpath>//omega[starts-with(concat(@false,"-"),"solid 1px green-")][@xml:id="id1"]//*[@class][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::alpha[@xml:lang="en-US"][following-sibling::upsilon[@insert="attribute value"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/omicron[starts-with(@content,"this-is-att-v")][@xml:lang="no-nb"]/*[starts-with(@title,"solid 1px")][@xml:lang="en"][not(following-sibling::*)]//rho[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/nu[contains(concat(@data,"$"),"bute$")][following-sibling::omega[not(child::node())][following-sibling::upsilon[not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/chi[contains(concat(@token,"$"),"ue$")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)]/theta[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::omicron[@string][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[contains(concat(@src,"$"),"ute value$")][@xml:id="id8"][not(child::node())][following-sibling::omega[starts-with(concat(@delete,"-"),"this.nodeValue-")][preceding-sibling::*[position() = 1]][following-sibling::psi[starts-with(concat(@false,"-"),"attribute value-")][@xml:lang="en-GB"][following-sibling::zeta[@data][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]]//phi[starts-with(@token,"a")][@xml:lang="nb"][@xml:id="id9"][following-sibling::epsilon[starts-with(concat(@data,"-"),"false-")][@xml:lang="no"][@xml:id="id10"]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <omega false="solid 1px green" xml:id="id1"> + <any class="123456789" xml:lang="en-GB" xml:id="id2"/> + <alpha xml:lang="en-US"/> + <upsilon insert="attribute value"/> + <rho xml:lang="no" xml:id="id3"> + <omicron content="this-is-att-value" xml:lang="no-nb"> + <any title="solid 1px green" xml:lang="en"> + <rho xml:lang="no-nb" xml:id="id4"> + <nu data="attribute"/> + <omega/> + <upsilon/> + <chi xml:lang="no" xml:id="id5"> + <chi token="attribute-value" xml:lang="no-nb" xml:id="id6"> + <theta xml:lang="en-US" xml:id="id7"/> + <omicron string="attribute value"> + <eta src="another attribute value" xml:id="id8"/> + <omega delete="this.nodeValue"/> + <psi false="attribute value" xml:lang="en-GB"/> + <zeta data="true" xml:lang="en-GB"> + <phi token="another attribute value" xml:lang="nb" xml:id="id9"/> + <epsilon data="false" xml:lang="no" xml:id="id10"> + <green>This text must be green</green> + </epsilon> + </zeta> + </omicron> + </chi> + </chi> + </rho> + </any> + </omicron> + </rho> + </omega> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en"]/mu[@false][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@delete][@xml:lang="en-US"][@xml:id="id1"][not(child::node())][following-sibling::beta[@xml:id="id2"][preceding-sibling::*[position() = 1]]/sigma[@xml:id="id3"][not(following-sibling::*)]//psi[@content][@xml:id="id4"][following-sibling::epsilon[@attribute][@xml:id="id5"][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en"> + <mu false="attribute value" xml:lang="en"> + <chi delete="another attribute value" xml:lang="en-US" xml:id="id1"/> + <beta xml:id="id2"> + <sigma xml:id="id3"> + <psi content="_blank" xml:id="id4"/> + <epsilon attribute="content" xml:id="id5"> + <green>This text must be green</green> + </epsilon> + </sigma> + </beta> + </mu> + </kappa> + </tree> + </test> + <test> + <xpath>//*[@insert][@xml:id="id1"]//omicron[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta//beta[@xml:id="id2"][not(preceding-sibling::*)]/rho[@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::upsilon[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[contains(concat(@attribute,"$"),"px green$")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@and][@xml:lang="en"]//eta[not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::psi[@content][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::psi[contains(concat(@attr,"$"),"is-is-att-value$")][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <any insert="another attribute value" xml:id="id1"> + <omicron xml:lang="en"> + <zeta> + <beta xml:id="id2"> + <rho xml:lang="en-US"/> + <upsilon xml:lang="no" xml:id="id3"> + <upsilon attribute="solid 1px green" xml:lang="no"/> + <sigma and="100%" xml:lang="en"> + <eta/> + <omicron xml:lang="no" xml:id="id4"/> + <psi content="attribute" xml:lang="en-US"/> + <psi attr="this-is-att-value"> + <green>This text must be green</green> + </psi> + </sigma> + </upsilon> + </beta> + </zeta> + </omicron> + </any> + </tree> + </test> + <test> + <xpath>//omega[@or][@xml:lang="no-nb"][@xml:id="id1"]/phi[starts-with(@or,"a")][@xml:lang="en-US"][not(child::node())][following-sibling::eta[@xml:lang="en-GB"][not(following-sibling::*)]/psi[contains(@name,"s-is-att-value")][@xml:lang="en"][not(child::node())][following-sibling::theta[@xml:id="id2"]/epsilon[@or][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]//tau[contains(concat(@and,"$"),"ue$")][not(child::node())][following-sibling::*[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[following-sibling::*[position()=5]][following-sibling::epsilon[@abort="123456789"][@xml:id="id4"][following-sibling::*[position()=4]][following-sibling::epsilon[@desciption="another attribute value"][@xml:lang="en-US"][not(child::node())][following-sibling::mu[@name][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::nu[@name][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][following-sibling::tau[contains(@name,"another attribute value")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 5]]/alpha[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@class][not(child::node())][following-sibling::phi[@delete][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::nu[following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@desciption][@xml:id="id8"][preceding-sibling::*[position() = 4]]//delta[@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::delta)]/chi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::psi[starts-with(@data,"tr")][@xml:lang="no"][@xml:id="id10"]//xi[@number][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <omega or="attribute value" xml:lang="no-nb" xml:id="id1"> + <phi or="attribute value" xml:lang="en-US"/> + <eta xml:lang="en-GB"> + <psi name="this-is-att-value" xml:lang="en"/> + <theta xml:id="id2"> + <epsilon or="attribute-value"/> + <pi xml:lang="en" xml:id="id3"> + <tau and="this-is-att-value"/> + <any xml:lang="en-GB"> + <chi/> + <epsilon abort="123456789" xml:id="id4"/> + <epsilon desciption="another attribute value" xml:lang="en-US"/> + <mu name="_blank" xml:id="id5"/> + <nu name="this.nodeValue" xml:lang="no-nb"/> + <tau name="another attribute value" xml:lang="en" xml:id="id6"> + <alpha xml:id="id7"/> + <sigma class="attribute-value"/> + <phi delete="attribute-value" xml:lang="nb"/> + <nu/> + <nu desciption="solid 1px green" xml:id="id8"> + <delta xml:lang="nb" xml:id="id9"> + <chi xml:lang="en"/> + <psi data="true" xml:lang="no" xml:id="id10"> + <xi number="false" xml:id="id11"> + <green>This text must be green</green> + </xi> + </psi> + </delta> + </nu> + </tau> + </any> + </pi> + </theta> + </eta> + </omega> + </tree> + </test> + <test> + <xpath>//omega[contains(@token,"his-is-")][@xml:id="id1"]/omicron[@xml:lang="en-GB"][not(preceding-sibling::*)]//pi[starts-with(@object,"tr")][not(child::node())][following-sibling::eta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[@xml:lang="en"][@xml:id="id2"][not(child::node())][following-sibling::chi[@xml:lang="no"][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omega token="this-is-att-value" xml:id="id1"> + <omicron xml:lang="en-GB"> + <pi object="true"/> + <eta xml:lang="en-GB"/> + <lambda xml:lang="en" xml:id="id2"/> + <chi xml:lang="no"> + <green>This text must be green</green> + </chi> + </omicron> + </omega> + </tree> + </test> + <test> + <xpath>//tau[starts-with(concat(@desciption,"-"),"false-")]/chi[@att][@xml:lang="no"][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[starts-with(concat(@token,"-"),"content-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/sigma[contains(concat(@number,"$")," attribute value$")][@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::delta[@false][@xml:lang="nb"][@xml:id="id3"][not(child::node())][following-sibling::eta[@attr][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::eta[@class="123456789"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/iota[starts-with(concat(@title,"-"),"true-")][@xml:lang="nb"][not(preceding-sibling::*)]//psi[starts-with(concat(@number,"-"),"100%-")][@xml:lang="no"][@xml:id="id5"]//omicron[@attribute="true"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@true][@xml:id="id7"][not(preceding-sibling::*)][not(preceding-sibling::beta or following-sibling::beta)]//pi[starts-with(concat(@number,"-"),"solid 1px green-")][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::sigma[contains(@or,"t")][@xml:lang="en-GB"][not(following-sibling::*)]/chi[contains(concat(@abort,"$"),"%$")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omicron[@or][not(preceding-sibling::*)]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <tau desciption="false"> + <chi att="false" xml:lang="no" xml:id="id1"/> + <rho token="content"> + <sigma number="another attribute value" xml:lang="nb" xml:id="id2"/> + <delta false="content" xml:lang="nb" xml:id="id3"/> + <eta attr="_blank" xml:lang="en-GB"/> + <eta class="123456789" xml:id="id4"> + <iota title="true" xml:lang="nb"> + <psi number="100%" xml:lang="no" xml:id="id5"> + <omicron attribute="true" xml:id="id6"> + <beta true="123456789" xml:id="id7"> + <pi number="solid 1px green" xml:lang="no" xml:id="id8"/> + <sigma or="content" xml:lang="en-GB"> + <chi abort="100%" xml:lang="nb"/> + <iota xml:lang="nb"/> + <tau xml:lang="no" xml:id="id9"> + <omicron or="content"> + <green>This text must be green</green> + </omicron> + </tau> + </sigma> + </beta> + </omicron> + </psi> + </iota> + </eta> + </rho> + </tau> + </tree> + </test> + <test> + <xpath>//delta[@xml:id="id1"]//pi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[@attrib][preceding-sibling::*[position() = 1]]//nu[@xml:id="id2"][not(following-sibling::*)]//chi[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[contains(concat(@true,"$"),"value$")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::*[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[starts-with(@attrib,"_bla")][@xml:lang="nb"][@xml:id="id5"]//mu[@token][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::kappa[@name="attribute"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@data][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[@att="solid 1px green"][@xml:id="id8"][not(following-sibling::*)]/delta[starts-with(@att,"attribute-")][@xml:id="id9"][not(following-sibling::*)]/sigma[@delete][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id10"][following-sibling::delta[@number][@xml:lang="no"]/tau[@false][@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[starts-with(@string,"12345")][@xml:lang="en-US"][@xml:id="id12"][not(following-sibling::*)]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:id="id1"> + <pi xml:lang="no-nb"/> + <any attrib="another attribute value"> + <nu xml:id="id2"> + <chi xml:lang="nb" xml:id="id3"> + <beta true="attribute-value" xml:id="id4"/> + <any/> + <tau attrib="_blank" xml:lang="nb" xml:id="id5"> + <mu token="this.nodeValue" xml:lang="en-US"/> + <kappa name="attribute" xml:id="id6"> + <psi data="100%" xml:lang="en-GB" xml:id="id7"/> + <omicron att="solid 1px green" xml:id="id8"> + <delta att="attribute-value" xml:id="id9"> + <sigma delete="attribute"/> + <zeta xml:lang="en-GB" xml:id="id10"/> + <delta number="this.nodeValue" xml:lang="no"> + <tau false="attribute" xml:lang="no-nb" xml:id="id11"> + <chi string="123456789" xml:lang="en-US" xml:id="id12"> + <green>This text must be green</green> + </chi> + </tau> + </delta> + </delta> + </omicron> + </kappa> + </tau> + </chi> + </nu> + </any> + </delta> + </tree> + </test> + <test> + <xpath>//mu[@and]//*[starts-with(concat(@content,"-"),"attribute value-")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::epsilon[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::zeta[starts-with(@content,"another a")][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/mu[@name][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[not(child::node())][following-sibling::gamma[@xml:lang="no"]/upsilon[@xml:id="id3"][not(preceding-sibling::*)]//omicron[@att][@xml:lang="en"][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::gamma[@xml:lang="en"][not(following-sibling::*)]//gamma[@att="solid 1px green"]//epsilon[contains(concat(@attrib,"$"),"ue$")][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][following-sibling::chi[@abort][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega[@xml:id="id7"][preceding-sibling::*[position() = 3]]//nu[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <mu and="false"> + <any content="attribute value" xml:lang="en-US" xml:id="id1"/> + <epsilon xml:lang="no"/> + <zeta content="another attribute value" xml:id="id2"> + <mu name="false" xml:lang="no-nb"/> + <sigma/> + <gamma xml:lang="no"> + <upsilon xml:id="id3"> + <omicron att="solid 1px green" xml:lang="en"/> + <psi xml:lang="en-GB" xml:id="id4"/> + <pi xml:lang="no-nb" xml:id="id5"/> + <gamma xml:lang="en"> + <gamma att="solid 1px green"> + <epsilon attrib="true"/> + <sigma xml:lang="en-GB"/> + <chi abort="attribute value" xml:lang="en-GB" xml:id="id6"/> + <omega xml:id="id7"> + <nu xml:lang="en"> + <green>This text must be green</green> + </nu> + </omega> + </gamma> + </gamma> + </upsilon> + </gamma> + </zeta> + </mu> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="en"]/chi[contains(concat(@and,"$"),"solid 1px green$")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)]//mu[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/*[@xml:lang="nb"][not(child::node())][following-sibling::omega[@token="content"][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//beta[@att="attribute value"][@xml:lang="en-US"][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][following-sibling::kappa[contains(concat(@object,"$"),"content$")][@xml:lang="en-GB"][not(following-sibling::*)]/gamma][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="en"> + <chi and="solid 1px green" xml:lang="en-US" xml:id="id1"> + <mu xml:lang="en-US" xml:id="id2"> + <any xml:lang="nb"/> + <omega token="content" xml:lang="en" xml:id="id3"> + <beta att="attribute value" xml:lang="en-US"/> + <epsilon xml:lang="en-GB"/> + <kappa object="content" xml:lang="en-GB"> + <gamma> + <green>This text must be green</green> + </gamma> + </kappa> + </omega> + </mu> + </chi> + </mu> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="nb"]//rho[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::theta[starts-with(@data,"f")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[not(following-sibling::pi)][not(child::node())][following-sibling::delta[@xml:lang="en"]//zeta[not(child::node())][following-sibling::epsilon[@xml:id="id2"][not(child::node())][following-sibling::lambda[contains(@or,"gre")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/kappa[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(following-sibling::kappa)][not(child::node())][following-sibling::sigma[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::iota[following-sibling::*[position()=1]][not(preceding-sibling::iota)][not(child::node())][following-sibling::omicron[starts-with(@class,"a")][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id8"][following-sibling::omega[@src][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[starts-with(@name,"a")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id10"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="nb"> + <rho xml:lang="en-US" xml:id="id1"/> + <theta data="false" xml:lang="no"/> + <pi/> + <delta xml:lang="en"> + <zeta/> + <epsilon xml:id="id2"/> + <lambda or="solid 1px green"> + <kappa xml:id="id3"/> + <sigma xml:lang="en-US"> + <delta xml:id="id4"/> + <iota/> + <omicron class="attribute value" xml:id="id5"> + <nu xml:lang="no" xml:id="id6"/> + <iota xml:lang="no-nb" xml:id="id7"> + <mu xml:lang="no-nb" xml:id="id8"/> + <omega src="true" xml:id="id9"> + <any name="attribute" xml:lang="nb"> + <upsilon xml:id="id10"> + <green>This text must be green</green> + </upsilon> + </any> + </omega> + </iota> + </omicron> + </sigma> + </lambda> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//eta[contains(concat(@data,"$"),"ntent$")][@xml:lang="en-GB"][@xml:id="id1"]/xi[starts-with(concat(@false,"-"),"false-")][not(preceding-sibling::*)]/*[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::epsilon[@false][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/*[@xml:lang="en-US"][not(child::node())][following-sibling::beta[@true="attribute"][@xml:lang="no"][not(following-sibling::*)]/mu[@abort="another attribute value"][not(child::node())][following-sibling::upsilon[@attrib][following-sibling::nu[contains(concat(@att,"$"),"ue$")]//alpha[@xml:id="id4"][not(following-sibling::*)]/omicron[@object][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[@number="this.nodeValue"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[starts-with(concat(@content,"-"),"this-")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="no-nb"]//*[not(preceding-sibling::*)][not(following-sibling::*)]/chi[not(preceding-sibling::*)][following-sibling::theta[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <eta data="content" xml:lang="en-GB" xml:id="id1"> + <xi false="false"> + <any xml:lang="en-GB" xml:id="id2"/> + <epsilon false="another attribute value" xml:id="id3"/> + <xi> + <any xml:lang="en-US"/> + <beta true="attribute" xml:lang="no"> + <mu abort="another attribute value"/> + <upsilon attrib="attribute"/> + <nu att="attribute-value"> + <alpha xml:id="id4"> + <omicron object="_blank" xml:id="id5"/> + <sigma number="this.nodeValue" xml:id="id6"> + <mu content="this-is-att-value" xml:lang="no"/> + <beta xml:lang="no-nb"> + <any> + <chi/> + <theta xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </theta> + </any> + </beta> + </sigma> + </alpha> + </nu> + </beta> + </xi> + </xi> + </eta> + </tree> + </test> + <test> + <xpath>//iota[starts-with(@false,"attribute ")]//lambda[@or][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[@attr][@xml:lang="en"][not(following-sibling::*)]/xi[@number][@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::xi)][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 2]][following-sibling::sigma[@xml:lang="en-GB"][not(child::node())][following-sibling::iota[@delete="attribute"]//beta[starts-with(concat(@class,"-"),"content-")][@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[@insert][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::*[starts-with(concat(@title,"-"),"attribute-")]/psi[not(preceding-sibling::*)][not(following-sibling::*)]//tau[@xml:id="id4"][following-sibling::iota[starts-with(@attribute,"th")][@xml:lang="en-US"][following-sibling::tau[contains(@attr,"bute-value")][@xml:lang="en"][not(following-sibling::*)]//mu[@insert][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::eta[@string][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="nb"][@xml:id="id6"]/rho[not(child::node())][following-sibling::*[@or][@xml:lang="en"]/xi[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <iota false="attribute value"> + <lambda or="this-is-att-value"/> + <xi attr="attribute-value" xml:lang="en"> + <xi number="attribute-value" xml:lang="en" xml:id="id1"/> + <xi/> + <zeta/> + <sigma xml:lang="en-GB"/> + <iota delete="attribute"> + <beta class="content" xml:lang="en-US" xml:id="id2"/> + <tau insert="false" xml:id="id3"/> + <any title="attribute"> + <psi> + <tau xml:id="id4"/> + <iota attribute="this.nodeValue" xml:lang="en-US"/> + <tau attr="attribute-value" xml:lang="en"> + <mu insert="attribute value" xml:lang="nb" xml:id="id5"/> + <eta string="this.nodeValue" xml:lang="no"/> + <eta xml:lang="nb" xml:id="id6"> + <rho/> + <any or="_blank" xml:lang="en"> + <xi xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </xi> + </any> + </eta> + </tau> + </psi> + </any> + </iota> + </xi> + </iota> + </tree> + </test> + <test> + <xpath>//mu/omega[@xml:id="id1"][not(preceding-sibling::*)]//iota[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[starts-with(@true,"100%")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[starts-with(@title,"tru")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//lambda[@delete][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::upsilon[not(following-sibling::*)]//sigma[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[starts-with(concat(@att,"-"),"true-")][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[starts-with(@and,"conten")][not(following-sibling::*)]//xi[@class][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@or="_blank"][@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]/nu[starts-with(concat(@title,"-"),"attribute value-")][@xml:lang="en-GB"][@xml:id="id9"]//psi[@xml:id="id10"][not(child::node())][following-sibling::delta[@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 1]]//iota[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <omega xml:id="id1"> + <iota xml:id="id2"/> + <nu true="100%" xml:lang="nb" xml:id="id3"/> + <beta title="true" xml:lang="no"> + <lambda delete="100%" xml:id="id4"/> + <upsilon> + <sigma xml:lang="no" xml:id="id5"> + <nu att="true" xml:id="id6"/> + <xi xml:lang="no-nb"/> + <alpha and="content"> + <xi class="false" xml:lang="en" xml:id="id7"> + <omicron or="_blank" xml:lang="en-US" xml:id="id8"> + <nu title="attribute value" xml:lang="en-GB" xml:id="id9"> + <psi xml:id="id10"/> + <delta xml:lang="no" xml:id="id11"> + <iota xml:lang="en-GB"/> + <nu> + <green>This text must be green</green> + </nu> + </delta> + </nu> + </omicron> + </xi> + </alpha> + </sigma> + </upsilon> + </beta> + </omega> + </mu> + </tree> + </test> + <test> + <xpath>//sigma[starts-with(@token,"this.no")]//*//*[@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::tau[@attrib][@xml:id="id2"][preceding-sibling::*[position() = 1]]//*[@and][following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[starts-with(@class,"this-is-at")][@xml:lang="en-US"][following-sibling::omicron[contains(concat(@true,"$"),"attribute$")][@xml:lang="en-US"][@xml:id="id4"]/alpha[@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::beta[@xml:id="id6"][following-sibling::rho[not(child::node())][following-sibling::upsilon[@attr="false"][@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=4]][following-sibling::rho[@xml:lang="en-US"][preceding-sibling::*[position() = 4]][following-sibling::zeta[not(child::node())][following-sibling::nu[starts-with(concat(@desciption,"-"),"false-")][@xml:lang="en"][preceding-sibling::*[position() = 6]][following-sibling::sigma[@xml:lang="en-GB"][@xml:id="id8"]/zeta[starts-with(@string,"attribute valu")][@xml:lang="nb"][not(child::node())][following-sibling::epsilon[@token][@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]//mu[starts-with(concat(@insert,"-"),"123456789-")][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>1</nth> + </result> + <tree> + <sigma token="this.nodeValue"> + <any> + <any xml:lang="no-nb" xml:id="id1"/> + <tau attrib="100%" xml:id="id2"> + <any and="solid 1px green"/> + <omega xml:id="id3"/> + <lambda class="this-is-att-value" xml:lang="en-US"/> + <omicron true="attribute" xml:lang="en-US" xml:id="id4"> + <alpha xml:lang="no" xml:id="id5"/> + <beta xml:id="id6"/> + <rho/> + <upsilon attr="false" xml:lang="en-GB" xml:id="id7"/> + <rho xml:lang="en-US"/> + <zeta/> + <nu desciption="false" xml:lang="en"/> + <sigma xml:lang="en-GB" xml:id="id8"> + <zeta string="attribute value" xml:lang="nb"/> + <epsilon token="content" xml:lang="en-US" xml:id="id9"> + <mu insert="123456789"> + <green>This text must be green</green> + </mu> + </epsilon> + </sigma> + </omicron> + </tau> + </any> + </sigma> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]/xi[starts-with(concat(@content,"-"),"123456789-")][following-sibling::rho[@insert][@xml:lang="no"][not(following-sibling::*)]//*[@content][@xml:lang="no-nb"][@xml:id="id2"]/iota[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::pi[@xml:id="id3"][not(child::node())][following-sibling::eta[@xml:lang="en"][not(following-sibling::*)][not(preceding-sibling::eta)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <xi content="123456789"/> + <rho insert="100%" xml:lang="no"> + <any content="attribute value" xml:lang="no-nb" xml:id="id2"> + <iota/> + <pi xml:id="id3"/> + <eta xml:lang="en"> + <green>This text must be green</green> + </eta> + </any> + </rho> + </alpha> + </tree> + </test> + <test> + <xpath>//phi[@xml:id="id1"]//psi[contains(concat(@true,"$"),"en$")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[@src="content"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//tau[contains(@name,"23")][not(following-sibling::*)]/chi[@xml:lang="nb"][@xml:id="id4"][following-sibling::eta[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[starts-with(@object,"this-is-")][@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::delta[contains(concat(@number,"$"),"reen$")][@xml:lang="no"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::sigma[starts-with(@insert,"1")][@xml:id="id6"][not(following-sibling::*)]//chi[@att][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@number][@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]//theta[@string][@xml:lang="en"][not(preceding-sibling::*)]//kappa[not(preceding-sibling::*)][not(following-sibling::*)]//xi[contains(concat(@data,"$"),"ue$")][@xml:lang="no"][not(following-sibling::*)]//pi[@attr][not(following-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:id="id1"> + <psi true="solid 1px green" xml:id="id2"/> + <omega xml:lang="en-US"/> + <chi src="content" xml:id="id3"> + <tau name="123456789"> + <chi xml:lang="nb" xml:id="id4"/> + <eta xml:lang="no"/> + <phi object="this-is-att-value" xml:lang="en" xml:id="id5"/> + <delta number="solid 1px green" xml:lang="no"/> + <sigma insert="100%" xml:id="id6"> + <chi att="123456789"/> + <eta number="attribute-value" xml:lang="en-GB" xml:id="id7"> + <theta string="123456789" xml:lang="en"> + <kappa> + <xi data="this.nodeValue" xml:lang="no"> + <pi attr="100%"> + <green>This text must be green</green> + </pi> + </xi> + </kappa> + </theta> + </eta> + </sigma> + </tau> + </chi> + </phi> + </tree> + </test> + <test> + <xpath>//epsilon[@or][@xml:lang="en"][@xml:id="id1"]/rho[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/tau[@attrib][@xml:id="id3"]/xi[not(preceding-sibling::*)][not(child::node())][following-sibling::chi[contains(concat(@number,"$"),"true$")][@xml:lang="nb"][following-sibling::nu[contains(@name,"ue")][@xml:lang="en-US"]//lambda[@xml:lang="en"]//omicron[not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//upsilon[@xml:lang="en-GB"][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 2]][following-sibling::iota[@xml:id="id5"][not(following-sibling::*)]/omega[@xml:lang="nb"][not(preceding-sibling::*)]//alpha[@xml:id="id6"][not(following-sibling::*)]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon or="attribute value" xml:lang="en" xml:id="id1"> + <rho xml:lang="en-US" xml:id="id2"> + <tau attrib="attribute" xml:id="id3"> + <xi/> + <chi number="true" xml:lang="nb"/> + <nu name="attribute value" xml:lang="en-US"> + <lambda xml:lang="en"> + <omicron/> + <phi xml:lang="no-nb"> + <upsilon xml:lang="en-GB"/> + <chi xml:lang="no" xml:id="id4"/> + <kappa/> + <iota xml:id="id5"> + <omega xml:lang="nb"> + <alpha xml:id="id6"> + <green>This text must be green</green> + </alpha> + </omega> + </iota> + </phi> + </lambda> + </nu> + </tau> + </rho> + </epsilon> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="no"]/theta[@attribute][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@token,"$"),"t-value$")][not(following-sibling::*)]//gamma[starts-with(@delete,"solid 1px")][@xml:id="id1"]/phi[starts-with(@and,"f")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]/*[following-sibling::*[position()=7]][following-sibling::lambda[@xml:lang="en"][@xml:id="id3"][following-sibling::delta[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::lambda[@content="_blank"][@xml:lang="en-GB"][following-sibling::*[position()=4]][following-sibling::epsilon[@false][@xml:lang="en"][preceding-sibling::*[position() = 4]][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@class][not(child::node())][following-sibling::alpha[starts-with(@or,"f")]/lambda[@xml:id="id5"]/xi//gamma[starts-with(@content,"tr")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)]/lambda[starts-with(concat(@delete,"-"),"_blank-")][@xml:lang="no"][@xml:id="id7"][not(child::node())][following-sibling::*[contains(concat(@true,"$"),"ute-value$")][@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::zeta[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi//mu[starts-with(concat(@and,"-"),"false-")][@xml:lang="no-nb"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[contains(@delete,"ibute value")][@xml:lang="no-nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@class][@xml:lang="en-US"][position() = 1]]][position() = 1]]]]]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="no"> + <theta attribute="solid 1px green"/> + <sigma token="this-is-att-value"> + <gamma delete="solid 1px green" xml:id="id1"> + <phi and="false" xml:lang="no" xml:id="id2"> + <any/> + <lambda xml:lang="en" xml:id="id3"/> + <delta xml:lang="no-nb"/> + <lambda content="_blank" xml:lang="en-GB"/> + <epsilon false="attribute value" xml:lang="en"/> + <sigma xml:lang="en-US" xml:id="id4"/> + <iota class="attribute-value"/> + <alpha or="false"> + <lambda xml:id="id5"> + <xi> + <gamma content="true" xml:lang="no-nb" xml:id="id6"> + <lambda delete="_blank" xml:lang="no" xml:id="id7"/> + <any true="attribute-value" xml:id="id8"/> + <zeta xml:lang="en-US"/> + <xi> + <mu and="false" xml:lang="no-nb" xml:id="id9"/> + <epsilon delete="another attribute value" xml:lang="no-nb" xml:id="id10"/> + <alpha class="_blank" xml:lang="en-US"> + <green>This text must be green</green> + </alpha> + </xi> + </gamma> + </xi> + </lambda> + </alpha> + </phi> + </gamma> + </sigma> + </chi> + </tree> + </test> + <test> + <xpath>//zeta[@class]//sigma[not(preceding-sibling::*)]//alpha[@xml:lang="en-US"][@xml:id="id1"][not(child::node())][following-sibling::beta[contains(concat(@delete,"$"),"nt$")][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//iota[starts-with(concat(@attribute,"-"),"true-")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[starts-with(concat(@attr,"-"),"solid 1px green-")][@xml:lang="nb"]//omicron[@delete][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::gamma[preceding-sibling::*[position() = 1]]//mu[@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <zeta class="attribute-value"> + <sigma> + <alpha xml:lang="en-US" xml:id="id1"/> + <beta delete="content" xml:lang="nb" xml:id="id2"> + <iota attribute="true" xml:id="id3"/> + <alpha attr="solid 1px green" xml:lang="nb"> + <omicron delete="attribute-value" xml:lang="nb" xml:id="id4"/> + <gamma> + <mu xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </mu> + </gamma> + </alpha> + </beta> + </sigma> + </zeta> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(concat(@token,"-"),"solid 1px green-")][@xml:id="id1"]//chi[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[contains(@attr,"ibute valu")][not(following-sibling::*)]/nu[contains(@and," value")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::psi[starts-with(@delete,"fals")][@xml:lang="en-GB"]/omicron[contains(@and,"eValue")][@xml:id="id3"][not(following-sibling::*)]/chi[@xml:lang="no"]/sigma[@xml:lang="no"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::nu[not(child::node())][following-sibling::tau[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(following-sibling::tau)]//theta[@xml:lang="no"][@xml:id="id5"]/upsilon[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::nu[contains(concat(@string,"$"),"ibute$")][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::chi[contains(concat(@and,"$"),"_blank$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::beta[starts-with(@string,"another attribute ")][not(following-sibling::*)]/beta[@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::beta[@xml:id="id8"][preceding-sibling::*[position() = 1]]//eta[@xml:lang="no"][not(following-sibling::*)]/nu[not(following-sibling::*)]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <omicron token="solid 1px green" xml:id="id1"> + <chi xml:lang="en-GB" xml:id="id2"> + <chi attr="attribute value"> + <nu and="another attribute value" xml:lang="en-US"/> + <psi delete="false" xml:lang="en-GB"> + <omicron and="this.nodeValue" xml:id="id3"> + <chi xml:lang="no"> + <sigma xml:lang="no" xml:id="id4"/> + <nu/> + <tau xml:lang="en-GB"> + <theta xml:lang="no" xml:id="id5"> + <upsilon xml:lang="en-US"/> + <nu string="attribute" xml:lang="en-GB" xml:id="id6"/> + <chi and="_blank" xml:lang="nb"/> + <beta string="another attribute value"> + <beta xml:lang="no-nb" xml:id="id7"/> + <beta xml:id="id8"> + <eta xml:lang="no"> + <nu> + <green>This text must be green</green> + </nu> + </eta> + </beta> + </beta> + </theta> + </tau> + </chi> + </omicron> + </psi> + </chi> + </chi> + </omicron> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="nb"]//chi[@xml:id="id1"]//delta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[contains(concat(@data,"$"),"ttribute value$")][preceding-sibling::*[position() = 1]]/chi[not(preceding-sibling::*)]//upsilon[@attrib][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[starts-with(concat(@true,"-"),"true-")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::*[not(child::node())][following-sibling::omicron[@src][not(child::node())][following-sibling::xi[@token="content"][not(following-sibling::*)]//omicron[@title][not(following-sibling::*)]/upsilon[@title][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::mu[@xml:lang="no-nb"][not(child::node())][following-sibling::sigma[starts-with(@insert,"attribut")][not(following-sibling::*)]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="nb"> + <chi xml:id="id1"> + <delta xml:id="id2"/> + <any data="attribute value"> + <chi> + <upsilon attrib="true" xml:lang="no-nb" xml:id="id3"/> + <mu true="true" xml:id="id4"/> + <any/> + <omicron src="false"/> + <xi token="content"> + <omicron title="content"> + <upsilon title="attribute" xml:lang="en"/> + <mu xml:lang="no-nb"/> + <sigma insert="attribute"> + <green>This text must be green</green> + </sigma> + </omicron> + </xi> + </chi> + </any> + </chi> + </omega> + </tree> + </test> + <test> + <xpath>//omicron[contains(@false,"k")][@xml:lang="en-US"]/pi[starts-with(concat(@token,"-"),"this.nodeValue-")][@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]//tau[starts-with(@name,"fals")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 2]]//lambda[@src="another attribute value"][@xml:id="id3"][not(child::node())][following-sibling::omega[not(following-sibling::*)]//zeta[@xml:lang="nb"][not(following-sibling::*)]/beta[@string="100%"][@xml:lang="no"]/omicron[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][not(following-sibling::*)]//epsilon[not(preceding-sibling::*)]/upsilon[@content][@xml:lang="en"]/gamma//sigma[contains(@attrib,"l")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omicron false="_blank" xml:lang="en-US"> + <pi token="this.nodeValue" xml:lang="no-nb" xml:id="id1"> + <tau name="false" xml:lang="en-US"/> + <sigma xml:lang="en-US"/> + <phi xml:lang="no-nb" xml:id="id2"> + <lambda src="another attribute value" xml:id="id3"/> + <omega> + <zeta xml:lang="nb"> + <beta string="100%" xml:lang="no"> + <omicron xml:lang="no-nb"/> + <tau xml:lang="no-nb"> + <epsilon> + <upsilon content="attribute" xml:lang="en"> + <gamma> + <sigma attrib="false" xml:id="id4"/> + <omicron xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </omicron> + </gamma> + </upsilon> + </epsilon> + </tau> + </beta> + </zeta> + </omega> + </phi> + </pi> + </omicron> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(concat(@class,"-"),"attribute value-")][@xml:lang="no-nb"][@xml:id="id1"]//psi[@xml:lang="en-GB"][@xml:id="id2"]/xi[@number]//lambda[@xml:id="id3"][not(following-sibling::*)]//chi[@attr][@xml:lang="no-nb"][not(following-sibling::*)]//tau[starts-with(@att,"another")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::phi[@data="solid 1px green"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::omicron[@title][@xml:lang="no-nb"][@xml:id="id6"]/beta[@desciption][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@xml:id="id7"][not(following-sibling::*)]/phi[starts-with(@name,"t")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::zeta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]]//alpha[@xml:id="id9"][not(preceding-sibling::*)]//zeta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@delete="_blank"][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@content][@xml:lang="en"][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@att="attribute-value"][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//upsilon[@xml:id="id12"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::rho[contains(concat(@string,"$"),"ank$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[starts-with(@string,"this-is-at")][not(following-sibling::*)]/zeta[@xml:lang="en"][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <gamma class="attribute value" xml:lang="no-nb" xml:id="id1"> + <psi xml:lang="en-GB" xml:id="id2"> + <xi number="this-is-att-value"> + <lambda xml:id="id3"> + <chi attr="solid 1px green" xml:lang="no-nb"> + <tau att="another attribute value" xml:lang="en-US" xml:id="id4"/> + <phi data="solid 1px green" xml:id="id5"/> + <omicron title="100%" xml:lang="no-nb" xml:id="id6"> + <beta desciption="100%"> + <nu xml:id="id7"> + <phi name="true" xml:lang="no-nb"/> + <zeta xml:lang="no-nb"/> + <upsilon xml:lang="en-GB" xml:id="id8"> + <alpha xml:id="id9"> + <zeta xml:lang="no-nb"> + <kappa delete="_blank" xml:lang="nb" xml:id="id10"> + <tau content="content" xml:lang="en"/> + <alpha xml:id="id11"/> + <gamma att="attribute-value" xml:lang="nb"> + <upsilon xml:id="id12"/> + <rho string="_blank"/> + <omega string="this-is-att-value"> + <zeta xml:lang="en"> + <green>This text must be green</green> + </zeta> + </omega> + </gamma> + </kappa> + </zeta> + </alpha> + </upsilon> + </nu> + </beta> + </omicron> + </chi> + </lambda> + </xi> + </psi> + </gamma> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en-US"]/xi[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id2"]/nu[following-sibling::iota[following-sibling::lambda[@insert="false"][@xml:id="id3"][not(child::node())][following-sibling::lambda[contains(concat(@number,"$"),"alue$")][@xml:lang="en"][not(child::node())][following-sibling::gamma[starts-with(@attr,"at")][@xml:id="id4"]//iota[@att][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma//rho[starts-with(@attr,"attribut")][@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@title][@xml:id="id6"][preceding-sibling::*[position() = 1]]//xi[contains(concat(@src,"$"),"s-att-value$")][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[contains(concat(@abort,"$"),"se$")][@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 2]]/delta[@xml:lang="no"][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id9"]/theta[starts-with(concat(@attrib,"-"),"this-")][@xml:lang="en-GB"][@xml:id="id10"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="nb"][@xml:id="id11"][not(following-sibling::*)]//phi[@attr][@xml:lang="en"][@xml:id="id12"][not(preceding-sibling::*)]//lambda[@xml:lang="en-GB"][not(child::node())][following-sibling::alpha[contains(concat(@src,"$"),"00%$")][@xml:lang="en"][@xml:id="id13"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@object][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="en-US"> + <xi xml:lang="en-GB" xml:id="id1"/> + <omicron xml:lang="no" xml:id="id2"> + <nu/> + <iota/> + <lambda insert="false" xml:id="id3"/> + <lambda number="attribute value" xml:lang="en"/> + <gamma attr="attribute" xml:id="id4"> + <iota att="123456789"/> + <sigma> + <rho attr="attribute" xml:lang="en" xml:id="id5"/> + <any title="100%" xml:id="id6"> + <xi src="this-is-att-value" xml:lang="en" xml:id="id7"/> + <sigma abort="false" xml:lang="en-US"/> + <psi xml:lang="nb" xml:id="id8"> + <delta xml:lang="no"/> + <chi xml:lang="no" xml:id="id9"> + <theta attrib="this-is-att-value" xml:lang="en-GB" xml:id="id10"/> + <psi xml:lang="nb" xml:id="id11"> + <phi attr="another attribute value" xml:lang="en" xml:id="id12"> + <lambda xml:lang="en-GB"/> + <alpha src="100%" xml:lang="en" xml:id="id13"> + <pi object="attribute"> + <green>This text must be green</green> + </pi> + </alpha> + </phi> + </psi> + </chi> + </psi> + </any> + </sigma> + </gamma> + </omicron> + </omicron> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]/theta[@string][@xml:id="id2"][not(following-sibling::*)]//*[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/eta[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::eta)]//*[@object][@xml:id="id5"][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <theta string="this.nodeValue" xml:id="id2"> + <any xml:lang="nb"/> + <tau xml:lang="en" xml:id="id3"> + <eta xml:id="id4"> + <any object="attribute-value" xml:id="id5"> + <green>This text must be green</green> + </any> + </eta> + </tau> + </theta> + </sigma> + </tree> + </test> + <test> + <xpath>//kappa[starts-with(@att,"12345")]//chi[contains(@attribute,"te")][@xml:id="id1"][not(child::node())][following-sibling::*[starts-with(@content,"tru")][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[starts-with(@desciption,"att")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::mu[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@content]/zeta[starts-with(@false,"attribute-value")][@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]/beta[@att][@xml:lang="en-US"][@xml:id="id4"]/chi[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@class][not(preceding-sibling::*)][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[contains(concat(@object,"$"),"00%$")][@xml:lang="en-GB"][@xml:id="id7"]//alpha[@xml:lang="no-nb"][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::rho[starts-with(concat(@and,"-"),"true-")][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <kappa att="123456789"> + <chi attribute="attribute" xml:id="id1"/> + <any content="true" xml:lang="nb" xml:id="id2"> + <iota desciption="attribute-value" xml:lang="nb"/> + <mu> + <alpha content="another attribute value"> + <zeta false="attribute-value" xml:lang="no" xml:id="id3"> + <beta att="solid 1px green" xml:lang="en-US" xml:id="id4"> + <chi xml:lang="no-nb" xml:id="id5"> + <rho class="123456789"/> + <epsilon xml:lang="en-US" xml:id="id6"> + <tau object="100%" xml:lang="en-GB" xml:id="id7"> + <alpha xml:lang="no-nb" xml:id="id8"/> + <rho and="true" xml:id="id9"> + <green>This text must be green</green> + </rho> + </tau> + </epsilon> + </chi> + </beta> + </zeta> + </alpha> + </mu> + </any> + </kappa> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en"][@xml:id="id1"]/mu[starts-with(@attribute,"attri")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/gamma[@content="this.nodeValue"][@xml:id="id3"][not(following-sibling::*)]/omicron[@and][not(preceding-sibling::*)]//phi[@delete][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@att="_blank"][@xml:lang="no"][preceding-sibling::*[position() = 1]]/kappa[@false="another attribute value"][@xml:id="id5"][not(preceding-sibling::*)]//zeta[@delete="attribute-value"][@xml:id="id6"][not(child::node())][following-sibling::alpha[@xml:lang="nb"][not(child::node())][following-sibling::omega[starts-with(@number,"con")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[@abort][@xml:lang="no-nb"][not(following-sibling::*)]/beta[following-sibling::upsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::pi//phi[starts-with(@false,"conten")][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::rho[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[@attribute="false"][@xml:id="id8"][following-sibling::upsilon[starts-with(@attrib,"another attrib")][following-sibling::*[position()=1]][following-sibling::zeta[@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[starts-with(@attrib,"conten")][@xml:id="id10"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en" xml:id="id1"> + <mu attribute="attribute value" xml:lang="en"/> + <psi xml:lang="no" xml:id="id2"/> + <pi xml:lang="en-US"> + <gamma content="this.nodeValue" xml:id="id3"> + <omicron and="this.nodeValue"> + <phi delete="100%" xml:id="id4"/> + <lambda att="_blank" xml:lang="no"> + <kappa false="another attribute value" xml:id="id5"> + <zeta delete="attribute-value" xml:id="id6"/> + <alpha xml:lang="nb"/> + <omega number="content" xml:lang="en-US" xml:id="id7"> + <theta abort="attribute" xml:lang="no-nb"> + <beta/> + <upsilon xml:lang="no-nb"/> + <pi> + <phi false="content"/> + <rho xml:lang="en-US"> + <omega attribute="false" xml:id="id8"/> + <upsilon attrib="another attribute value"/> + <zeta xml:id="id9"> + <theta attrib="content" xml:id="id10"> + <green>This text must be green</green> + </theta> + </zeta> + </rho> + </pi> + </theta> + </omega> + </kappa> + </lambda> + </omicron> + </gamma> + </pi> + </delta> + </tree> + </test> + <test> + <xpath>//mu[contains(@content,"his.no")][@xml:lang="nb"]/psi[contains(concat(@true,"$"),"id 1px green$")][@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(concat(@name,"$"),"odeValue$")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@object="100%"][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/omicron[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="no-nb"][not(child::node())][following-sibling::gamma[starts-with(@att,"fa")][preceding-sibling::*[position() = 3]]//phi[contains(concat(@and,"$"),"other attribute value$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[contains(@title,"2345")][@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]/beta[contains(@abort,"se")][not(preceding-sibling::*)]//epsilon[contains(concat(@attrib,"$"),"nother attribute value$")][@xml:id="id5"][not(child::node())][following-sibling::iota[@xml:lang="no"][@xml:id="id6"][following-sibling::theta[@xml:lang="en-GB"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::sigma[@object="_blank"][@xml:id="id8"][not(following-sibling::*)]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <mu content="this.nodeValue" xml:lang="nb"> + <psi true="solid 1px green" xml:lang="en" xml:id="id1"/> + <mu name="this.nodeValue"/> + <rho object="100%" xml:lang="no-nb"> + <omicron xml:lang="en-US"/> + <epsilon xml:lang="nb" xml:id="id2"/> + <lambda xml:lang="no-nb"/> + <gamma att="false"> + <phi and="another attribute value" xml:id="id3"> + <alpha title="123456789" xml:lang="en" xml:id="id4"> + <beta abort="false"> + <epsilon attrib="another attribute value" xml:id="id5"/> + <iota xml:lang="no" xml:id="id6"/> + <theta xml:lang="en-GB" xml:id="id7"/> + <sigma object="_blank" xml:id="id8"> + <green>This text must be green</green> + </sigma> + </beta> + </alpha> + </phi> + </gamma> + </rho> + </mu> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="no-nb"][@xml:id="id1"]/zeta[@delete="another attribute value"][not(preceding-sibling::*)]//mu[@xml:lang="nb"]/zeta[@xml:id="id2"][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//kappa[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(@or,"his.nodeValue")][@xml:id="id5"]//eta[@xml:id="id6"][not(child::node())][following-sibling::chi[contains(@desciption,"attri")][preceding-sibling::*[position() = 1]]//delta[@xml:lang="no"][not(preceding-sibling::*)]/phi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[starts-with(@object,"conten")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@true="false"][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>1</nth> + </result> + <tree> + <theta xml:lang="no-nb" xml:id="id1"> + <zeta delete="another attribute value"> + <mu xml:lang="nb"> + <zeta xml:id="id2"/> + <beta/> + <nu xml:id="id3"> + <kappa xml:lang="nb" xml:id="id4"/> + <kappa or="this.nodeValue" xml:id="id5"> + <eta xml:id="id6"/> + <chi desciption="attribute"> + <delta xml:lang="no"> + <phi xml:lang="en-GB"> + <alpha object="content" xml:lang="no" xml:id="id7"/> + <delta true="false" xml:lang="en-GB" xml:id="id8"> + <green>This text must be green</green> + </delta> + </phi> + </delta> + </chi> + </kappa> + </nu> + </mu> + </zeta> + </theta> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en-GB"][@xml:id="id1"]//tau[contains(concat(@token,"$"),"t-value$")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[contains(@attrib,"attribute val")][@xml:lang="en-GB"][not(following-sibling::*)]/nu[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[starts-with(@string,"f")][@xml:lang="nb"][@xml:id="id3"]/beta[@title="content"][not(following-sibling::*)]/kappa[@or][@xml:lang="en-GB"][not(following-sibling::*)]/omega[not(preceding-sibling::*)][following-sibling::kappa[@data][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[@xml:lang="en-US"][not(following-sibling::*)]/gamma[starts-with(@name,"attribute-valu")][@xml:lang="nb"][@xml:id="id5"]/nu[@src="solid 1px green"][@xml:id="id6"][not(preceding-sibling::*)]//phi[@xml:id="id7"][not(preceding-sibling::*)]//chi[@xml:lang="nb"][not(following-sibling::*)]/phi[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en-GB" xml:id="id1"> + <tau token="this-is-att-value" xml:lang="en-US"/> + <omega xml:lang="en-GB" xml:id="id2"/> + <any attrib="attribute value" xml:lang="en-GB"> + <nu xml:lang="en-US"/> + <omicron string="false" xml:lang="nb" xml:id="id3"> + <beta title="content"> + <kappa or="solid 1px green" xml:lang="en-GB"> + <omega/> + <kappa data="attribute-value" xml:lang="en-GB" xml:id="id4"> + <beta xml:lang="en"/> + <any xml:lang="en-US"> + <gamma name="attribute-value" xml:lang="nb" xml:id="id5"> + <nu src="solid 1px green" xml:id="id6"> + <phi xml:id="id7"> + <chi xml:lang="nb"> + <phi xml:lang="en" xml:id="id8"/> + <omicron xml:lang="en-US"> + <green>This text must be green</green> + </omicron> + </chi> + </phi> + </nu> + </gamma> + </any> + </kappa> + </kappa> + </beta> + </omicron> + </any> + </delta> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]/mu[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::upsilon[@and="attribute value"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[following-sibling::*[position()=1]][following-sibling::lambda[preceding-sibling::*[position() = 3]]/tau[@xml:lang="nb"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::lambda[@or="true"][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//kappa[@xml:lang="en"][@xml:id="id6"][following-sibling::*[position()=3]][following-sibling::kappa[@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::omicron[@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/rho[@delete][not(preceding-sibling::*)]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <mu xml:lang="en-GB" xml:id="id2"/> + <upsilon and="attribute value" xml:id="id3"/> + <any/> + <lambda> + <tau xml:lang="nb" xml:id="id4"/> + <lambda or="true" xml:lang="nb" xml:id="id5"> + <kappa xml:lang="en" xml:id="id6"/> + <kappa xml:lang="no-nb" xml:id="id7"/> + <omicron xml:lang="no-nb"/> + <psi> + <rho delete="this-is-att-value"> + <green>This text must be green</green> + </rho> + </psi> + </lambda> + </lambda> + </zeta> + </tree> + </test> + <test> + <xpath>//pi[contains(concat(@true,"$"),"value$")][@xml:lang="no"][@xml:id="id1"]//iota[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[not(following-sibling::*)][not(parent::*/*[position()=2])]//rho[contains(concat(@token,"$"),"ontent$")][@xml:lang="no"][following-sibling::iota[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(following-sibling::iota)]//epsilon//beta[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 1]]/delta[@xml:id="id4"][not(following-sibling::*)]/psi[@content][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)]//mu[@xml:id="id6"]/delta[not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <pi true="attribute value" xml:lang="no" xml:id="id1"> + <iota xml:lang="no-nb" xml:id="id2"/> + <gamma xml:lang="en" xml:id="id3"> + <lambda> + <rho token="content" xml:lang="no"/> + <iota xml:lang="en"> + <epsilon> + <beta xml:lang="no-nb"/> + <epsilon> + <delta xml:id="id4"> + <psi content="another attribute value" xml:lang="nb" xml:id="id5"> + <mu xml:id="id6"> + <delta> + <green>This text must be green</green> + </delta> + </mu> + </psi> + </delta> + </epsilon> + </epsilon> + </iota> + </lambda> + </gamma> + </pi> + </tree> + </test> + <test> + <xpath>//omega/*[@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::tau[@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/eta[@xml:id="id3"][following-sibling::rho[preceding-sibling::*[position() = 1]]/phi[starts-with(@abort,"this-is-att-va")][not(following-sibling::*)]/pi[@xml:id="id4"][following-sibling::kappa[starts-with(@token,"1234567")][@xml:lang="nb"][following-sibling::lambda[starts-with(@or,"_b")][@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::*[@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//alpha[@data][@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)][not(preceding-sibling::alpha)]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <any xml:id="id1"/> + <tau xml:lang="en-US" xml:id="id2"/> + <any xml:lang="en-GB"> + <eta xml:id="id3"/> + <rho> + <phi abort="this-is-att-value"> + <pi xml:id="id4"/> + <kappa token="123456789" xml:lang="nb"/> + <lambda or="_blank" xml:lang="en" xml:id="id5"/> + <any xml:lang="en-US" xml:id="id6"> + <alpha data="content" xml:lang="nb" xml:id="id7"> + <green>This text must be green</green> + </alpha> + </any> + </phi> + </rho> + </any> + </omega> + </tree> + </test> + <test> + <xpath>//beta[@xml:id="id1"]//delta[contains(@insert,"rue")][@xml:lang="en-GB"][not(child::node())][following-sibling::mu[following-sibling::upsilon/omicron[contains(concat(@content,"$"),"rue$")][@xml:lang="en-GB"][not(following-sibling::*)]//delta[starts-with(@abort,"1234")][@xml:lang="nb"]/mu[@xml:lang="en-GB"][@xml:id="id2"]//omicron[@xml:id="id3"][not(preceding-sibling::*)]/tau[@insert][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(@attribute,"ue")][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::iota[@xml:id="id6"][not(child::node())][following-sibling::kappa[@xml:lang="en"][following-sibling::omicron[not(preceding-sibling::omicron or following-sibling::omicron)][following-sibling::pi[not(following-sibling::pi)][not(child::node())][following-sibling::epsilon[@desciption][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 5]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:id="id1"> + <delta insert="true" xml:lang="en-GB"/> + <mu/> + <upsilon> + <omicron content="true" xml:lang="en-GB"> + <delta abort="123456789" xml:lang="nb"> + <mu xml:lang="en-GB" xml:id="id2"> + <omicron xml:id="id3"> + <tau insert="content" xml:id="id4"> + <rho attribute="attribute value" xml:lang="en-US" xml:id="id5"/> + <iota xml:id="id6"/> + <kappa xml:lang="en"/> + <omicron/> + <pi/> + <epsilon desciption="100%" xml:lang="en-US" xml:id="id7"> + <green>This text must be green</green> + </epsilon> + </tau> + </omicron> + </mu> + </delta> + </omicron> + </upsilon> + </beta> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@true,"-"),"123456789-")]/gamma[@insert="another attribute value"][@xml:id="id1"][following-sibling::*[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::phi[starts-with(@data,"so")][@xml:lang="no"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id4"]//mu[not(child::node())][following-sibling::upsilon[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:id="id6"][following-sibling::theta[starts-with(@and,"sol")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:id="id7"][not(child::node())][following-sibling::gamma[@xml:id="id8"][not(following-sibling::*)]//rho[starts-with(@data,"attribute")][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][not(preceding-sibling::rho)][not(child::node())][following-sibling::eta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]//upsilon[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::*[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/chi[@title][following-sibling::gamma[@xml:lang="no"][following-sibling::rho[contains(@name,"his.nodeVal")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[contains(concat(@or,"$"),"k$")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::iota[@attrib="false"][@xml:id="id11"][not(following-sibling::*)]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <delta true="123456789"> + <gamma insert="another attribute value" xml:id="id1"/> + <any xml:lang="nb" xml:id="id2"/> + <phi data="solid 1px green" xml:lang="no" xml:id="id3"/> + <epsilon xml:lang="en-GB"/> + <tau xml:lang="no-nb" xml:id="id4"> + <mu/> + <upsilon xml:lang="no" xml:id="id5"> + <mu xml:id="id6"/> + <theta and="solid 1px green" xml:lang="en-US"/> + <theta xml:id="id7"/> + <gamma xml:id="id8"> + <rho data="attribute value" xml:lang="en" xml:id="id9"/> + <eta xml:lang="en-US"> + <upsilon xml:lang="en"/> + <any/> + <xi xml:lang="nb" xml:id="id10"> + <chi title="100%"/> + <gamma xml:lang="no"/> + <rho name="this.nodeValue"/> + <theta or="_blank"/> + <iota attrib="false" xml:id="id11"> + <green>This text must be green</green> + </iota> + </xi> + </eta> + </gamma> + </upsilon> + </tau> + </delta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="nb"][@xml:id="id1"]//beta[contains(concat(@true,"$"),"value$")][@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]/lambda[starts-with(concat(@delete,"-"),"attribute-")][@xml:id="id3"][following-sibling::*[position()=2]][following-sibling::eta[@content][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::theta[not(following-sibling::*)]//kappa[not(child::node())][following-sibling::gamma[starts-with(@src,"_")][not(following-sibling::*)]//delta[contains(@or,"att-")][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[@number][@xml:lang="nb"][@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[not(following-sibling::*)]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="nb" xml:id="id1"> + <beta true="this-is-att-value" xml:lang="en" xml:id="id2"> + <lambda delete="attribute" xml:id="id3"/> + <eta content="100%"/> + <theta> + <kappa/> + <gamma src="_blank"> + <delta or="this-is-att-value" xml:id="id4"/> + <zeta number="solid 1px green" xml:lang="nb" xml:id="id5"/> + <chi> + <green>This text must be green</green> + </chi> + </gamma> + </theta> + </beta> + </sigma> + </tree> + </test> + <test> + <xpath>//omega[starts-with(concat(@delete,"-"),"false-")]/iota[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[starts-with(concat(@delete,"-"),"false-")][@xml:id="id1"][not(preceding-sibling::epsilon)]//phi[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[contains(concat(@and,"$"),"tribute-value$")]//zeta[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:lang="en-GB"][not(preceding-sibling::*)]/rho[@xml:lang="en-US"][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@att][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:lang="no"]/*[@attrib="this-is-att-value"][not(following-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega delete="false"> + <iota xml:lang="nb"/> + <epsilon delete="false" xml:id="id1"> + <phi xml:id="id2"/> + <nu xml:lang="nb"> + <phi and="attribute-value"> + <zeta xml:lang="no" xml:id="id3"> + <psi xml:lang="en-GB"> + <rho xml:lang="en-US"/> + <gamma> + <psi att="true" xml:id="id4"> + <eta xml:lang="no"> + <any attrib="this-is-att-value"> + <green>This text must be green</green> + </any> + </eta> + </psi> + </gamma> + </psi> + </zeta> + </phi> + </nu> + </epsilon> + </omega> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no"]//tau[starts-with(@class,"attri")][@xml:id="id1"]/pi[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[starts-with(@name,"anothe")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/upsilon[contains(concat(@number,"$"),"ute value$")][@xml:id="id3"][not(preceding-sibling::*)]//*[starts-with(concat(@or,"-"),"this-")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]//upsilon[starts-with(concat(@attr,"-"),"this-")][@xml:id="id5"]//tau[@xml:id="id6"][not(preceding-sibling::*)]/delta[contains(@name,"ue")][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::gamma[starts-with(concat(@number,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::tau[@xml:lang="en-US"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/nu[@class][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[contains(concat(@data,"$"),"rue$")][@xml:lang="nb"][@xml:id="id10"][following-sibling::upsilon[contains(@object,"%")][@xml:id="id11"][not(following-sibling::*)]/nu[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::lambda[@data][not(child::node())][following-sibling::tau[@data="another attribute value"][@xml:id="id12"][not(following-sibling::*)]//nu[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:id="id13"]//beta[starts-with(concat(@class,"-"),"123456789-")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="no-nb"][@xml:id="id14"]//eta[contains(concat(@delete,"$"),"n$")][@xml:id="id15"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[starts-with(concat(@or,"-"),"_blank-")][not(preceding-sibling::*)]/theta[@xml:id="id16"][not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no"> + <tau class="attribute-value" xml:id="id1"> + <pi xml:lang="en"> + <sigma name="another attribute value" xml:lang="en-US" xml:id="id2"> + <upsilon number="attribute value" xml:id="id3"> + <any or="this-is-att-value" xml:lang="no-nb" xml:id="id4"> + <upsilon attr="this-is-att-value" xml:id="id5"> + <tau xml:id="id6"> + <delta name="true" xml:id="id7"/> + <gamma number="attribute" xml:lang="en-GB" xml:id="id8"/> + <tau xml:lang="en-US" xml:id="id9"> + <nu class="another attribute value" xml:lang="no"> + <kappa data="true" xml:lang="nb" xml:id="id10"/> + <upsilon object="100%" xml:id="id11"> + <nu xml:lang="no-nb"/> + <lambda data="solid 1px green"/> + <tau data="another attribute value" xml:id="id12"> + <nu content="this.nodeValue" xml:id="id13"> + <beta class="123456789" xml:lang="nb"/> + <iota xml:lang="no-nb" xml:id="id14"> + <eta delete="solid 1px green" xml:id="id15"> + <omicron or="_blank"> + <theta xml:id="id16"> + <green>This text must be green</green> + </theta> + </omicron> + </eta> + </iota> + </nu> + </tau> + </upsilon> + </nu> + </tau> + </tau> + </upsilon> + </any> + </upsilon> + </sigma> + </pi> + </tau> + </beta> + </tree> + </test> + <test> + <xpath>//rho[@true="attribute"][@xml:lang="en-GB"]//phi[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/phi[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@true][@xml:id="id3"][not(following-sibling::*)]/gamma[starts-with(concat(@delete,"-"),"123456789-")][not(preceding-sibling::*)][not(following-sibling::*)]/*[contains(@attribute,"lan")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:id="id5"]/alpha//tau[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[contains(@data,"te value")][@xml:lang="no-nb"][@xml:id="id7"][following-sibling::*[position()=3]][following-sibling::upsilon[starts-with(@abort,"attri")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][@xml:id="id8"][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@xml:id="id9"]//tau[starts-with(concat(@true,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)]/lambda[@class][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="no"][@xml:id="id13"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <rho true="attribute" xml:lang="en-GB"> + <phi xml:lang="nb" xml:id="id1"/> + <phi xml:lang="no-nb" xml:id="id2"> + <phi xml:lang="no"/> + <phi true="false" xml:id="id3"> + <gamma delete="123456789"> + <any attribute="_blank" xml:lang="en" xml:id="id4"/> + <lambda xml:id="id5"> + <alpha> + <tau xml:lang="en-GB" xml:id="id6"> + <iota data="another attribute value" xml:lang="no-nb" xml:id="id7"/> + <upsilon abort="attribute"/> + <epsilon xml:lang="en-GB" xml:id="id8"/> + <xi xml:id="id9"> + <tau true="this.nodeValue" xml:lang="en" xml:id="id10"> + <lambda class="this-is-att-value" xml:id="id11"> + <chi xml:id="id12"> + <zeta xml:lang="no" xml:id="id13"> + <green>This text must be green</green> + </zeta> + </chi> + </lambda> + </tau> + </xi> + </tau> + </alpha> + </lambda> + </gamma> + </phi> + </phi> + </rho> + </tree> + </test> + <test> + <xpath>//lambda[contains(@att,"ute val")][@xml:id="id1"]/kappa[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@class][@xml:lang="nb"][not(child::node())][following-sibling::omega//iota[contains(concat(@insert,"$"),"is-att-value$")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[not(preceding-sibling::*)][not(preceding-sibling::omega)][following-sibling::epsilon[starts-with(@content,"attribute")]/delta[@xml:id="id3"][not(preceding-sibling::*)]//zeta[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::nu[starts-with(@attribute,"solid 1px gr")]/omega[@xml:id="id5"][not(preceding-sibling::*)]/upsilon[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[contains(@and,"on")][@xml:id="id7"]//phi[starts-with(@or,"10")][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[@attrib][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="no"][following-sibling::rho[@xml:lang="no"][@xml:id="id9"]//tau[@xml:id="id10"][not(following-sibling::*)]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <lambda att="another attribute value" xml:id="id1"> + <kappa xml:id="id2"/> + <rho class="attribute-value" xml:lang="nb"/> + <omega> + <iota insert="this-is-att-value" xml:lang="en"> + <omega/> + <epsilon content="attribute value"> + <delta xml:id="id3"> + <zeta xml:id="id4"/> + <nu attribute="solid 1px green"> + <omega xml:id="id5"> + <upsilon xml:id="id6"/> + <upsilon and="content" xml:id="id7"> + <phi or="100%"> + <zeta attrib="solid 1px green" xml:id="id8"/> + <lambda xml:lang="no"/> + <rho xml:lang="no" xml:id="id9"> + <tau xml:id="id10"> + <green>This text must be green</green> + </tau> + </rho> + </phi> + </upsilon> + </omega> + </nu> + </delta> + </epsilon> + </iota> + </omega> + </lambda> + </tree> + </test> + <test> + <xpath>//psi[starts-with(@and,"attr")][@xml:lang="no-nb"][@xml:id="id1"]/lambda[not(following-sibling::*)]//theta[@xml:lang="no-nb"][not(preceding-sibling::*)]//iota[@xml:id="id2"][not(child::node())][following-sibling::nu[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@content][@xml:lang="en"][@xml:id="id3"]/phi[@xml:lang="en"][@xml:id="id4"][not(child::node())][following-sibling::pi[@attribute][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//gamma[@xml:lang="en-US"][@xml:id="id6"][following-sibling::mu/*[contains(@title,"this.nodeVal")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[contains(@false,"89")][not(child::node())][following-sibling::delta[contains(concat(@title,"$"),"value$")][@xml:lang="en-US"][not(following-sibling::*)]//lambda[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::rho[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/alpha[starts-with(@class,"this-is-att-va")][@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <psi and="attribute value" xml:lang="no-nb" xml:id="id1"> + <lambda> + <theta xml:lang="no-nb"> + <iota xml:id="id2"/> + <nu xml:lang="no"/> + <sigma content="this-is-att-value" xml:lang="en" xml:id="id3"> + <phi xml:lang="en" xml:id="id4"/> + <pi attribute="solid 1px green" xml:lang="en-US" xml:id="id5"> + <gamma xml:lang="en-US" xml:id="id6"/> + <mu> + <any title="this.nodeValue" xml:lang="en"> + <psi false="123456789"/> + <delta title="attribute-value" xml:lang="en-US"> + <lambda xml:lang="no"/> + <chi xml:lang="nb" xml:id="id7"/> + <rho xml:lang="en-GB"> + <alpha class="this-is-att-value" xml:lang="en-GB" xml:id="id8"> + <green>This text must be green</green> + </alpha> + </rho> + </delta> + </any> + </mu> + </pi> + </sigma> + </theta> + </lambda> + </psi> + </tree> + </test> + <test> + <xpath>//gamma/upsilon[@att][@xml:lang="en"][following-sibling::theta[@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]/xi[starts-with(@src,"attribute va")][not(preceding-sibling::*)][following-sibling::*[position()=7]][following-sibling::phi[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=6]][following-sibling::lambda[@xml:lang="en"][following-sibling::theta[@or][@xml:id="id2"][following-sibling::upsilon[@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::tau[@xml:lang="en"][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[@string="false"][preceding-sibling::*[position() = 6]][following-sibling::alpha[@number][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <gamma> + <upsilon att="123456789" xml:lang="en"/> + <theta xml:lang="nb" xml:id="id1"> + <xi src="attribute value"/> + <phi xml:lang="nb"/> + <lambda xml:lang="en"/> + <theta or="true" xml:id="id2"/> + <upsilon xml:id="id3"/> + <tau xml:lang="en"/> + <tau string="false"/> + <alpha number="this-is-att-value"> + <green>This text must be green</green> + </alpha> + </theta> + </gamma> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="nb"][@xml:id="id1"]/sigma[@title][not(following-sibling::*)]/theta[contains(@data,"23")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::tau[@true="attribute value"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@xml:lang="en-US"][@xml:id="id4"][following-sibling::chi[preceding-sibling::*[position() = 1]]/rho[@xml:lang="en"]//rho[@desciption]/theta[@or="123456789"][@xml:lang="en-US"][not(following-sibling::*)]/theta[@title][@xml:lang="en-GB"][not(preceding-sibling::*)]//phi[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[not(child::node())][following-sibling::rho[@xml:lang="nb"][preceding-sibling::*[position() = 2]]//xi[@xml:id="id6"][not(child::node())][following-sibling::sigma[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="nb" xml:id="id1"> + <sigma title="100%"> + <theta data="123456789" xml:id="id2"/> + <tau true="attribute value" xml:id="id3"> + <chi xml:lang="en-US" xml:id="id4"/> + <chi> + <rho xml:lang="en"> + <rho desciption="attribute"> + <theta or="123456789" xml:lang="en-US"> + <theta title="_blank" xml:lang="en-GB"> + <phi xml:id="id5"/> + <omicron/> + <rho xml:lang="nb"> + <xi xml:id="id6"/> + <sigma xml:id="id7"> + <green>This text must be green</green> + </sigma> + </rho> + </theta> + </theta> + </rho> + </rho> + </chi> + </tau> + </sigma> + </nu> + </tree> + </test> + <test> + <xpath>//psi[starts-with(concat(@token,"-"),"solid 1px green-")]/nu[contains(concat(@true,"$"),"ue$")]/lambda[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::eta[contains(@true,"bla")]/*[contains(concat(@data,"$"),"789$")][@xml:id="id1"][not(preceding-sibling::*)]/delta[following-sibling::sigma[@xml:lang="nb"][following-sibling::*[position()=3]][following-sibling::*[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::nu[@xml:id="id2"][not(child::node())][following-sibling::lambda[contains(concat(@src,"$"),"tent$")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//gamma[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[starts-with(@data,"t")][@xml:lang="en-US"]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <psi token="solid 1px green"> + <nu true="attribute value"> + <lambda xml:lang="en-US"/> + <eta true="_blank"> + <any data="123456789" xml:id="id1"> + <delta/> + <sigma xml:lang="nb"/> + <any xml:lang="en"/> + <nu xml:id="id2"/> + <lambda src="content" xml:lang="no-nb" xml:id="id3"> + <gamma xml:id="id4"/> + <sigma data="this-is-att-value" xml:lang="en-US"> + <green>This text must be green</green> + </sigma> + </lambda> + </any> + </eta> + </nu> + </psi> + </tree> + </test> + <test> + <xpath>//rho[@number][@xml:id="id1"]//nu[@class][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::omicron[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]//beta[@number][not(child::node())][following-sibling::rho[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[@class][@xml:lang="no-nb"][@xml:id="id5"][following-sibling::omicron[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 3]]/chi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::beta[@true="_blank"][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]]/iota[contains(@attribute,"56789")][@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::delta[starts-with(@title,"at")][@xml:lang="no"][@xml:id="id9"][not(child::node())][following-sibling::alpha[@xml:id="id10"]//delta[@xml:id="id11"][not(following-sibling::*)]/gamma[contains(concat(@delete,"$"),"alse$")]/gamma[@true][@xml:lang="no-nb"][@xml:id="id12"][not(preceding-sibling::*)][following-sibling::beta[@and][@xml:id="id13"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[starts-with(@insert,"tr")][not(following-sibling::*)]//iota[@xml:lang="no"]//eta[@xml:lang="en"][not(following-sibling::*)]/rho[@xml:lang="en"][@xml:id="id14"][not(following-sibling::*)]/nu[starts-with(@name,"another attribute valu")][@xml:lang="nb"][@xml:id="id15"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id16"][not(following-sibling::*)]//kappa[@xml:lang="no-nb"][@xml:id="id17"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <rho number="solid 1px green" xml:id="id1"> + <nu class="false" xml:lang="no" xml:id="id2"/> + <omicron xml:id="id3"> + <rho xml:lang="en" xml:id="id4"> + <beta number="solid 1px green"/> + <rho xml:lang="en"/> + <lambda class="content" xml:lang="no-nb" xml:id="id5"/> + <omicron xml:lang="no" xml:id="id6"> + <chi xml:lang="no"/> + <beta true="_blank" xml:lang="en" xml:id="id7"> + <iota attribute="123456789" xml:lang="en-GB" xml:id="id8"/> + <delta title="attribute" xml:lang="no" xml:id="id9"/> + <alpha xml:id="id10"> + <delta xml:id="id11"> + <gamma delete="false"> + <gamma true="attribute value" xml:lang="no-nb" xml:id="id12"/> + <beta and="123456789" xml:id="id13"> + <theta insert="true"> + <iota xml:lang="no"> + <eta xml:lang="en"> + <rho xml:lang="en" xml:id="id14"> + <nu name="another attribute value" xml:lang="nb" xml:id="id15"/> + <sigma xml:lang="en-US" xml:id="id16"> + <kappa xml:lang="no-nb" xml:id="id17"> + <green>This text must be green</green> + </kappa> + </sigma> + </rho> + </eta> + </iota> + </theta> + </beta> + </gamma> + </delta> + </alpha> + </beta> + </omicron> + </rho> + </omicron> + </rho> + </tree> + </test> + <test> + <xpath>//theta[starts-with(concat(@delete,"-"),"content-")]/pi[@attribute][@xml:lang="en"][not(child::node())][following-sibling::delta[following-sibling::*[contains(@data,"e")][not(child::node())][following-sibling::alpha[@xml:id="id1"]//gamma[@xml:lang="no-nb"][following-sibling::rho[@title][preceding-sibling::*[position() = 1]]/delta[@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]//rho[@insert][@xml:id="id3"]/theta[@desciption][@xml:id="id4"][not(following-sibling::*)]//delta[@att="_blank"][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)]/psi[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@false][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]//xi[@xml:lang="en-GB"][following-sibling::omicron[@token][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]]//chi[not(preceding-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <theta delete="content"> + <pi attribute="content" xml:lang="en"/> + <delta/> + <any data="false"/> + <alpha xml:id="id1"> + <gamma xml:lang="no-nb"/> + <rho title="content"> + <delta xml:lang="no-nb" xml:id="id2"> + <rho insert="attribute value" xml:id="id3"> + <theta desciption="this.nodeValue" xml:id="id4"> + <delta att="_blank" xml:lang="en-US" xml:id="id5"> + <psi xml:lang="en" xml:id="id6"/> + <any false="this.nodeValue"/> + <phi xml:lang="en-US"> + <xi xml:lang="en-GB"/> + <omicron token="false" xml:lang="en" xml:id="id7"> + <chi> + <green>This text must be green</green> + </chi> + </omicron> + </phi> + </delta> + </theta> + </rho> + </delta> + </rho> + </alpha> + </theta> + </tree> + </test> + <test> + <xpath>//alpha//gamma[contains(@string,"nk")][not(preceding-sibling::*)]/lambda[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau//iota[following-sibling::tau[not(child::node())][following-sibling::psi[@xml:lang="en-GB"][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <alpha> + <gamma string="_blank"> + <lambda xml:lang="en" xml:id="id1"/> + <tau> + <iota/> + <tau/> + <psi xml:lang="en-GB"> + <green>This text must be green</green> + </psi> + </tau> + </gamma> + </alpha> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="no-nb"]/lambda[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::gamma[@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::tau[not(following-sibling::*)]/omicron[@object][following-sibling::theta[@and="_blank"][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[starts-with(@token,"anot")][@xml:lang="en"][@xml:id="id3"][following-sibling::eta[@xml:id="id4"][following-sibling::*[position()=1]][not(preceding-sibling::eta)][not(child::node())][following-sibling::gamma[not(following-sibling::*)]//*[starts-with(concat(@name,"-"),"_blank-")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id6"]/rho[contains(@content,"s.n")][@xml:lang="en"][@xml:id="id7"]/pi[@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::pi)][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="no-nb"> + <lambda/> + <gamma xml:lang="en-GB" xml:id="id1"/> + <tau> + <omicron object="solid 1px green"/> + <theta and="_blank" xml:lang="no-nb" xml:id="id2"> + <delta token="another attribute value" xml:lang="en" xml:id="id3"/> + <eta xml:id="id4"/> + <gamma> + <any name="_blank" xml:id="id5"> + <chi xml:id="id6"> + <rho content="this.nodeValue" xml:lang="en" xml:id="id7"> + <pi xml:id="id8"> + <green>This text must be green</green> + </pi> + </rho> + </chi> + </any> + </gamma> + </theta> + </tau> + </rho> + </tree> + </test> + <test> + <xpath>//xi[contains(concat(@src,"$"),"another attribute value$")][@xml:id="id1"]//eta[contains(concat(@and,"$"),"e$")]//nu[@true][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[@att][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[starts-with(concat(@abort,"-"),"attribute value-")][@xml:id="id3"][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <xi src="another attribute value" xml:id="id1"> + <eta and="true"> + <nu true="_blank" xml:lang="no" xml:id="id2"/> + <gamma> + <rho att="false" xml:lang="en-US"> + <phi abort="attribute value" xml:id="id3"> + <green>This text must be green</green> + </phi> + </rho> + </gamma> + </eta> + </xi> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]//*[starts-with(concat(@insert,"-"),"solid 1px green-")][@xml:id="id2"][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[starts-with(@token,"12345")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@class]/psi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::upsilon[starts-with(@src,"a")][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/pi[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::sigma[@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::gamma[starts-with(concat(@att,"-"),"content-")][@xml:lang="en-US"][@xml:id="id7"]/omega[starts-with(@attribute,"attribute-val")][@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]//gamma[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@and][@xml:lang="nb"][not(following-sibling::*)]/lambda[contains(@desciption,"la")][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu//rho[@xml:lang="en-US"][@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@insert][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[starts-with(@number,"_blan")][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[starts-with(@insert,"attri")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/iota[starts-with(concat(@class,"-"),"false-")][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <any insert="solid 1px green" xml:id="id2"/> + <chi> + <delta token="123456789" xml:lang="en-US"> + <sigma class="solid 1px green"> + <psi xml:lang="no"/> + <upsilon src="attribute" xml:lang="en-US" xml:id="id3"> + <pi xml:lang="no" xml:id="id4"/> + <sigma xml:lang="nb" xml:id="id5"/> + <tau xml:lang="en-GB" xml:id="id6"/> + <gamma att="content" xml:lang="en-US" xml:id="id7"> + <omega attribute="attribute-value" xml:lang="no" xml:id="id8"> + <gamma xml:id="id9"> + <sigma/> + <pi and="attribute value" xml:lang="nb"> + <lambda desciption="_blank" xml:lang="no"/> + <mu> + <rho xml:lang="en-US" xml:id="id10"/> + <iota insert="_blank"> + <psi number="_blank"/> + <alpha insert="attribute-value" xml:lang="en-US"> + <iota class="false"> + <green>This text must be green</green> + </iota> + </alpha> + </iota> + </mu> + </pi> + </gamma> + </omega> + </gamma> + </upsilon> + </sigma> + </delta> + </chi> + </rho> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-US"][@xml:id="id1"]//iota[@xml:id="id2"][not(following-sibling::*)]/theta[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id4"][not(child::node())][following-sibling::upsilon[@object][@xml:lang="nb"][@xml:id="id5"][following-sibling::psi[contains(concat(@src,"$"),"tribute$")][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 4]][not(following-sibling::*)]/psi[@content][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@att][@xml:id="id7"][not(following-sibling::*)]/phi[@xml:lang="en"][following-sibling::*[position()=1]][not(preceding-sibling::phi or following-sibling::phi)][not(child::node())][following-sibling::omega[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/zeta[@xml:id="id8"][following-sibling::nu[@xml:lang="en"][@xml:id="id9"]/omicron[contains(concat(@string,"$"),"alue$")]/lambda[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="no"][@xml:id="id10"][not(following-sibling::*)]/eta[starts-with(@number,"cont")][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[@xml:id="id12"][not(preceding-sibling::*)][following-sibling::beta[starts-with(concat(@attribute,"-"),"123456789-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@attribute="this-is-att-value"][@xml:lang="en-US"][@xml:id="id13"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-US" xml:id="id1"> + <iota xml:id="id2"> + <theta xml:id="id3"/> + <beta xml:id="id4"/> + <upsilon object="true" xml:lang="nb" xml:id="id5"/> + <psi src="attribute" xml:lang="no-nb" xml:id="id6"/> + <rho> + <psi content="attribute-value"/> + <eta att="content" xml:id="id7"> + <phi xml:lang="en"/> + <omega xml:lang="en-US"> + <zeta xml:id="id8"/> + <nu xml:lang="en" xml:id="id9"> + <omicron string="this.nodeValue"> + <lambda xml:lang="en-US"/> + <xi xml:lang="no" xml:id="id10"> + <eta number="content" xml:id="id11"> + <pi xml:id="id12"/> + <beta attribute="123456789"> + <any attribute="this-is-att-value" xml:lang="en-US" xml:id="id13"> + <green>This text must be green</green> + </any> + </beta> + </eta> + </xi> + </omicron> + </nu> + </omega> + </eta> + </rho> + </iota> + </any> + </tree> + </test> + <test> + <xpath>//lambda[@desciption="false"][@xml:lang="en"]/pi[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@or][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[starts-with(concat(@name,"-"),"123456789-")][@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//sigma[@xml:id="id4"]/omega[@or="solid 1px green"][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//eta[following-sibling::iota[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[@and][@xml:id="id6"][not(child::node())][following-sibling::omicron[starts-with(concat(@attrib,"-"),"123456789-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[@xml:id="id7"][not(preceding-sibling::*)]/upsilon[@xml:lang="en-GB"][not(child::node())][following-sibling::phi[@number][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//delta[not(preceding-sibling::*)]/mu[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@and][@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@abort][@xml:id="id9"]/mu[starts-with(@or,"at")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[starts-with(@data,"attr")][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::gamma[@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::rho[@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::eta[@xml:id="id12"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/theta[starts-with(@attribute,"12")][@xml:lang="no"][not(following-sibling::*)]/eta[@string][@xml:lang="no-nb"][@xml:id="id13"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <lambda desciption="false" xml:lang="en"> + <pi xml:lang="en-US" xml:id="id1"> + <eta or="this.nodeValue" xml:id="id2"/> + <pi name="123456789" xml:lang="no" xml:id="id3"> + <sigma xml:id="id4"> + <omega or="solid 1px green" xml:lang="nb" xml:id="id5"> + <eta/> + <iota> + <rho and="another attribute value" xml:id="id6"/> + <omicron attrib="123456789"> + <upsilon xml:id="id7"> + <upsilon xml:lang="en-GB"/> + <phi number="false" xml:lang="no-nb"> + <delta> + <mu xml:lang="nb"> + <xi and="_blank" xml:lang="no-nb" xml:id="id8"/> + <tau abort="attribute" xml:id="id9"> + <mu or="attribute-value" xml:lang="no-nb"/> + <omega data="attribute-value" xml:id="id10"/> + <gamma xml:lang="en"/> + <rho xml:lang="nb" xml:id="id11"/> + <eta xml:id="id12"> + <theta attribute="123456789" xml:lang="no"> + <eta string="this.nodeValue" xml:lang="no-nb" xml:id="id13"> + <green>This text must be green</green> + </eta> + </theta> + </eta> + </tau> + </mu> + </delta> + </phi> + </upsilon> + </omicron> + </iota> + </omega> + </sigma> + </pi> + </pi> + </lambda> + </tree> + </test> + <test> + <xpath>//sigma[@token][@xml:lang="no-nb"][@xml:id="id1"]/phi[starts-with(@desciption,"th")][@xml:id="id2"][not(following-sibling::*)]/zeta[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::epsilon[contains(@and,"id 1px green")][following-sibling::chi[@xml:id="id4"]/omicron[@class][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <sigma token="solid 1px green" xml:lang="no-nb" xml:id="id1"> + <phi desciption="this.nodeValue" xml:id="id2"> + <zeta xml:lang="no" xml:id="id3"/> + <epsilon and="solid 1px green"/> + <chi xml:id="id4"> + <omicron class="another attribute value"> + <green>This text must be green</green> + </omicron> + </chi> + </phi> + </sigma> + </tree> + </test> + <test> + <xpath>//upsilon//eta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::lambda[@string="true"][@xml:lang="no-nb"][not(following-sibling::*)]/epsilon[@xml:lang="en"][@xml:id="id1"][not(following-sibling::*)]/tau[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[not(child::node())][following-sibling::chi[@xml:id="id2"][not(child::node())][following-sibling::psi[starts-with(@att,"10")][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 3]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon> + <eta xml:lang="en-US"/> + <lambda string="true" xml:lang="no-nb"> + <epsilon xml:lang="en" xml:id="id1"> + <tau xml:lang="no-nb"/> + <tau/> + <chi xml:id="id2"/> + <psi att="100%" xml:lang="no-nb" xml:id="id3"> + <green>This text must be green</green> + </psi> + </epsilon> + </lambda> + </upsilon> + </tree> + </test> + <test> + <xpath>//kappa[contains(concat(@name,"$"),"3456789$")][@xml:id="id1"]/mu[@xml:id="id2"][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[@true][@xml:lang="no"][not(child::node())][following-sibling::omega[@and][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::xi[contains(@class,"e")][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[@and="content"][@xml:lang="no"][@xml:id="id4"][following-sibling::mu[starts-with(@attr,"1234")][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/lambda[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[starts-with(concat(@number,"-"),"attribute-")][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::phi[@xml:id="id7"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::nu[@xml:lang="no"][@xml:id="id8"]//alpha[starts-with(@src,"another ")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::theta[@xml:id="id9"][not(following-sibling::*)]/zeta[@xml:id="id10"][not(preceding-sibling::*)][not(preceding-sibling::zeta)]/iota[starts-with(concat(@abort,"-"),"attribute-")][@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)]/upsilon[starts-with(@attrib,"attribute v")][@xml:id="id12"]/omicron[contains(@true,"se")][@xml:lang="en"][not(preceding-sibling::*)][position() = 1]]]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <kappa name="123456789" xml:id="id1"> + <mu xml:id="id2"/> + <beta xml:id="id3"> + <pi true="this.nodeValue" xml:lang="no"/> + <omega and="this-is-att-value"/> + <xi class="false"/> + <xi and="content" xml:lang="no" xml:id="id4"/> + <mu attr="123456789"> + <lambda xml:lang="no-nb" xml:id="id5"/> + <eta number="attribute-value" xml:id="id6"/> + <phi xml:id="id7"/> + <nu xml:lang="no" xml:id="id8"> + <alpha src="another attribute value" xml:lang="en-US"/> + <theta xml:id="id9"> + <zeta xml:id="id10"> + <iota abort="attribute" xml:lang="no-nb" xml:id="id11"> + <upsilon attrib="attribute value" xml:id="id12"> + <omicron true="false" xml:lang="en"> + <green>This text must be green</green> + </omicron> + </upsilon> + </iota> + </zeta> + </theta> + </nu> + </mu> + </beta> + </kappa> + </tree> + </test> + <test> + <xpath>//epsilon[@or]/sigma[starts-with(concat(@class,"-"),"another attribute value-")][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::rho[@xml:lang="no"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[@insert][@xml:id="id2"][following-sibling::rho[@and][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 3]]//tau[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::kappa[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//kappa[@number="attribute value"][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)]/beta[not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)]/sigma[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="en"][preceding-sibling::*[position() = 1]]/omega[@xml:lang="en-US"][not(child::node())][following-sibling::omega[@xml:id="id8"][not(following-sibling::*)]//psi[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::pi[@data="100%"][@xml:lang="en"][@xml:id="id10"]/zeta[@abort][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@insert][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(following-sibling::any)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <epsilon or="attribute"> + <sigma class="another attribute value"/> + <rho xml:lang="no" xml:id="id1"/> + <psi insert="true" xml:id="id2"/> + <rho and="_blank" xml:lang="no" xml:id="id3"> + <tau xml:lang="en-GB" xml:id="id4"/> + <kappa xml:lang="en-GB"> + <kappa number="attribute value" xml:lang="en-GB" xml:id="id5"> + <beta> + <any xml:lang="en-GB" xml:id="id6"> + <sigma xml:lang="en-US" xml:id="id7"/> + <sigma xml:lang="en"> + <omega xml:lang="en-US"/> + <omega xml:id="id8"> + <psi xml:id="id9"/> + <pi data="100%" xml:lang="en" xml:id="id10"> + <zeta abort="content" xml:id="id11"/> + <beta xml:lang="en"/> + <any insert="false"> + <green>This text must be green</green> + </any> + </pi> + </omega> + </sigma> + </any> + </beta> + </kappa> + </kappa> + </rho> + </epsilon> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en-US"][@xml:id="id1"]/chi[@attr][@xml:id="id2"]//pi[starts-with(concat(@and,"-"),"content-")]//eta[@class][@xml:id="id3"][not(child::node())][following-sibling::lambda[@attribute]/omicron[starts-with(@number,"co")][@xml:lang="en-GB"][not(following-sibling::*)]/chi[@object="another attribute value"][not(preceding-sibling::*)][following-sibling::omega[starts-with(concat(@att,"-"),"another attribute value-")][not(following-sibling::*)]/pi[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]/nu[not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en-US" xml:id="id1"> + <chi attr="false" xml:id="id2"> + <pi and="content"> + <eta class="false" xml:id="id3"/> + <lambda attribute="content"> + <omicron number="content" xml:lang="en-GB"> + <chi object="another attribute value"/> + <omega att="another attribute value"> + <pi xml:lang="no" xml:id="id4"> + <nu> + <green>This text must be green</green> + </nu> + </pi> + </omega> + </omicron> + </lambda> + </pi> + </chi> + </upsilon> + </tree> + </test> + <test> + <xpath>//mu[@class="attribute value"][@xml:lang="no-nb"]//xi[contains(concat(@name,"$"),"ibute-value$")][not(following-sibling::*)][not(parent::*/*[position()=2])]//chi[contains(concat(@token,"$"),"tribute-value$")][@xml:id="id1"]//theta[@xml:lang="en-GB"][following-sibling::eta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::gamma[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::theta[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::psi[@attrib="this-is-att-value"][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::pi[contains(concat(@name,"$"),"alse$")][@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]/sigma[contains(@attr,"%")][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::mu[starts-with(@data,"tr")][not(following-sibling::*)]//theta[@and="attribute value"]//alpha[not(preceding-sibling::*)][following-sibling::sigma[contains(@false,"value")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::mu[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::mu[@attr][@xml:id="id7"][not(following-sibling::*)]//iota[@xml:id="id8"][not(following-sibling::*)]/tau[@data="attribute value"][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)]/kappa[@attribute="false"][@xml:lang="en-GB"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::delta[@xml:id="id12"][not(following-sibling::*)]//theta[@xml:lang="no"][@xml:id="id13"][not(child::node())][following-sibling::alpha[@xml:lang="en-US"]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <mu class="attribute value" xml:lang="no-nb"> + <xi name="attribute-value"> + <chi token="attribute-value" xml:id="id1"> + <theta xml:lang="en-GB"/> + <eta xml:lang="no-nb"/> + <gamma/> + <theta xml:lang="no-nb" xml:id="id2"/> + <psi attrib="this-is-att-value" xml:lang="no-nb" xml:id="id3"/> + <pi name="false" xml:lang="no" xml:id="id4"> + <sigma attr="100%"/> + <beta xml:lang="no" xml:id="id5"/> + <mu data="true"> + <theta and="attribute value"> + <alpha/> + <sigma false="this-is-att-value" xml:lang="en-US" xml:id="id6"/> + <mu xml:lang="en-US"/> + <mu attr="123456789" xml:id="id7"> + <iota xml:id="id8"> + <tau data="attribute value" xml:lang="nb" xml:id="id9"> + <pi xml:lang="en-US" xml:id="id10"> + <kappa attribute="false" xml:lang="en-GB" xml:id="id11"/> + <delta xml:id="id12"> + <theta xml:lang="no" xml:id="id13"/> + <alpha xml:lang="en-US"> + <green>This text must be green</green> + </alpha> + </delta> + </pi> + </tau> + </iota> + </mu> + </theta> + </mu> + </pi> + </chi> + </xi> + </mu> + </tree> + </test> + <test> + <xpath>//gamma[@class]//epsilon[@attr="_blank"][not(following-sibling::*)]/beta[@attrib="solid 1px green"][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@xml:id="id3"]//iota[not(child::node())][following-sibling::upsilon[starts-with(concat(@abort,"-"),"attribute value-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@number="_blank"][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::sigma[contains(@src,"56")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[not(child::node())][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]/zeta[@xml:lang="en-US"][not(following-sibling::*)]//eta[@xml:lang="no"][following-sibling::rho[contains(@abort,"3")][@xml:lang="en-US"][@xml:id="id8"][following-sibling::xi[@xml:lang="en"]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <gamma class="content"> + <epsilon attr="_blank"> + <beta attrib="solid 1px green" xml:lang="en-US" xml:id="id1"/> + <alpha xml:id="id2"> + <pi xml:id="id3"> + <iota/> + <upsilon abort="attribute value" xml:lang="no-nb"> + <zeta number="_blank" xml:lang="en-US" xml:id="id4"> + <epsilon xml:lang="nb" xml:id="id5"/> + <sigma src="123456789" xml:lang="en-US" xml:id="id6"/> + <any/> + <tau xml:lang="no-nb" xml:id="id7"> + <zeta xml:lang="en-US"> + <eta xml:lang="no"/> + <rho abort="123456789" xml:lang="en-US" xml:id="id8"/> + <xi xml:lang="en"> + <green>This text must be green</green> + </xi> + </zeta> + </tau> + </zeta> + </upsilon> + </pi> + </alpha> + </epsilon> + </gamma> + </tree> + </test> + <test> + <xpath>//chi[@name="attribute"][@xml:lang="en-US"][@xml:id="id1"]/xi[@name][@xml:lang="en"][@xml:id="id2"]//tau[following-sibling::*[position()=2]][following-sibling::kappa[@token="solid 1px green"][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::sigma[@true][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//mu[contains(@title,"ibut")]//omega[starts-with(concat(@att,"-"),"attribute-")][@xml:id="id3"]/pi[@xml:id="id4"][not(preceding-sibling::*)]/kappa[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@and][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:id="id6"][following-sibling::theta[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]//upsilon[@xml:id="id8"][not(child::node())][following-sibling::alpha[contains(@true,"tribute valu")][@xml:lang="nb"][not(following-sibling::*)]/delta[not(following-sibling::*)]/phi[@xml:id="id9"][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@xml:lang="en-US"]/nu[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::zeta[starts-with(concat(@name,"-"),"false-")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/omega//nu[contains(@object,"a")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@attribute][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[starts-with(concat(@insert,"-"),"attribute value-")][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <chi name="attribute" xml:lang="en-US" xml:id="id1"> + <xi name="123456789" xml:lang="en" xml:id="id2"> + <tau/> + <kappa token="solid 1px green" xml:lang="no-nb"/> + <sigma true="true" xml:lang="en-US"> + <mu title="attribute"> + <omega att="attribute" xml:id="id3"> + <pi xml:id="id4"> + <kappa xml:lang="nb" xml:id="id5"/> + <phi and="100%"/> + <omega xml:id="id6"/> + <theta xml:lang="en-GB" xml:id="id7"> + <upsilon xml:id="id8"/> + <alpha true="attribute value" xml:lang="nb"> + <delta> + <phi xml:id="id9"/> + <any> + <phi xml:lang="en-US"> + <nu xml:lang="en-US"/> + <zeta name="false" xml:lang="en-US"> + <omega> + <nu object="attribute" xml:lang="no-nb"/> + <omicron attribute="solid 1px green" xml:id="id10"/> + <mu insert="attribute value"> + <green>This text must be green</green> + </mu> + </omega> + </zeta> + </phi> + </any> + </delta> + </alpha> + </theta> + </pi> + </omega> + </mu> + </sigma> + </xi> + </chi> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="no"]//xi[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[not(child::node())][following-sibling::omicron[starts-with(@title,"false")][@xml:lang="no"]/kappa[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@string][not(preceding-sibling::*)]//nu[@or][@xml:lang="nb"][@xml:id="id2"][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="no"> + <xi xml:lang="no"/> + <alpha/> + <omicron title="false" xml:lang="no"> + <kappa xml:id="id1"> + <mu string="another attribute value"> + <nu or="true" xml:lang="nb" xml:id="id2"> + <green>This text must be green</green> + </nu> + </mu> + </kappa> + </omicron> + </upsilon> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="nb"][@xml:id="id1"]/phi[starts-with(concat(@class,"-"),"false-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::omicron[@xml:lang="no-nb"][not(following-sibling::*)]/*[following-sibling::theta[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/upsilon[@object][@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="nb" xml:id="id1"> + <phi class="false" xml:lang="no-nb"> + <delta xml:lang="en" xml:id="id2"/> + <omicron xml:lang="no-nb"> + <any/> + <theta xml:lang="nb" xml:id="id3"> + <upsilon object="attribute" xml:lang="en-US"/> + <epsilon xml:lang="no-nb"> + <green>This text must be green</green> + </epsilon> + </theta> + </omicron> + </phi> + </kappa> + </tree> + </test> + <test> + <xpath>//lambda[@src]//rho[starts-with(concat(@content,"-"),"another attribute value-")][@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]/beta[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:id="id3"][not(following-sibling::*)]//theta[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/omega[@att][@xml:lang="en-GB"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::tau[@abort][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@desciption][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::theta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@token][@xml:lang="no-nb"]/kappa[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <lambda src="123456789"> + <rho content="another attribute value" xml:lang="no" xml:id="id1"> + <beta xml:lang="no-nb" xml:id="id2"> + <psi xml:id="id3"> + <theta xml:lang="en" xml:id="id4"> + <omega att="attribute" xml:lang="en-GB" xml:id="id5"/> + <tau abort="this.nodeValue" xml:id="id6"> + <any desciption="solid 1px green" xml:lang="no"/> + <theta> + <beta token="this.nodeValue" xml:lang="no-nb"> + <kappa xml:lang="en"> + <green>This text must be green</green> + </kappa> + </beta> + </theta> + </tau> + </theta> + </psi> + </beta> + </rho> + </lambda> + </tree> + </test> + <test> + <xpath>//mu[starts-with(@attrib,"true")][@xml:lang="en"]//phi[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(@src,"attribut")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]//xi[following-sibling::gamma[not(child::node())][following-sibling::iota[contains(concat(@false,"$"),"56789$")][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::lambda[@xml:id="id4"]//upsilon[@xml:lang="no-nb"][@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::iota[contains(@title,"alue")][@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@class][@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 2]]/phi[@number="this.nodeValue"][@xml:lang="nb"][@xml:id="id8"][following-sibling::omicron[@false][@xml:lang="no"][following-sibling::xi[@xml:id="id9"][not(following-sibling::*)]/xi[@xml:lang="en"][@xml:id="id10"][following-sibling::beta[starts-with(concat(@or,"-"),"solid 1px green-")][@xml:lang="no-nb"][not(child::node())][following-sibling::omega[contains(concat(@or,"$"),"1px green$")][preceding-sibling::*[position() = 2]]//phi[contains(@content,"attri")][@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::epsilon[@object][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <mu attrib="true" xml:lang="en"> + <phi xml:lang="no" xml:id="id1"> + <psi src="attribute value" xml:lang="nb" xml:id="id2"> + <xi/> + <gamma/> + <iota false="123456789" xml:lang="en" xml:id="id3"/> + <lambda xml:id="id4"> + <upsilon xml:lang="no-nb" xml:id="id5"/> + <iota title="attribute-value" xml:lang="nb" xml:id="id6"/> + <iota class="_blank" xml:lang="no" xml:id="id7"> + <phi number="this.nodeValue" xml:lang="nb" xml:id="id8"/> + <omicron false="100%" xml:lang="no"/> + <xi xml:id="id9"> + <xi xml:lang="en" xml:id="id10"/> + <beta or="solid 1px green" xml:lang="no-nb"/> + <omega or="solid 1px green"> + <phi content="another attribute value" xml:lang="no-nb" xml:id="id11"/> + <epsilon object="true" xml:lang="nb"> + <green>This text must be green</green> + </epsilon> + </omega> + </xi> + </iota> + </lambda> + </psi> + </phi> + </mu> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="no-nb"]/mu[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::mu)]//lambda[starts-with(@desciption,"att")][following-sibling::sigma[@xml:id="id1"][preceding-sibling::*[position() = 1]]/pi[@class][not(preceding-sibling::*)]/phi[@xml:lang="en-US"]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="no-nb"> + <mu xml:lang="no"> + <lambda desciption="attribute"/> + <sigma xml:id="id1"> + <pi class="123456789"> + <phi xml:lang="en-US"> + <green>This text must be green</green> + </phi> + </pi> + </sigma> + </mu> + </mu> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(@object,"12345")][@xml:lang="nb"]/phi[contains(@object,"k")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id1"][following-sibling::gamma[@attrib="attribute value"][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]/beta[@desciption="100%"][@xml:id="id3"][not(preceding-sibling::*)]/alpha[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@src]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <omicron object="123456789" xml:lang="nb"> + <phi object="_blank"/> + <omicron xml:lang="en-US" xml:id="id1"/> + <gamma attrib="attribute value" xml:lang="nb" xml:id="id2"> + <beta desciption="100%" xml:id="id3"> + <alpha xml:id="id4"> + <rho src="attribute value"> + <green>This text must be green</green> + </rho> + </alpha> + </beta> + </gamma> + </omicron> + </tree> + </test> + <test> + <xpath>//beta[contains(@attrib,"but")][@xml:id="id1"]//rho[following-sibling::*[position()=3]][following-sibling::*[@data][@xml:lang="en-GB"][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::epsilon[starts-with(concat(@att,"-"),"solid 1px green-")][@xml:id="id3"][not(following-sibling::*)]/xi[@or="123456789"][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(preceding-sibling::kappa or following-sibling::kappa)][following-sibling::pi[@abort="solid 1px green"][@xml:lang="en-GB"][following-sibling::omicron[@false="this.nodeValue"][@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="nb"][preceding-sibling::*[position() = 3]]/theta[@xml:lang="no"]/omega[@object][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@and][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@title="123456789"][not(child::node())][following-sibling::pi[@insert="100%"][@xml:id="id6"]/iota[@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)]/tau[contains(concat(@src,"$"),"tribute$")][@xml:id="id8"][following-sibling::phi[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <beta attrib="attribute" xml:id="id1"> + <rho/> + <any data="false" xml:lang="en-GB"/> + <psi xml:lang="en-GB" xml:id="id2"/> + <epsilon att="solid 1px green" xml:id="id3"> + <xi or="123456789" xml:lang="no-nb" xml:id="id4"> + <kappa xml:id="id5"/> + <pi abort="solid 1px green" xml:lang="en-GB"/> + <omicron false="this.nodeValue" xml:lang="en-GB"/> + <iota xml:lang="nb"> + <theta xml:lang="no"> + <omega object="solid 1px green" xml:lang="no"/> + <zeta> + <mu and="_blank" xml:lang="en-US"> + <omega title="123456789"/> + <pi insert="100%" xml:id="id6"> + <iota xml:lang="nb" xml:id="id7"> + <tau src="attribute" xml:id="id8"/> + <phi/> + <beta xml:lang="nb"> + <green>This text must be green</green> + </beta> + </iota> + </pi> + </mu> + </zeta> + </theta> + </iota> + </xi> + </epsilon> + </beta> + </tree> + </test> + <test> + <xpath>//omega[contains(@attr,"t")][@xml:lang="nb"]//mu[contains(concat(@src,"$"),"bute$")][not(following-sibling::*)]//epsilon[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::tau[@xml:id="id2"][not(following-sibling::*)]//gamma[@xml:lang="en-US"][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/phi[contains(concat(@att,"$"),"56789$")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::pi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::omicron[@false][@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::upsilon[starts-with(@and,"attribute-v")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]]//eta[starts-with(@false,"another attribute ")][@xml:lang="no-nb"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <omega attr="content" xml:lang="nb"> + <mu src="attribute"> + <epsilon xml:id="id1"/> + <tau xml:id="id2"> + <gamma xml:lang="en-US"/> + <tau xml:lang="en-GB" xml:id="id3"> + <phi att="123456789" xml:id="id4"/> + <pi xml:lang="no-nb"/> + <omicron false="another attribute value" xml:lang="en-US" xml:id="id5"/> + <upsilon and="attribute-value" xml:lang="en-US" xml:id="id6"> + <eta false="another attribute value" xml:lang="no-nb"> + <green>This text must be green</green> + </eta> + </upsilon> + </tau> + </tau> + </mu> + </omega> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no"]//omicron[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::iota[contains(concat(@data,"$"),"t-value$")][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@class][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//theta[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::zeta[@title][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//zeta[@att][@xml:lang="no"]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no"> + <omicron xml:id="id1"/> + <tau xml:lang="en"/> + <iota data="this-is-att-value" xml:lang="no" xml:id="id2"/> + <zeta class="true" xml:lang="no-nb"> + <theta xml:lang="no-nb"/> + <zeta title="solid 1px green" xml:lang="nb"/> + <nu xml:lang="no-nb" xml:id="id3"> + <zeta att="solid 1px green" xml:lang="no"> + <green>This text must be green</green> + </zeta> + </nu> + </zeta> + </lambda> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-US"]/zeta[@object="this-is-att-value"][@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]/sigma[starts-with(concat(@string,"-"),"another attribute value-")][following-sibling::eta[@xml:id="id2"]//alpha[starts-with(@false,"another")][@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[starts-with(concat(@desciption,"-"),"this.nodeValue-")][@xml:lang="no-nb"]/epsilon[starts-with(@true,"con")][not(child::node())][following-sibling::epsilon[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]]//alpha[starts-with(@insert,"this.nodeV")][@xml:id="id5"]//nu[contains(@attr,"67")][@xml:id="id6"][not(child::node())][following-sibling::lambda[@xml:lang="en"]//phi[not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="en-US"][@xml:id="id7"]/lambda[@xml:id="id8"]/beta[@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:lang="en"][@xml:id="id10"][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id11"][preceding-sibling::*[position() = 1]]//delta/epsilon[@insert][@xml:id="id12"]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-US"> + <zeta object="this-is-att-value" xml:lang="nb" xml:id="id1"> + <sigma string="another attribute value"/> + <eta xml:id="id2"> + <alpha false="another attribute value" xml:lang="en-GB" xml:id="id3"/> + <beta desciption="this.nodeValue" xml:lang="no-nb"> + <epsilon true="content"/> + <epsilon xml:lang="no" xml:id="id4"> + <alpha insert="this.nodeValue" xml:id="id5"> + <nu attr="123456789" xml:id="id6"/> + <lambda xml:lang="en"> + <phi> + <phi xml:lang="en-US" xml:id="id7"> + <lambda xml:id="id8"> + <beta xml:lang="nb" xml:id="id9"> + <theta xml:lang="en" xml:id="id10"/> + <epsilon xml:lang="no-nb" xml:id="id11"> + <delta> + <epsilon insert="123456789" xml:id="id12"> + <green>This text must be green</green> + </epsilon> + </delta> + </epsilon> + </beta> + </lambda> + </phi> + </phi> + </lambda> + </alpha> + </epsilon> + </beta> + </eta> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@token,"-"),"100%-")][@xml:lang="no"][@xml:id="id1"]//upsilon[contains(concat(@attr,"$"),".nodeValue$")][@xml:lang="en-US"][not(child::node())][following-sibling::alpha[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@object="attribute-value"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::pi[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 3]][following-sibling::chi[not(following-sibling::*)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <delta token="100%" xml:lang="no" xml:id="id1"> + <upsilon attr="this.nodeValue" xml:lang="en-US"/> + <alpha xml:lang="en"/> + <zeta object="attribute-value" xml:id="id2"/> + <pi xml:lang="en-GB" xml:id="id3"/> + <chi> + <green>This text must be green</green> + </chi> + </delta> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="no"]//sigma[@true]//chi[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[contains(@attrib,"e")][@xml:lang="en"][@xml:id="id2"][following-sibling::iota[contains(concat(@abort,"$"),"ibute$")][following-sibling::*[position()=1]][following-sibling::xi[contains(@and,"1")][@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="no"> + <sigma true="_blank"> + <chi xml:lang="nb" xml:id="id1"> + <kappa attrib="attribute-value" xml:lang="en" xml:id="id2"/> + <iota abort="attribute"/> + <xi and="solid 1px green" xml:lang="en-GB"> + <green>This text must be green</green> + </xi> + </chi> + </sigma> + </delta> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="no-nb"][@xml:id="id1"]/beta[starts-with(concat(@data,"-"),"attribute-")][not(preceding-sibling::*)][following-sibling::xi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[not(preceding-sibling::*)]/kappa[@xml:lang="en-US"][not(preceding-sibling::*)]/theta[not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::theta)]//chi[starts-with(concat(@number,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/iota[@data="another attribute value"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="nb"][not(child::node())][following-sibling::xi[@delete][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@content="attribute-value"][@xml:lang="nb"][preceding-sibling::*[position() = 3]]/phi[@att][@xml:id="id5"][not(preceding-sibling::*)]/chi[@xml:id="id6"][not(preceding-sibling::*)]/mu[contains(concat(@content,"$"),"e$")][@xml:lang="en-GB"][not(following-sibling::*)]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="no-nb" xml:id="id1"> + <beta data="attribute"/> + <xi> + <chi> + <kappa xml:lang="en-US"> + <theta> + <chi number="this.nodeValue" xml:lang="nb" xml:id="id2"/> + <lambda xml:lang="en-GB" xml:id="id3"> + <iota data="another attribute value" xml:id="id4"/> + <upsilon xml:lang="nb"/> + <xi delete="attribute-value"/> + <psi content="attribute-value" xml:lang="nb"> + <phi att="another attribute value" xml:id="id5"> + <chi xml:id="id6"> + <mu content="attribute-value" xml:lang="en-GB"> + <green>This text must be green</green> + </mu> + </chi> + </phi> + </psi> + </lambda> + </theta> + </kappa> + </chi> + </xi> + </eta> + </tree> + </test> + <test> + <xpath>//upsilon//iota[contains(@class,"56789")][not(child::node())][following-sibling::omicron[following-sibling::*[position()=2]][following-sibling::theta[@number][@xml:lang="en"][@xml:id="id1"][following-sibling::xi[@xml:lang="en-US"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//delta[not(following-sibling::*)]/nu[@xml:id="id2"][following-sibling::chi[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::alpha[@xml:lang="no"][@xml:id="id4"]/pi[contains(concat(@attrib,"$"),"tribute value$")][@xml:lang="en"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <upsilon> + <iota class="123456789"/> + <omicron/> + <theta number="123456789" xml:lang="en" xml:id="id1"/> + <xi xml:lang="en-US"> + <delta> + <nu xml:id="id2"/> + <chi xml:id="id3"/> + <delta xml:lang="en-GB"/> + <alpha xml:lang="no" xml:id="id4"> + <pi attrib="attribute value" xml:lang="en"> + <green>This text must be green</green> + </pi> + </alpha> + </delta> + </xi> + </upsilon> + </tree> + </test> + <test> + <xpath>//sigma[@true][@xml:id="id1"]//delta[@string][@xml:id="id2"]/omicron[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::lambda[contains(@false,"e")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]]/upsilon[contains(concat(@data,"$"),"odeValue$")][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::sigma[@object][@xml:id="id6"][following-sibling::pi[contains(@attrib,"n")][@xml:lang="nb"][@xml:id="id7"][following-sibling::theta[contains(@att,"t")][preceding-sibling::*[position() = 3]]/delta[@xml:lang="en"][@xml:id="id8"]/omega[starts-with(@string,"cont")][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@or][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <sigma true="123456789" xml:id="id1"> + <delta string="_blank" xml:id="id2"> + <omicron xml:lang="no-nb" xml:id="id3"/> + <lambda false="another attribute value" xml:lang="no" xml:id="id4"> + <upsilon data="this.nodeValue" xml:lang="en-US" xml:id="id5"/> + <sigma object="123456789" xml:id="id6"/> + <pi attrib="solid 1px green" xml:lang="nb" xml:id="id7"/> + <theta att="attribute"> + <delta xml:lang="en" xml:id="id8"> + <omega string="content"> + <kappa or="solid 1px green"> + <green>This text must be green</green> + </kappa> + </omega> + </delta> + </theta> + </lambda> + </delta> + </sigma> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]/mu[starts-with(@attribute,"this.node")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@content][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::lambda[@xml:lang="nb"][not(following-sibling::*)]/epsilon[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[starts-with(concat(@data,"-"),"100%-")][following-sibling::beta[starts-with(@insert,"100%")][@xml:id="id5"][preceding-sibling::*[position() = 2]]/omega[@attrib][not(child::node())][following-sibling::lambda[@abort][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::lambda[starts-with(@insert,"content")][@xml:lang="nb"][@xml:id="id7"][not(child::node())][following-sibling::rho/xi[not(child::node())][following-sibling::iota[@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[preceding-sibling::*[position() = 2]][following-sibling::kappa[starts-with(concat(@insert,"-"),"this.nodeValue-")][@xml:lang="en-GB"][@xml:id="id9"]//omega[@xml:lang="nb"][not(preceding-sibling::*)]/lambda[not(preceding-sibling::*)][not(following-sibling::*)]//delta[@title][@xml:lang="nb"][not(child::node())][following-sibling::pi[@xml:lang="no"][@xml:id="id10"][not(following-sibling::*)]/omega[contains(@string,"0%")][@xml:lang="no-nb"][@xml:id="id11"]//upsilon[starts-with(@false,"1")][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <mu attribute="this.nodeValue" xml:lang="nb"/> + <mu xml:lang="en-GB" xml:id="id2"/> + <eta content="content" xml:lang="en-US" xml:id="id3"/> + <lambda xml:lang="nb"> + <epsilon xml:lang="no" xml:id="id4"/> + <theta data="100%"/> + <beta insert="100%" xml:id="id5"> + <omega attrib="this.nodeValue"/> + <lambda abort="this.nodeValue" xml:id="id6"/> + <lambda insert="content" xml:lang="nb" xml:id="id7"/> + <rho> + <xi/> + <iota xml:id="id8"/> + <any/> + <kappa insert="this.nodeValue" xml:lang="en-GB" xml:id="id9"> + <omega xml:lang="nb"> + <lambda> + <delta title="true" xml:lang="nb"/> + <pi xml:lang="no" xml:id="id10"> + <omega string="100%" xml:lang="no-nb" xml:id="id11"> + <upsilon false="100%"> + <green>This text must be green</green> + </upsilon> + </omega> + </pi> + </lambda> + </omega> + </kappa> + </rho> + </beta> + </lambda> + </chi> + </tree> + </test> + <test> + <xpath>//upsilon[contains(@and,"al")][@xml:lang="nb"]/gamma[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[contains(@insert,"%")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//upsilon[not(child::node())][following-sibling::alpha[@data][not(following-sibling::*)]/pi[@xml:lang="no"][@xml:id="id2"][following-sibling::mu[contains(concat(@src,"$"),"_blank$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[contains(@att,"Value")][@xml:id="id3"][not(following-sibling::*)][not(preceding-sibling::theta or following-sibling::theta)][not(preceding-sibling::theta)]//beta[@class][@xml:lang="en-US"]//phi[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id6"]//delta[starts-with(@object,"this.nod")][@xml:lang="en-GB"][@xml:id="id7"][following-sibling::tau[preceding-sibling::*[position() = 1]][following-sibling::alpha[following-sibling::psi[@att][@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]//omega[@xml:id="id9"][not(preceding-sibling::*)]]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <upsilon and="false" xml:lang="nb"> + <gamma xml:id="id1"/> + <epsilon insert="100%"> + <upsilon/> + <alpha data="false"> + <pi xml:lang="no" xml:id="id2"/> + <mu src="_blank"> + <theta att="this.nodeValue" xml:id="id3"> + <beta class="this.nodeValue" xml:lang="en-US"> + <phi xml:id="id4"> + <mu xml:id="id5"/> + <omicron xml:lang="en-US" xml:id="id6"> + <delta object="this.nodeValue" xml:lang="en-GB" xml:id="id7"/> + <tau/> + <alpha/> + <psi att="this-is-att-value" xml:lang="en-US" xml:id="id8"> + <omega xml:id="id9"> + <green>This text must be green</green> + </omega> + </psi> + </omicron> + </phi> + </beta> + </theta> + </mu> + </alpha> + </epsilon> + </upsilon> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="en-GB"][@xml:id="id1"]//*[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::gamma[starts-with(concat(@data,"-"),"this-")][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[starts-with(concat(@src,"-"),"100%-")][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//*[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)]//mu[starts-with(concat(@src,"-"),"false-")][not(child::node())][following-sibling::delta[starts-with(@object,"_b")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@xml:id="id6"][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="en-GB" xml:id="id1"> + <any xml:lang="nb"/> + <gamma data="this-is-att-value" xml:lang="en" xml:id="id2"/> + <phi src="100%" xml:id="id3"> + <any xml:lang="en-GB" xml:id="id4"> + <mu src="false"/> + <delta object="_blank" xml:id="id5"> + <phi xml:id="id6"> + <green>This text must be green</green> + </phi> + </delta> + </any> + </phi> + </beta> + </tree> + </test> + <test> + <xpath>//omicron[contains(@src,"4")][@xml:id="id1"]/xi[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::phi[@attribute][@xml:lang="no-nb"][not(child::node())][following-sibling::beta[@att][@xml:lang="no"][not(child::node())][following-sibling::*[@attr][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 3]]//omicron[@title][@xml:lang="en-US"]//eta[@number][@xml:lang="no"]/phi[@token]/alpha[@xml:lang="nb"][@xml:id="id4"]//pi[contains(@number,"tt")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@string="true"][not(following-sibling::*)]//delta[@true][@xml:id="id6"][not(preceding-sibling::*)]//phi[contains(@object,"6789")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@src="this-is-att-value"][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <omicron src="123456789" xml:id="id1"> + <xi xml:id="id2"/> + <phi attribute="this.nodeValue" xml:lang="no-nb"/> + <beta att="false" xml:lang="no"/> + <any attr="content" xml:lang="en" xml:id="id3"> + <omicron title="false" xml:lang="en-US"> + <eta number="attribute-value" xml:lang="no"> + <phi token="100%"> + <alpha xml:lang="nb" xml:id="id4"> + <pi number="attribute" xml:id="id5"> + <theta string="true"> + <delta true="false" xml:id="id6"> + <phi object="123456789" xml:lang="en-GB"/> + <epsilon src="this-is-att-value" xml:lang="nb" xml:id="id7"> + <green>This text must be green</green> + </epsilon> + </delta> + </theta> + </pi> + </alpha> + </phi> + </eta> + </omicron> + </any> + </omicron> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no"][@xml:id="id1"]//omicron[contains(concat(@name,"$"),"tt-value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 1]]//upsilon[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[following-sibling::phi[contains(@token,"een")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/eta[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::omicron[contains(@name,"e")][@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@xml:id="id5"]/gamma[@false][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@or,"$"),"value$")][@xml:lang="en-US"][@xml:id="id7"]//omicron[@desciption][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no" xml:id="id1"> + <omicron name="this-is-att-value" xml:lang="no-nb"/> + <epsilon> + <upsilon xml:lang="en-GB" xml:id="id2"> + <phi/> + <phi token="solid 1px green" xml:lang="no-nb" xml:id="id3"> + <eta xml:lang="en"/> + <omicron name="attribute value" xml:lang="en-US" xml:id="id4"/> + <rho xml:id="id5"> + <gamma false="100%" xml:id="id6"/> + <alpha or="attribute value" xml:lang="en-US" xml:id="id7"> + <omicron desciption="attribute-value"> + <green>This text must be green</green> + </omicron> + </alpha> + </rho> + </phi> + </upsilon> + </epsilon> + </kappa> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="en-GB"][@xml:id="id1"]//pi[not(preceding-sibling::*)]/sigma[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(preceding-sibling::sigma or following-sibling::sigma)][following-sibling::phi[@false][not(following-sibling::*)]/kappa[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//*//sigma[contains(@class,"12345")][following-sibling::gamma[@xml:id="id3"][preceding-sibling::*[position() = 1]]//nu[contains(@data,"lue")][@xml:lang="no-nb"][not(preceding-sibling::*)]/psi[@or][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]//eta[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::mu[contains(@attrib,"te value")][@xml:lang="no-nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omicron[@xml:lang="nb"][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[@number][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:id="id9"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="no-nb"][@xml:id="id10"]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="en-GB" xml:id="id1"> + <pi> + <sigma xml:lang="en-US" xml:id="id2"/> + <phi false="attribute"> + <kappa xml:lang="en-US"> + <any> + <sigma class="123456789"/> + <gamma xml:id="id3"> + <nu data="this-is-att-value" xml:lang="no-nb"> + <psi or="another attribute value" xml:lang="nb" xml:id="id4"> + <eta xml:lang="no" xml:id="id5"/> + <any xml:lang="en-US" xml:id="id6"/> + <mu attrib="attribute value" xml:lang="no-nb" xml:id="id7"> + <omicron xml:lang="nb"/> + <rho number="solid 1px green" xml:id="id8"/> + <nu xml:id="id9"/> + <omicron xml:lang="no-nb" xml:id="id10"> + <green>This text must be green</green> + </omicron> + </mu> + </psi> + </nu> + </gamma> + </any> + </kappa> + </phi> + </pi> + </omicron> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="nb"][@xml:id="id1"]/psi[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::gamma[contains(concat(@token,"$"),"ttribute$")][preceding-sibling::*[position() = 1]][following-sibling::chi[@false][@xml:id="id3"]//omicron[not(child::node())][following-sibling::tau[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id4"]//upsilon[not(following-sibling::*)]/pi[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::iota[@class="attribute value"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::phi[@xml:id="id6"][preceding-sibling::*[position() = 2]]//theta[contains(concat(@src,"$"),"ttribute value$")][@xml:lang="no"][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[contains(concat(@src,"$"),"ute value$")][@xml:lang="en"][not(following-sibling::*)]/pi[starts-with(@src,"another")][@xml:lang="no-nb"][not(preceding-sibling::pi)][not(child::node())][following-sibling::epsilon[@xml:id="id8"][following-sibling::*[position()=4]][following-sibling::xi[@xml:lang="no-nb"][following-sibling::delta[@xml:lang="nb"][not(child::node())][following-sibling::kappa[@xml:id="id9"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::kappa[@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 5]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="nb" xml:id="id1"> + <psi xml:id="id2"/> + <gamma token="attribute"/> + <chi false="content" xml:id="id3"> + <omicron/> + <tau token="attribute" xml:lang="nb" xml:id="id4"> + <upsilon> + <pi xml:lang="en-GB"/> + <iota class="attribute value" xml:id="id5"/> + <phi xml:id="id6"> + <theta src="attribute value" xml:lang="no"/> + <rho xml:lang="en-GB" xml:id="id7"/> + <theta src="attribute value" xml:lang="en"> + <pi src="another attribute value" xml:lang="no-nb"/> + <epsilon xml:id="id8"/> + <xi xml:lang="no-nb"/> + <delta xml:lang="nb"/> + <kappa xml:id="id9"/> + <kappa xml:lang="en" xml:id="id10"> + <green>This text must be green</green> + </kappa> + </theta> + </phi> + </upsilon> + </tau> + </chi> + </any> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]//theta[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::kappa[contains(@class,"56789")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[starts-with(@attr,"attri")][@xml:lang="en"]//xi[contains(@att,"0%")][not(preceding-sibling::*)]/zeta[@name][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="no"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <theta xml:lang="en" xml:id="id2"/> + <kappa class="123456789"/> + <upsilon attr="attribute" xml:lang="en"> + <xi att="100%"> + <zeta name="false" xml:id="id3"> + <phi xml:id="id4"/> + <tau xml:lang="no"> + <green>This text must be green</green> + </tau> + </zeta> + </xi> + </upsilon> + </xi> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="nb"][@xml:id="id1"]/zeta[@true][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[@delete="this-is-att-value"][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[starts-with(concat(@class,"-"),"content-")][@xml:lang="en-GB"][not(following-sibling::*)]/chi[contains(@object,"tru")][@xml:id="id4"][following-sibling::beta[@xml:lang="en"][@xml:id="id5"]//nu[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::xi[@object="100%"][@xml:id="id7"]//upsilon/omicron[starts-with(concat(@content,"-"),"solid 1px green-")][@xml:lang="nb"][@xml:id="id8"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@desciption][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:id="id10"]/lambda[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:lang="nb"][@xml:id="id12"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="nb" xml:id="id1"> + <zeta true="solid 1px green" xml:lang="en-GB" xml:id="id2"/> + <delta delete="this-is-att-value" xml:lang="en" xml:id="id3"> + <epsilon class="content" xml:lang="en-GB"> + <chi object="true" xml:id="id4"/> + <beta xml:lang="en" xml:id="id5"> + <nu xml:lang="en-GB" xml:id="id6"/> + <xi object="100%" xml:id="id7"> + <upsilon> + <omicron content="solid 1px green" xml:lang="nb" xml:id="id8"/> + <chi desciption="this.nodeValue"> + <beta xml:lang="nb" xml:id="id9"/> + <upsilon xml:id="id10"> + <lambda and="this.nodeValue" xml:lang="nb" xml:id="id11"/> + <nu xml:lang="nb" xml:id="id12"> + <green>This text must be green</green> + </nu> + </upsilon> + </chi> + </upsilon> + </xi> + </beta> + </epsilon> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]//alpha[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::beta[@xml:lang="no"][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id6"]/gamma[@and="100%"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@src][@xml:id="id7"][not(child::node())][following-sibling::tau[@xml:lang="en"]/pi[@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/omicron[@object][not(following-sibling::*)]//chi[@xml:lang="nb"][following-sibling::omega[contains(@or," value")][@xml:lang="en-GB"][following-sibling::xi[@xml:lang="en"][@xml:id="id9"]//*[starts-with(concat(@content,"-"),"this-")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en"][not(following-sibling::*)]//tau[@xml:lang="no-nb"][@xml:id="id10"][not(following-sibling::*)]/xi[@xml:lang="en"][@xml:id="id11"]//tau[@number][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:id="id12"][preceding-sibling::*[position() = 1]][following-sibling::*[contains(concat(@string,"$"),"reen$")][@xml:id="id13"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//pi[@number][@xml:lang="en-GB"][@xml:id="id14"][not(following-sibling::*)][position() = 1]][position() = 1]]]]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <alpha xml:lang="en" xml:id="id2"/> + <tau xml:lang="no-nb" xml:id="id3"/> + <beta xml:lang="no" xml:id="id4"/> + <lambda xml:lang="en-US" xml:id="id5"/> + <epsilon xml:lang="no-nb" xml:id="id6"> + <gamma and="100%"> + <omicron src="attribute value" xml:id="id7"/> + <tau xml:lang="en"> + <pi xml:id="id8"/> + <alpha xml:lang="en-US"> + <omicron object="solid 1px green"> + <chi xml:lang="nb"/> + <omega or="attribute value" xml:lang="en-GB"/> + <xi xml:lang="en" xml:id="id9"> + <any content="this-is-att-value" xml:lang="no"/> + <gamma/> + <lambda xml:lang="en"> + <tau xml:lang="no-nb" xml:id="id10"> + <xi xml:lang="en" xml:id="id11"> + <tau number="attribute value"/> + <tau xml:id="id12"/> + <any string="solid 1px green" xml:id="id13"> + <pi number="false" xml:lang="en-GB" xml:id="id14"> + <green>This text must be green</green> + </pi> + </any> + </xi> + </tau> + </lambda> + </xi> + </omicron> + </alpha> + </tau> + </gamma> + </epsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//psi[contains(@desciption,"456789")][@xml:lang="nb"]//eta[@attribute="123456789"][@xml:id="id1"][not(following-sibling::*)]/gamma[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::mu[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[not(following-sibling::*)]//iota[@xml:lang="no"][not(child::node())][following-sibling::lambda[@insert="false"][@xml:id="id4"]//kappa[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::*[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/iota[@xml:lang="no"][not(following-sibling::*)]/sigma[contains(concat(@true,"$"),"ibute value$")][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]//theta[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::mu//mu[@attribute][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::mu)][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//alpha[starts-with(@desciption,"another attribute valu")][@xml:lang="no"][@xml:id="id8"]/eta[contains(concat(@token,"$"),"bute$")][@xml:id="id9"][not(following-sibling::*)]/mu[@xml:lang="nb"]/beta[@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <psi desciption="123456789" xml:lang="nb"> + <eta attribute="123456789" xml:id="id1"> + <gamma xml:id="id2"/> + <mu xml:lang="en" xml:id="id3"/> + <pi> + <iota xml:lang="no"/> + <lambda insert="false" xml:id="id4"> + <kappa xml:id="id5"/> + <any xml:lang="en-US"> + <iota xml:lang="no"> + <sigma true="another attribute value" xml:lang="en" xml:id="id6"> + <theta xml:lang="no"/> + <mu> + <mu attribute="solid 1px green" xml:lang="en-GB" xml:id="id7"/> + <sigma> + <alpha desciption="another attribute value" xml:lang="no" xml:id="id8"> + <eta token="attribute" xml:id="id9"> + <mu xml:lang="nb"> + <beta xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </beta> + </mu> + </eta> + </alpha> + </sigma> + </mu> + </sigma> + </iota> + </any> + </lambda> + </pi> + </eta> + </psi> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-GB"]/xi[@att][not(preceding-sibling::*)][not(following-sibling::*)]/tau[starts-with(@or,"1234")][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:id="id2"][preceding-sibling::*[position() = 1]]//xi[contains(@and,"lue")][@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[contains(concat(@true,"$"),"tribute value$")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]]//psi[starts-with(concat(@insert,"-"),"this-")][@xml:id="id4"]//epsilon[following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:id="id5"][preceding-sibling::*[position() = 1]]//nu[@xml:lang="no-nb"][following-sibling::nu/iota[not(following-sibling::*)][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en-GB"> + <xi att="attribute value"> + <tau or="123456789" xml:id="id1"/> + <omicron xml:id="id2"> + <xi and="attribute-value" xml:lang="en-GB" xml:id="id3"/> + <omicron xml:lang="en"/> + <xi true="attribute value" xml:lang="en-US"> + <psi insert="this-is-att-value" xml:id="id4"> + <epsilon/> + <tau xml:id="id5"> + <nu xml:lang="no-nb"/> + <nu> + <iota> + <green>This text must be green</green> + </iota> + </nu> + </tau> + </psi> + </xi> + </omicron> + </xi> + </chi> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="nb"][@xml:id="id1"]//epsilon[@class][@xml:id="id2"][not(preceding-sibling::*)]//omicron[not(following-sibling::*)]//beta[starts-with(@content,"this.no")][@xml:lang="en-GB"][not(following-sibling::*)]//mu[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::mu[not(following-sibling::*)]/sigma[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[starts-with(@title,"at")][@xml:id="id5"][preceding-sibling::*[position() = 1]]/lambda[starts-with(@number,"attr")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::kappa[starts-with(concat(@content,"-"),"this-")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[not(following-sibling::*)]//epsilon[@xml:id="id8"][not(following-sibling::*)]//omicron[@delete][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@att][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="nb" xml:id="id1"> + <epsilon class="_blank" xml:id="id2"> + <omicron> + <beta content="this.nodeValue" xml:lang="en-GB"> + <mu xml:lang="en-GB" xml:id="id3"/> + <mu> + <sigma xml:id="id4"/> + <upsilon title="attribute value" xml:id="id5"> + <lambda number="attribute-value" xml:lang="en-GB" xml:id="id6"/> + <kappa content="this-is-att-value" xml:id="id7"> + <any> + <epsilon xml:id="id8"> + <omicron delete="_blank" xml:lang="no" xml:id="id9"> + <gamma att="true" xml:lang="nb" xml:id="id10"> + <green>This text must be green</green> + </gamma> + </omicron> + </epsilon> + </any> + </kappa> + </upsilon> + </mu> + </beta> + </omicron> + </epsilon> + </omicron> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="en"]//omega[@xml:id="id1"][not(preceding-sibling::*)][not(preceding-sibling::omega)]//theta[@xml:lang="nb"][@xml:id="id2"]/epsilon[@object][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::zeta[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="no-nb"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="en"> + <omega xml:id="id1"> + <theta xml:lang="nb" xml:id="id2"> + <epsilon object="another attribute value" xml:lang="en-US" xml:id="id3"/> + <zeta xml:id="id4"/> + <psi xml:lang="no-nb"> + <green>This text must be green</green> + </psi> + </theta> + </omega> + </rho> + </tree> + </test> + <test> + <xpath>//epsilon/alpha//rho[@string][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[starts-with(@number,"_bla")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::omicron[not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <epsilon> + <alpha> + <rho string="_blank" xml:lang="nb"> + <kappa number="_blank" xml:lang="no"/> + <upsilon xml:lang="en"/> + <omicron> + <green>This text must be green</green> + </omicron> + </rho> + </alpha> + </epsilon> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="en-GB"][@xml:id="id1"]/sigma[@string="solid 1px green"][@xml:lang="en-US"][@xml:id="id2"][following-sibling::pi[@xml:id="id3"][following-sibling::*[position()=2]][following-sibling::zeta[preceding-sibling::*[position() = 2]][following-sibling::alpha[@string]/kappa[contains(@content,"ank")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]//omega[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::omega)]/nu[@xml:lang="no"][not(preceding-sibling::*)]//epsilon[@or][@xml:lang="en-GB"][@xml:id="id6"]/lambda[not(preceding-sibling::*)][following-sibling::delta[@delete][preceding-sibling::*[position() = 1]][following-sibling::nu[@object][@xml:id="id7"][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 3]]/omega[@xml:id="id8"][not(preceding-sibling::*)]//delta[@xml:lang="no-nb"][not(preceding-sibling::*)]//pi[not(preceding-sibling::*)][following-sibling::phi[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::phi[preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="en-GB" xml:id="id1"> + <sigma string="solid 1px green" xml:lang="en-US" xml:id="id2"/> + <pi xml:id="id3"/> + <zeta/> + <alpha string="_blank"> + <kappa content="_blank" xml:lang="no-nb" xml:id="id4"> + <omega xml:lang="no-nb" xml:id="id5"> + <nu xml:lang="no"> + <epsilon or="solid 1px green" xml:lang="en-GB" xml:id="id6"> + <lambda/> + <delta delete="attribute-value"/> + <nu object="attribute-value" xml:id="id7"/> + <zeta> + <omega xml:id="id8"> + <delta xml:lang="no-nb"> + <pi/> + <phi xml:id="id9"/> + <phi> + <green>This text must be green</green> + </phi> + </delta> + </omega> + </zeta> + </epsilon> + </nu> + </omega> + </kappa> + </alpha> + </epsilon> + </tree> + </test> + <test> + <xpath>//theta[@or="this-is-att-value"]//beta[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::omega[starts-with(@attr,"at")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[starts-with(@desciption,"solid 1px gre")][@xml:lang="en-US"]//epsilon[@true][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::gamma[contains(@data,"234")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//zeta[@content][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::upsilon[contains(@number,"attribute valu")][@xml:id="id5"]//theta[@xml:id="id6"][not(child::node())][following-sibling::theta[contains(concat(@false,"$"),"e$")][following-sibling::chi//beta[contains(concat(@attribute,"$"),"100%$")]//iota[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)]/phi[@token][@xml:lang="nb"][@xml:id="id8"][not(following-sibling::*)][not(preceding-sibling::phi)]/zeta[@xml:lang="en-US"]/omicron[@xml:id="id9"][not(preceding-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <theta or="this-is-att-value"> + <beta xml:lang="en" xml:id="id1"/> + <omega attr="attribute value" xml:lang="en-GB"> + <nu desciption="solid 1px green" xml:lang="en-US"> + <epsilon true="_blank" xml:lang="en-GB" xml:id="id2"/> + <gamma data="123456789"/> + <sigma/> + <sigma xml:lang="no-nb" xml:id="id3"> + <zeta content="attribute-value" xml:id="id4"/> + <upsilon number="another attribute value" xml:id="id5"> + <theta xml:id="id6"/> + <theta false="true"/> + <chi> + <beta attribute="100%"> + <iota xml:lang="en-US" xml:id="id7"> + <phi token="content" xml:lang="nb" xml:id="id8"> + <zeta xml:lang="en-US"> + <omicron xml:id="id9"> + <green>This text must be green</green> + </omicron> + </zeta> + </phi> + </iota> + </beta> + </chi> + </upsilon> + </sigma> + </nu> + </omega> + </theta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="no"]//eta[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="en-US"]/eta//rho[@insert="_blank"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="no"> + <eta xml:id="id1"> + <theta xml:id="id2"/> + <omicron xml:lang="en-US"> + <eta> + <rho insert="_blank"> + <green>This text must be green</green> + </rho> + </eta> + </omicron> + </eta> + </sigma> + </tree> + </test> + <test> + <xpath>//xi[@class][@xml:lang="en-GB"]/theta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[starts-with(concat(@data,"-"),"attribute value-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/omicron[@xml:lang="en-US"][not(child::node())][following-sibling::zeta[@delete][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]/pi[contains(@false,"olid 1px green")][@xml:lang="nb"][not(following-sibling::*)]//zeta[@token="attribute value"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[following-sibling::rho[@attribute="solid 1px green"]/*[@false][@xml:lang="no"]//delta[contains(concat(@or,"$"),"_blank$")][not(preceding-sibling::*)]//iota[starts-with(@token,"att")][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:id="id2"][not(child::node())][following-sibling::tau[@data][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::upsilon[contains(concat(@src,"$"),"false$")][preceding-sibling::*[position() = 3]][following-sibling::kappa//epsilon[@or="this-is-att-value"][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::*[contains(@class,"bute value")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <xi class="content" xml:lang="en-GB"> + <theta xml:lang="no"> + <nu xml:lang="no-nb"/> + <zeta data="attribute value" xml:lang="no-nb"> + <omicron xml:lang="en-US"/> + <zeta delete="_blank" xml:lang="no-nb" xml:id="id1"> + <pi false="solid 1px green" xml:lang="nb"> + <zeta token="attribute value"> + <xi/> + <rho attribute="solid 1px green"> + <any false="solid 1px green" xml:lang="no"> + <delta or="_blank"> + <iota token="attribute"/> + <any xml:id="id2"/> + <tau data="false"/> + <upsilon src="false"/> + <kappa> + <epsilon or="this-is-att-value" xml:lang="en-GB" xml:id="id3"/> + <any class="another attribute value" xml:lang="en-GB"> + <green>This text must be green</green> + </any> + </kappa> + </delta> + </any> + </rho> + </zeta> + </pi> + </zeta> + </zeta> + </theta> + </xi> + </tree> + </test> + <test> + <xpath>//phi[@and="this.nodeValue"][@xml:id="id1"]//chi[@xml:id="id2"][not(preceding-sibling::*)]//psi[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::iota[@src][@xml:lang="en"][following-sibling::*[position()=3]][following-sibling::rho[starts-with(concat(@number,"-"),"true-")][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::eta[@delete][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][following-sibling::beta[contains(@attribute,"100")][@xml:id="id5"][preceding-sibling::*[position() = 4]]//psi[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@false="attribute-value"][@xml:lang="nb"]/kappa[@xml:id="id7"][following-sibling::xi[@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 1]]/tau[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[starts-with(@true,"attri")][@xml:lang="no"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/*[following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[@xml:id="id11"][not(preceding-sibling::*)][following-sibling::alpha[starts-with(concat(@name,"-"),"false-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[@false="true"][@xml:lang="nb"][following-sibling::rho[@name][@xml:lang="nb"][@xml:id="id12"][preceding-sibling::*[position() = 3]][following-sibling::zeta[@xml:id="id13"][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]/alpha[@xml:lang="no"][not(preceding-sibling::alpha)]/zeta[@xml:id="id14"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <phi and="this.nodeValue" xml:id="id1"> + <chi xml:id="id2"> + <psi xml:id="id3"/> + <iota src="100%" xml:lang="en"/> + <rho number="true" xml:id="id4"/> + <eta delete="123456789" xml:lang="no-nb"/> + <beta attribute="100%" xml:id="id5"> + <psi xml:lang="no" xml:id="id6"/> + <phi false="attribute-value" xml:lang="nb"> + <kappa xml:id="id7"/> + <xi xml:lang="en" xml:id="id8"> + <tau xml:id="id9"> + <omicron true="attribute" xml:lang="no" xml:id="id10"> + <any/> + <zeta> + <omega xml:id="id11"/> + <alpha name="false"/> + <upsilon false="true" xml:lang="nb"/> + <rho name="content" xml:lang="nb" xml:id="id12"/> + <zeta xml:id="id13"/> + <omega xml:lang="en-GB"> + <alpha xml:lang="no"> + <zeta xml:id="id14"> + <green>This text must be green</green> + </zeta> + </alpha> + </omega> + </zeta> + </omicron> + </tau> + </xi> + </phi> + </beta> + </chi> + </phi> + </tree> + </test> + <test> + <xpath>//alpha[contains(@number," 1px gre")]/eta[not(child::node())][following-sibling::iota[@xml:lang="en"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::nu[@object][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//psi[@attrib][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::nu[@delete][preceding-sibling::*[position() = 1]]//beta/tau[@xml:id="id3"]/chi[starts-with(concat(@true,"-"),"content-")][@xml:id="id4"][not(preceding-sibling::*)]/phi[@xml:id="id5"][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]]//iota[not(following-sibling::*)]/upsilon[contains(concat(@name,"$"),"k$")]/eta[@data="attribute"][not(child::node())][following-sibling::tau[@xml:id="id7"][preceding-sibling::*[position() = 1]]//eta[@token="attribute-value"][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::kappa[@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:id="id9"][preceding-sibling::*[position() = 2]]//lambda[@desciption="123456789"]/gamma[@attr][@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <alpha number="solid 1px green"> + <eta/> + <iota xml:lang="en" xml:id="id1"/> + <nu object="content"> + <psi attrib="another attribute value" xml:id="id2"/> + <nu delete="_blank"> + <beta> + <tau xml:id="id3"> + <chi true="content" xml:id="id4"> + <phi xml:id="id5"/> + <psi xml:lang="en-GB" xml:id="id6"> + <iota> + <upsilon name="_blank"> + <eta data="attribute"/> + <tau xml:id="id7"> + <eta token="attribute-value" xml:lang="en"/> + <kappa xml:id="id8"/> + <iota xml:id="id9"> + <lambda desciption="123456789"> + <gamma attr="attribute value" xml:id="id10"/> + <beta xml:id="id11"> + <green>This text must be green</green> + </beta> + </lambda> + </iota> + </tau> + </upsilon> + </iota> + </psi> + </chi> + </tau> + </beta> + </nu> + </nu> + </alpha> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(@insert,"fa")][@xml:lang="en-US"][@xml:id="id1"]/eta[contains(concat(@class,"$"),"e$")][@xml:lang="en"]//nu[starts-with(concat(@string,"-"),"this-")][@xml:id="id2"][following-sibling::alpha[contains(concat(@name,"$"),"tribute$")][@xml:lang="en-US"][following-sibling::upsilon[preceding-sibling::*[position() = 2]]//nu[not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en-GB"][not(child::node())][following-sibling::zeta[starts-with(@class,"con")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/omicron[following-sibling::iota[not(child::node())][following-sibling::theta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::sigma[@xml:id="id4"][not(child::node())][following-sibling::alpha[@xml:id="id5"][following-sibling::sigma[starts-with(@content,"10")][@xml:id="id6"][not(child::node())][following-sibling::omicron[@content="true"][@xml:id="id7"][position() = 1]]]][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <epsilon insert="false" xml:lang="en-US" xml:id="id1"> + <eta class="true" xml:lang="en"> + <nu string="this-is-att-value" xml:id="id2"/> + <alpha name="attribute" xml:lang="en-US"/> + <upsilon> + <nu/> + <upsilon xml:lang="en-GB"/> + <zeta class="content" xml:lang="en-US"/> + <alpha> + <omicron/> + <iota/> + <theta xml:lang="no" xml:id="id3"/> + <sigma xml:id="id4"/> + <alpha xml:id="id5"/> + <sigma content="100%" xml:id="id6"/> + <omicron content="true" xml:id="id7"> + <green>This text must be green</green> + </omicron> + </alpha> + </upsilon> + </eta> + </epsilon> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]//iota[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[preceding-sibling::*[position() = 1]]//delta[@insert][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@data][@xml:lang="no-nb"][not(following-sibling::*)]//lambda[@xml:id="id2"][following-sibling::epsilon[@insert][@xml:lang="no"][preceding-sibling::*[position() = 1]]/phi[@xml:id="id3"][not(preceding-sibling::*)]//rho[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="en-US"][not(child::node())][following-sibling::psi[@name][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:lang="en"][not(following-sibling::*)]//omicron[starts-with(@attr,"c")]/upsilon[contains(concat(@name,"$")," 1px green$")][@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]/delta[not(following-sibling::*)]/beta[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::omicron[@content][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[contains(concat(@token,"$"),"ue$")][@xml:id="id7"][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <iota/> + <phi> + <delta insert="123456789"> + <sigma data="false" xml:lang="no-nb"> + <lambda xml:id="id2"/> + <epsilon insert="attribute-value" xml:lang="no"> + <phi xml:id="id3"> + <rho xml:lang="no-nb"/> + <delta xml:lang="en-US"/> + <psi name="_blank" xml:id="id4"/> + <upsilon xml:lang="en"> + <omicron attr="content"> + <upsilon name="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <delta> + <beta xml:lang="no" xml:id="id6"/> + <omicron content="attribute value" xml:lang="no-nb"> + <sigma token="this.nodeValue" xml:id="id7"> + <green>This text must be green</green> + </sigma> + </omicron> + </delta> + </upsilon> + </omicron> + </upsilon> + </phi> + </epsilon> + </sigma> + </delta> + </phi> + </xi> + </tree> + </test> + <test> + <xpath>//theta[contains(@string,"ontent")][@xml:lang="nb"]//iota[contains(@token,"t-v")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:id="id1"]//kappa[@xml:id="id2"][not(preceding-sibling::*)]//beta[@attribute="this-is-att-value"][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[starts-with(concat(@true,"-"),"solid 1px green-")][@xml:id="id4"][following-sibling::omega[@and="attribute"][@xml:lang="no"][not(following-sibling::*)]//pi[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <theta string="content" xml:lang="nb"> + <iota token="this-is-att-value" xml:lang="en"> + <theta xml:id="id1"> + <kappa xml:id="id2"> + <beta attribute="this-is-att-value" xml:lang="en" xml:id="id3"> + <zeta true="solid 1px green" xml:id="id4"/> + <omega and="attribute" xml:lang="no"> + <pi xml:lang="en"> + <green>This text must be green</green> + </pi> + </omega> + </beta> + </kappa> + </theta> + </iota> + </theta> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en-US"]//alpha[@xml:id="id1"][not(preceding-sibling::*)]/delta[@xml:id="id2"][following-sibling::alpha[starts-with(concat(@src,"-"),"this-")][@xml:lang="en"][@xml:id="id3"][following-sibling::*[position()=3]][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::*[preceding-sibling::*[position() = 3]][following-sibling::epsilon[starts-with(concat(@attribute,"-"),"solid 1px green-")][not(following-sibling::*)]//sigma[@class][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id5"][preceding-sibling::*[position() = 1]]/kappa[@delete="123456789"][@xml:lang="no"][following-sibling::epsilon[@xml:id="id6"][not(following-sibling::*)]/kappa[@xml:id="id7"][not(following-sibling::*)]/sigma[contains(@attr,"12345")][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[preceding-sibling::*[position() = 1]]/eta[@false][@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::xi[starts-with(concat(@and,"-"),"another attribute value-")][@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]//*[contains(concat(@title,"$"),"tribute value$")][not(preceding-sibling::*)][not(following-sibling::any)][following-sibling::omega[@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::kappa[@class="attribute"][@xml:id="id11"][preceding-sibling::*[position() = 2]][following-sibling::psi[@true="another attribute value"][@xml:id="id12"][not(child::node())][following-sibling::nu[contains(concat(@src,"$"),"false$")][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::psi[@xml:id="id13"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en-US"> + <alpha xml:id="id1"> + <delta xml:id="id2"/> + <alpha src="this-is-att-value" xml:lang="en" xml:id="id3"/> + <beta xml:lang="nb"/> + <any/> + <epsilon attribute="solid 1px green"> + <sigma class="this-is-att-value" xml:id="id4"/> + <beta xml:id="id5"> + <kappa delete="123456789" xml:lang="no"/> + <epsilon xml:id="id6"> + <kappa xml:id="id7"> + <sigma attr="123456789"/> + <rho> + <eta false="solid 1px green" xml:lang="en-GB" xml:id="id8"/> + <xi and="another attribute value" xml:lang="en" xml:id="id9"> + <any title="another attribute value"/> + <omega xml:id="id10"/> + <kappa class="attribute" xml:id="id11"/> + <psi true="another attribute value" xml:id="id12"/> + <nu src="false"/> + <psi xml:id="id13"> + <green>This text must be green</green> + </psi> + </xi> + </rho> + </kappa> + </epsilon> + </beta> + </epsilon> + </alpha> + </omega> + </tree> + </test> + <test> + <xpath>//theta[@attribute][@xml:id="id1"]//nu[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 1]]//*[starts-with(concat(@attr,"-"),"_blank-")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]/omicron[contains(@delete,"ther attribute value")][@xml:id="id3"]/pi[@xml:lang="no"]//kappa[@xml:lang="en"][@xml:id="id4"]//delta[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[not(following-sibling::*)][not(following-sibling::iota)]/eta[starts-with(concat(@delete,"-"),"solid 1px green-")][@xml:lang="nb"][not(child::node())][following-sibling::*[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[starts-with(concat(@attrib,"-"),"solid 1px green-")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[not(preceding-sibling::*)][not(following-sibling::*)]/lambda[contains(@or,"alse")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <theta attribute="_blank" xml:id="id1"> + <nu xml:lang="no"/> + <phi> + <any attr="_blank" xml:lang="nb" xml:id="id2"> + <omicron delete="another attribute value" xml:id="id3"> + <pi xml:lang="no"> + <kappa xml:lang="en" xml:id="id4"> + <delta xml:lang="no" xml:id="id5"> + <iota> + <eta delete="solid 1px green" xml:lang="nb"/> + <any xml:lang="en-US" xml:id="id6"> + <epsilon attrib="solid 1px green" xml:lang="en"> + <mu> + <lambda or="false" xml:lang="en-US"> + <green>This text must be green</green> + </lambda> + </mu> + </epsilon> + </any> + </iota> + </delta> + </kappa> + </pi> + </omicron> + </any> + </phi> + </theta> + </tree> + </test> + <test> + <xpath>//iota[contains(@data,"ank")][@xml:id="id1"]//*[@xml:id="id2"][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[following-sibling::*[@title][@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]//psi[@xml:id="id4"]//chi[@xml:id="id5"][not(child::node())][following-sibling::kappa[contains(@desciption,"%")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]]//psi[@class][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="no"]//omicron[starts-with(@abort,"1")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[@name="false"][@xml:lang="no"][not(preceding-sibling::*)]//zeta[@content][@xml:lang="nb"]/psi[@att="content"][@xml:lang="en"][@xml:id="id9"][following-sibling::rho[@xml:id="id10"][not(following-sibling::*)]/kappa[@xml:lang="en-US"]//lambda[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::pi[starts-with(@string,"at")][@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 1]]/kappa[starts-with(@number,"th")][@xml:id="id12"]//mu[@xml:id="id13"][not(preceding-sibling::mu)][following-sibling::kappa[not(preceding-sibling::kappa)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <iota data="_blank" xml:id="id1"> + <any xml:id="id2"/> + <beta/> + <iota/> + <any title="content" xml:lang="en-US" xml:id="id3"> + <psi xml:id="id4"> + <chi xml:id="id5"/> + <kappa desciption="100%"/> + <zeta xml:lang="en-GB" xml:id="id6"> + <psi class="100%" xml:id="id7"> + <mu xml:lang="no"> + <omicron abort="100%" xml:lang="en"/> + <lambda xml:lang="nb" xml:id="id8"> + <pi name="false" xml:lang="no"> + <zeta content="content" xml:lang="nb"> + <psi att="content" xml:lang="en" xml:id="id9"/> + <rho xml:id="id10"> + <kappa xml:lang="en-US"> + <lambda content="attribute" xml:lang="no-nb"/> + <pi string="attribute" xml:lang="no" xml:id="id11"> + <kappa number="this.nodeValue" xml:id="id12"> + <mu xml:id="id13"/> + <kappa> + <green>This text must be green</green> + </kappa> + </kappa> + </pi> + </kappa> + </rho> + </zeta> + </pi> + </lambda> + </mu> + </psi> + </zeta> + </psi> + </any> + </iota> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]//lambda[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::rho[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@object="this.nodeValue"][@xml:lang="en-GB"][not(following-sibling::*)]/gamma[contains(concat(@delete,"$"),"tribute-value$")][@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/mu[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::sigma[@and][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="en-US"][following-sibling::phi[@attrib][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 3]]//alpha/*[starts-with(@and,"this-is-at")][@xml:id="id7"][following-sibling::eta[@xml:id="id8"]//epsilon[contains(@token,"gree")][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@false][@xml:lang="no-nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]]//sigma[@xml:lang="en-GB"][not(following-sibling::*)]//gamma[@xml:lang="en-GB"][not(child::node())][following-sibling::theta[starts-with(concat(@attrib,"-"),"solid 1px green-")][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@xml:id="id12"][preceding-sibling::*[position() = 2]]//xi[@xml:lang="en-US"][not(preceding-sibling::*)]/omega[starts-with(@token,"this.nodeV")][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[starts-with(concat(@delete,"-"),"another attribute value-")][@xml:lang="en-US"][not(following-sibling::*)]//epsilon[position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <lambda xml:lang="en-GB" xml:id="id2"/> + <rho xml:id="id3"> + <psi object="this.nodeValue" xml:lang="en-GB"> + <gamma delete="attribute-value" xml:lang="no-nb" xml:id="id4"> + <mu xml:id="id5"/> + <sigma and="false"/> + <beta xml:lang="en-US"/> + <phi attrib="this.nodeValue" xml:lang="no-nb" xml:id="id6"> + <alpha> + <any and="this-is-att-value" xml:id="id7"/> + <eta xml:id="id8"> + <epsilon token="solid 1px green" xml:id="id9"/> + <delta false="another attribute value" xml:lang="no-nb" xml:id="id10"> + <sigma xml:lang="en-GB"> + <gamma xml:lang="en-GB"/> + <theta attrib="solid 1px green" xml:id="id11"/> + <kappa xml:id="id12"> + <xi xml:lang="en-US"> + <omega token="this.nodeValue"/> + <lambda/> + <chi/> + <zeta delete="another attribute value" xml:lang="en-US"> + <epsilon> + <green>This text must be green</green> + </epsilon> + </zeta> + </xi> + </kappa> + </sigma> + </delta> + </eta> + </alpha> + </phi> + </gamma> + </psi> + </rho> + </pi> + </tree> + </test> + <test> + <xpath>//omicron[starts-with(@att,"attribute value")]//mu[@xml:lang="en-GB"][@xml:id="id1"][not(child::node())][following-sibling::beta//sigma[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::delta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[starts-with(@or,"tru")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::mu[starts-with(concat(@attrib,"-"),"attribute value-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 4]][following-sibling::rho[@att][@xml:lang="en-GB"][following-sibling::iota[@name][not(following-sibling::*)]//lambda[@desciption][@xml:id="id4"][not(preceding-sibling::*)]/tau[contains(@false,"0%")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][not(child::node())][following-sibling::epsilon/chi[@token][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::kappa[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="no"]/lambda[@attrib]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <omicron att="attribute value"> + <mu xml:lang="en-GB" xml:id="id1"/> + <beta> + <sigma xml:lang="en-US" xml:id="id2"/> + <delta xml:lang="no" xml:id="id3"/> + <kappa or="true" xml:lang="en-GB"/> + <mu attrib="attribute value" xml:lang="no-nb"/> + <zeta/> + <rho att="false" xml:lang="en-GB"/> + <iota name="_blank"> + <lambda desciption="another attribute value" xml:id="id4"> + <tau false="100%" xml:lang="en-GB"/> + <epsilon xml:lang="en-US"/> + <epsilon> + <chi token="content" xml:lang="en-US" xml:id="id5"/> + <kappa xml:lang="no" xml:id="id6"/> + <theta xml:lang="no"> + <lambda attrib="false"> + <green>This text must be green</green> + </lambda> + </theta> + </epsilon> + </lambda> + </iota> + </beta> + </omicron> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="no"]/pi[not(following-sibling::*)]//chi[@attrib][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::sigma[@attribute][@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[starts-with(concat(@attr,"-"),"content-")][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:id="id3"][preceding-sibling::*[position() = 3]]//mu[@xml:id="id4"][not(child::node())][following-sibling::theta[@number="attribute-value"][@xml:id="id5"][following-sibling::rho[starts-with(@number,"solid 1px gre")][@xml:id="id6"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="no"> + <pi> + <chi attrib="attribute value" xml:lang="en-US" xml:id="id1"/> + <sigma attribute="attribute value" xml:lang="en-US" xml:id="id2"/> + <eta attr="content"/> + <rho xml:id="id3"> + <mu xml:id="id4"/> + <theta number="attribute-value" xml:id="id5"/> + <rho number="solid 1px green" xml:id="id6"> + <green>This text must be green</green> + </rho> + </rho> + </pi> + </zeta> + </tree> + </test> + <test> + <xpath>//alpha[@false][@xml:lang="no-nb"]//theta[@false][@xml:id="id1"][following-sibling::delta[preceding-sibling::*[position() = 1]][following-sibling::mu[starts-with(@and,"this.n")][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/kappa[@xml:lang="en"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::psi[starts-with(concat(@class,"-"),"attribute value-")][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[following-sibling::theta[starts-with(concat(@delete,"-"),"this-")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::sigma[@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@number][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]]//theta[@xml:lang="no"][@xml:id="id7"]//nu[@attr][not(child::node())][following-sibling::omega[starts-with(@delete,"cont")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@xml:lang="en"][@xml:id="id8"]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <alpha false="123456789" xml:lang="no-nb"> + <theta false="true" xml:id="id1"/> + <delta/> + <mu and="this.nodeValue" xml:id="id2"> + <kappa xml:lang="en" xml:id="id3"/> + <psi class="attribute value" xml:id="id4"> + <lambda/> + <theta delete="this-is-att-value" xml:id="id5"/> + <sigma xml:id="id6"/> + <omicron number="attribute value" xml:lang="no-nb"> + <theta xml:lang="no" xml:id="id7"> + <nu attr="attribute"/> + <omega delete="content" xml:lang="en"/> + <alpha xml:lang="en" xml:id="id8"> + <green>This text must be green</green> + </alpha> + </theta> + </omicron> + </psi> + </mu> + </alpha> + </tree> + </test> + <test> + <xpath>//xi//gamma[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::kappa[@xml:id="id1"][following-sibling::rho[starts-with(@title,"100")][following-sibling::lambda[starts-with(concat(@true,"-"),"another attribute value-")][@xml:lang="en-GB"][@xml:id="id2"]//gamma[@token][not(child::node())][following-sibling::psi[starts-with(concat(@insert,"-"),"100%-")][@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]/tau[starts-with(concat(@number,"-"),"attribute-")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::tau[@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::upsilon[@class][@xml:lang="en-US"][following-sibling::upsilon[not(following-sibling::*)]//sigma[starts-with(concat(@or,"-"),"true-")][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@class][@xml:id="id7"][not(following-sibling::*)]//omega[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(concat(@false,"$"),"ue$")][@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)]//beta[starts-with(@content,"fa")][@xml:id="id9"][not(following-sibling::*)]//upsilon[contains(@att,"ut")][not(preceding-sibling::*)]//beta[@name="false"][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::pi[@xml:lang="no"][@xml:id="id11"][position() = 1]][position() = 1]][position() = 1]]]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <xi> + <gamma xml:lang="no-nb"/> + <kappa xml:id="id1"/> + <rho title="100%"/> + <lambda true="another attribute value" xml:lang="en-GB" xml:id="id2"> + <gamma token="this.nodeValue"/> + <psi insert="100%" xml:lang="en-GB" xml:id="id3"> + <tau number="attribute" xml:id="id4"/> + <tau xml:id="id5"/> + <upsilon class="solid 1px green" xml:lang="en-US"/> + <upsilon> + <sigma or="true" xml:lang="no-nb" xml:id="id6"/> + <nu class="true" xml:id="id7"> + <omega xml:lang="nb"> + <rho false="true" xml:lang="no-nb" xml:id="id8"> + <beta content="false" xml:id="id9"> + <upsilon att="attribute-value"> + <beta name="false" xml:lang="no"/> + <delta xml:id="id10"/> + <pi xml:lang="no" xml:id="id11"> + <green>This text must be green</green> + </pi> + </upsilon> + </beta> + </rho> + </omega> + </nu> + </upsilon> + </psi> + </lambda> + </xi> + </tree> + </test> + <test> + <xpath>//chi/delta[@object="123456789"][@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]//pi[contains(concat(@attrib,"$"),"e$")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[contains(@false,"e")][@xml:id="id3"][not(following-sibling::*)]//chi[@or][not(following-sibling::*)]/zeta[starts-with(@data,"t")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::gamma[starts-with(concat(@number,"-"),"solid 1px green-")][not(following-sibling::*)]/chi[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[not(following-sibling::*)]/rho[@att="content"][@xml:id="id6"][not(following-sibling::*)]/sigma[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[starts-with(@attribute,"this-is")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@object][following-sibling::*[position()=1]][following-sibling::chi[@class][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//psi[@class][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@src][@xml:id="id8"]/omicron[@attrib][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <chi> + <delta object="123456789" xml:lang="en-GB" xml:id="id1"> + <pi attrib="true" xml:id="id2"> + <delta false="attribute-value" xml:id="id3"> + <chi or="content"> + <zeta data="true" xml:id="id4"/> + <gamma number="solid 1px green"> + <chi xml:id="id5"> + <beta> + <rho att="content" xml:id="id6"> + <sigma xml:lang="nb"> + <omicron attribute="this-is-att-value" xml:lang="no"/> + <xi object="another attribute value"/> + <chi class="false" xml:lang="en-US" xml:id="id7"> + <psi class="solid 1px green"/> + <upsilon src="another attribute value" xml:id="id8"> + <omicron attrib="content" xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </upsilon> + </chi> + </sigma> + </rho> + </beta> + </chi> + </gamma> + </chi> + </delta> + </pi> + </delta> + </chi> + </tree> + </test> + <test> + <xpath>//theta[@data][@xml:id="id1"]//gamma[@attrib="solid 1px green"][not(preceding-sibling::*)]//psi[@xml:lang="no"][not(preceding-sibling::*)]/psi[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@delete][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@attribute="attribute-value"][@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <theta data="solid 1px green" xml:id="id1"> + <gamma attrib="solid 1px green"> + <psi xml:lang="no"> + <psi xml:lang="nb" xml:id="id2"> + <xi delete="attribute-value" xml:lang="en-GB"/> + <kappa attribute="attribute-value" xml:lang="en-US" xml:id="id3"/> + <nu xml:id="id4"> + <green>This text must be green</green> + </nu> + </psi> + </psi> + </gamma> + </theta> + </tree> + </test> + <test> + <xpath>//phi[starts-with(concat(@number,"-"),"this.nodeValue-")][@xml:lang="en-GB"][@xml:id="id1"]//epsilon[@xml:id="id2"][not(following-sibling::*)]/sigma[@xml:lang="no"][following-sibling::sigma[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::xi[@attrib][@xml:id="id4"][not(following-sibling::*)]//gamma[@xml:lang="no-nb"][@xml:id="id5"]/zeta[@xml:lang="en-US"][not(preceding-sibling::*)]//zeta[contains(@abort,"lue")][@xml:id="id6"][not(child::node())][following-sibling::nu[@delete][@xml:lang="no"][following-sibling::sigma[starts-with(@att,"conte")][@xml:id="id7"][not(following-sibling::*)]//omicron[starts-with(concat(@src,"-"),"attribute value-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@data][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:lang="no-nb"]//pi[@xml:id="id8"][not(following-sibling::*)]//beta[@attribute][@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::xi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::omicron[starts-with(@name,"anot")][@xml:lang="en-US"][following-sibling::*[position()=1]][not(following-sibling::omicron)][following-sibling::chi[@name][not(following-sibling::*)]//kappa[@xml:lang="nb"][@xml:id="id9"][not(following-sibling::*)]/xi[starts-with(concat(@content,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <phi number="this.nodeValue" xml:lang="en-GB" xml:id="id1"> + <epsilon xml:id="id2"> + <sigma xml:lang="no"/> + <sigma xml:id="id3"/> + <nu attr="attribute" xml:lang="no"/> + <xi attrib="123456789" xml:id="id4"> + <gamma xml:lang="no-nb" xml:id="id5"> + <zeta xml:lang="en-US"> + <zeta abort="this-is-att-value" xml:id="id6"/> + <nu delete="this-is-att-value" xml:lang="no"/> + <sigma att="content" xml:id="id7"> + <omicron src="attribute value"/> + <alpha data="this-is-att-value"> + <xi xml:lang="no-nb"> + <pi xml:id="id8"> + <beta attribute="solid 1px green" xml:lang="no"/> + <xi xml:lang="no-nb"/> + <omicron name="another attribute value" xml:lang="en-US"/> + <chi name="this.nodeValue"> + <kappa xml:lang="nb" xml:id="id9"> + <xi content="attribute"> + <green>This text must be green</green> + </xi> + </kappa> + </chi> + </pi> + </xi> + </alpha> + </sigma> + </zeta> + </gamma> + </xi> + </epsilon> + </phi> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@abort,"attribut")]//tau[contains(@or,"bute ")][@xml:id="id1"]/eta[not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::chi[contains(@attribute,"e")][@xml:lang="no"][not(following-sibling::*)]//zeta[contains(@object,"ntent")][@xml:lang="en-GB"]/epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[contains(concat(@src,"$"),"se$")][@xml:lang="en-US"][not(preceding-sibling::*)]/tau[@xml:id="id3"]//theta[starts-with(@src,"fa")][@xml:id="id4"][following-sibling::psi[contains(@content,"lue")][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega abort="attribute"> + <tau or="attribute value" xml:id="id1"> + <eta> + <iota xml:lang="en-US" xml:id="id2"/> + <chi attribute="true" xml:lang="no"> + <zeta object="content" xml:lang="en-GB"> + <epsilon xml:lang="no-nb"> + <epsilon src="false" xml:lang="en-US"> + <tau xml:id="id3"> + <theta src="false" xml:id="id4"/> + <psi content="this.nodeValue"> + <green>This text must be green</green> + </psi> + </tau> + </epsilon> + </epsilon> + </zeta> + </chi> + </eta> + </tau> + </omega> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no-nb"]//zeta[starts-with(concat(@attr,"-"),"solid 1px green-")][@xml:lang="no"][not(following-sibling::*)]/alpha[contains(@attrib,"alue")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//delta[contains(@object,"n")][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::eta[@xml:id="id4"][preceding-sibling::*[position() = 1]]/alpha[@object][@xml:id="id5"][not(preceding-sibling::*)]//chi[starts-with(concat(@delete,"-"),"this-")][@xml:lang="no-nb"][@xml:id="id6"][following-sibling::eta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[starts-with(@content,"fa")][@xml:lang="en"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id8"]/chi[@xml:id="id9"][not(child::node())][following-sibling::alpha[not(child::node())][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id10"][not(following-sibling::kappa)][not(child::node())][following-sibling::delta[@attr][@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no-nb"> + <zeta attr="solid 1px green" xml:lang="no"> + <alpha attrib="this-is-att-value" xml:lang="en-US" xml:id="id1"/> + <epsilon xml:lang="no" xml:id="id2"> + <delta object="another attribute value" xml:lang="en-GB" xml:id="id3"/> + <eta xml:id="id4"> + <alpha object="attribute-value" xml:id="id5"> + <chi delete="this-is-att-value" xml:lang="no-nb" xml:id="id6"/> + <eta/> + <chi content="false" xml:lang="en" xml:id="id7"/> + <kappa xml:lang="en-US" xml:id="id8"> + <chi xml:id="id9"/> + <alpha/> + <kappa xml:lang="en-GB" xml:id="id10"/> + <delta attr="100%" xml:lang="nb"> + <green>This text must be green</green> + </delta> + </kappa> + </alpha> + </eta> + </epsilon> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="en-US"][@xml:id="id1"]//xi[@object="true"][@xml:id="id2"][not(preceding-sibling::*)]/alpha[contains(@false,"fa")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[contains(@class,"value")][@xml:lang="no"][preceding-sibling::*[position() = 1]]/theta[starts-with(@number,"12345678")][@xml:lang="en-US"][following-sibling::upsilon[contains(@object,"e")][@xml:id="id3"]//theta[not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:id="id4"][not(following-sibling::*)]//upsilon[starts-with(concat(@insert,"-"),"this.nodeValue-")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::tau[contains(@content,"is-is-att")][@xml:id="id5"]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="en-US" xml:id="id1"> + <xi object="true" xml:id="id2"> + <alpha false="false" xml:lang="no-nb"/> + <psi class="this-is-att-value" xml:lang="no"> + <theta number="123456789" xml:lang="en-US"/> + <upsilon object="false" xml:id="id3"> + <theta/> + <psi xml:id="id4"> + <upsilon insert="this.nodeValue" xml:lang="no"/> + <tau content="this-is-att-value" xml:id="id5"> + <green>This text must be green</green> + </tau> + </psi> + </upsilon> + </psi> + </xi> + </tau> + </tree> + </test> + <test> + <xpath>//alpha//nu[starts-with(concat(@string,"-"),"_blank-")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::nu)]/rho[starts-with(@content,"conten")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/pi[@data][@xml:lang="nb"][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]//beta[@xml:id="id5"][following-sibling::gamma[contains(concat(@and,"$"),"nt$")][@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]/nu[@xml:lang="en"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <alpha> + <nu string="_blank" xml:id="id1"> + <rho content="content" xml:id="id2"/> + <sigma attr="attribute" xml:lang="en" xml:id="id3"> + <pi data="100%" xml:lang="nb"/> + <theta xml:lang="en-US" xml:id="id4"> + <beta xml:id="id5"/> + <gamma and="content" xml:lang="en-US" xml:id="id6"> + <nu xml:lang="en"> + <green>This text must be green</green> + </nu> + </gamma> + </theta> + </sigma> + </nu> + </alpha> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="en"]//sigma[@or][@xml:lang="no"][not(following-sibling::*)]//delta[contains(concat(@data,"$"),"tent$")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::pi[starts-with(concat(@false,"-"),"attribute-")][following-sibling::*[position()=2]][following-sibling::omega[preceding-sibling::*[position() = 3]][following-sibling::epsilon[contains(concat(@attrib,"$"),"this.nodeValue$")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//rho[@number="100%"][not(preceding-sibling::*)][following-sibling::mu[@attr][@xml:id="id4"][preceding-sibling::*[position() = 1]]//iota[@xml:id="id5"][not(following-sibling::*)]//epsilon[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:lang="nb"][not(following-sibling::*)]/phi[@attr][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="en"> + <sigma or="_blank" xml:lang="no"> + <delta data="content" xml:id="id1"/> + <chi xml:id="id2"/> + <pi false="attribute-value"/> + <omega/> + <epsilon attrib="this.nodeValue" xml:lang="no" xml:id="id3"> + <rho number="100%"/> + <mu attr="123456789" xml:id="id4"> + <iota xml:id="id5"> + <epsilon xml:lang="en"> + <epsilon xml:lang="nb"> + <phi attr="another attribute value" xml:id="id6"> + <green>This text must be green</green> + </phi> + </epsilon> + </epsilon> + </iota> + </mu> + </epsilon> + </sigma> + </eta> + </tree> + </test> + <test> + <xpath>//lambda[@src="solid 1px green"][@xml:id="id1"]//eta[@xml:id="id2"][not(preceding-sibling::*)]//omega[@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[contains(concat(@or,"$"),"_blank$")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::sigma[@xml:id="id4"][preceding-sibling::*[position() = 2]]/zeta[@attrib][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <lambda src="solid 1px green" xml:id="id1"> + <eta xml:id="id2"> + <omega xml:id="id3"/> + <xi or="_blank" xml:lang="no"/> + <sigma xml:id="id4"> + <zeta attrib="solid 1px green"> + <green>This text must be green</green> + </zeta> + </sigma> + </eta> + </lambda> + </tree> + </test> + <test> + <xpath>//sigma//kappa[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)]//phi[contains(concat(@insert,"$"),"lid 1px green$")][@xml:lang="no-nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::beta[@or][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::omicron[@attrib="content"][@xml:id="id4"][following-sibling::nu//gamma[@xml:lang="en-US"][not(preceding-sibling::*)]//kappa[starts-with(@data,"attribut")][@xml:lang="no"][not(following-sibling::*)][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <kappa xml:lang="en-US" xml:id="id1"> + <phi insert="solid 1px green" xml:lang="no-nb"/> + <theta xml:lang="en" xml:id="id2"/> + <theta> + <nu xml:lang="en"/> + <beta or="100%" xml:lang="en" xml:id="id3"/> + <omicron attrib="content" xml:id="id4"/> + <nu> + <gamma xml:lang="en-US"> + <kappa data="attribute" xml:lang="no"> + <green>This text must be green</green> + </kappa> + </gamma> + </nu> + </theta> + </kappa> + </sigma> + </tree> + </test> + <test> + <xpath>//upsilon[@and="another attribute value"][@xml:lang="no"][@xml:id="id1"]/lambda[@src][@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//xi[@string][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[contains(concat(@class,"$"),"olid 1px green$")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::upsilon[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::upsilon[@xml:lang="en"][@xml:id="id7"][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:lang="no-nb"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//omega[contains(@attribute,"e")][@xml:lang="en-GB"]/upsilon[@xml:id="id8"][not(preceding-sibling::*)]/nu[starts-with(concat(@attrib,"-"),"solid 1px green-")][@xml:lang="no"][following-sibling::iota//sigma[@xml:id="id9"][following-sibling::nu[@xml:lang="en-GB"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon and="another attribute value" xml:lang="no" xml:id="id1"> + <lambda src="attribute-value" xml:lang="en-US" xml:id="id2"> + <xi string="100%" xml:lang="en-US" xml:id="id3"> + <mu class="solid 1px green" xml:lang="en-GB" xml:id="id4"/> + <upsilon xml:id="id5"/> + <kappa xml:lang="en" xml:id="id6"/> + <upsilon xml:lang="en" xml:id="id7"/> + <any/> + <any xml:lang="no-nb"> + <omega attribute="true" xml:lang="en-GB"> + <upsilon xml:id="id8"> + <nu attrib="solid 1px green" xml:lang="no"/> + <iota> + <sigma xml:id="id9"/> + <nu xml:lang="en-GB" xml:id="id10"> + <green>This text must be green</green> + </nu> + </iota> + </upsilon> + </omega> + </any> + </xi> + </lambda> + </upsilon> + </tree> + </test> + <test> + <xpath>//eta//epsilon[@and="123456789"][@xml:id="id1"]/chi[@delete][@xml:id="id2"][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[starts-with(concat(@attrib,"-"),"123456789-")][not(preceding-sibling::*)]/iota[contains(concat(@delete,"$"),"e$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:id="id5"][preceding-sibling::*[position() = 1]]//eta[@name][@xml:id="id6"][not(preceding-sibling::*)]//zeta[starts-with(concat(@desciption,"-"),"_blank-")][@xml:id="id7"]//gamma[@attrib][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@and="true"][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]]//phi/chi[starts-with(@content,"a")][@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@attrib][@xml:id="id10"][following-sibling::upsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/nu[contains(@token,"e ")][@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@object="solid 1px green"][@xml:lang="en"][@xml:id="id12"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[contains(@string,"ute value")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/*[@xml:lang="en-US"][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <eta> + <epsilon and="123456789" xml:id="id1"> + <chi delete="attribute-value" xml:id="id2"/> + <sigma> + <delta xml:lang="no"> + <gamma attrib="123456789"> + <iota delete="false" xml:id="id3"> + <rho xml:lang="en-GB" xml:id="id4"/> + <any xml:id="id5"> + <eta name="content" xml:id="id6"> + <zeta desciption="_blank" xml:id="id7"> + <gamma attrib="content"> + <omicron and="true"/> + <omicron xml:lang="en-GB" xml:id="id8"> + <phi> + <chi content="attribute" xml:lang="en-GB" xml:id="id9"/> + <gamma attrib="this.nodeValue" xml:id="id10"/> + <upsilon xml:lang="no-nb"> + <nu token="attribute value" xml:lang="nb" xml:id="id11"/> + <omicron object="solid 1px green" xml:lang="en" xml:id="id12"/> + <upsilon string="another attribute value" xml:lang="no"> + <any xml:lang="en-US"> + <green>This text must be green</green> + </any> + </upsilon> + </upsilon> + </phi> + </omicron> + </gamma> + </zeta> + </eta> + </any> + </iota> + </gamma> + </delta> + </sigma> + </epsilon> + </eta> + </tree> + </test> + <test> + <xpath>//nu[@data]//beta[starts-with(@title,"attribute v")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::iota[following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@att="attribute value"][following-sibling::iota[@attribute][not(following-sibling::*)]/upsilon[starts-with(@attr,"t")][@xml:id="id1"][not(preceding-sibling::*)]//theta[contains(@title,"10")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[starts-with(concat(@title,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]/theta[contains(concat(@abort,"$"),"e$")][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@true][not(child::node())][following-sibling::beta[contains(@delete,"ue")][@xml:lang="no"]//lambda[@xml:id="id4"][not(following-sibling::*)]/xi[@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]/lambda[@true][not(following-sibling::*)]/pi[not(following-sibling::pi)]//sigma[starts-with(@object,"attribute valu")][@xml:lang="no-nb"][not(preceding-sibling::*)]/tau[@xml:lang="no-nb"][not(following-sibling::*)]//psi[@true="true"][@xml:lang="en"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <nu data="attribute-value"> + <beta title="attribute value" xml:lang="no-nb"/> + <iota/> + <kappa att="attribute value"/> + <iota attribute="true"> + <upsilon attr="this.nodeValue" xml:id="id1"> + <theta title="100%" xml:lang="en" xml:id="id2"/> + <mu title="attribute" xml:lang="en-GB" xml:id="id3"> + <theta abort="attribute value"> + <nu true="123456789"/> + <beta delete="this-is-att-value" xml:lang="no"> + <lambda xml:id="id4"> + <xi xml:lang="en-GB" xml:id="id5"> + <lambda true="_blank"> + <pi> + <sigma object="attribute value" xml:lang="no-nb"> + <tau xml:lang="no-nb"> + <psi true="true" xml:lang="en"> + <green>This text must be green</green> + </psi> + </tau> + </sigma> + </pi> + </lambda> + </xi> + </lambda> + </beta> + </theta> + </mu> + </upsilon> + </iota> + </nu> + </tree> + </test> + <test> + <xpath>//nu[@title="this-is-att-value"][@xml:id="id1"]//beta[@abort="123456789"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="no"]/upsilon[contains(@class,"fal")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//gamma[@xml:lang="en-US"][not(following-sibling::*)]/iota[@xml:id="id3"][not(child::node())][following-sibling::beta[@class][@xml:lang="nb"][following-sibling::theta[not(following-sibling::*)]/theta[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]//psi[@xml:id="id5"]/upsilon[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::zeta[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::phi[starts-with(@true,"solid ")][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[starts-with(concat(@src,"-"),"attribute value-")][not(following-sibling::*)]//zeta[contains(concat(@insert,"$"),"e$")][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <nu title="this-is-att-value" xml:id="id1"> + <beta abort="123456789" xml:lang="no-nb"/> + <phi xml:lang="no"> + <upsilon class="false" xml:lang="nb" xml:id="id2"> + <gamma xml:lang="en-US"> + <iota xml:id="id3"/> + <beta class="this-is-att-value" xml:lang="nb"/> + <theta> + <theta xml:lang="no" xml:id="id4"> + <psi xml:id="id5"> + <upsilon/> + <zeta xml:lang="no" xml:id="id6"/> + <phi true="solid 1px green" xml:lang="nb" xml:id="id7"/> + <omicron src="attribute value"> + <zeta insert="true"> + <green>This text must be green</green> + </zeta> + </omicron> + </psi> + </theta> + </theta> + </gamma> + </upsilon> + </phi> + </nu> + </tree> + </test> + <test> + <xpath>//gamma[contains(concat(@delete,"$"),"%$")][@xml:id="id1"]//alpha[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::delta[contains(concat(@attribute,"$"),"attribute$")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//tau[contains(concat(@string,"$"),"alue$")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@and][@xml:id="id5"][not(preceding-sibling::*)]/phi[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[contains(concat(@data,"$"),"e$")][not(child::node())][following-sibling::upsilon[starts-with(@title,"attribute va")][@xml:lang="nb"][not(following-sibling::*)]//nu[starts-with(concat(@or,"-"),"false-")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 2]]/epsilon[contains(concat(@src,"$"),"attribute$")][@xml:id="id8"][following-sibling::pi[contains(concat(@src,"$"),"alue$")][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::gamma[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::epsilon[@xml:lang="en-US"][preceding-sibling::*[position() = 4]]//delta[starts-with(concat(@content,"-"),"100%-")][@xml:lang="en"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::omega[contains(concat(@false,"$"),"e$")][@xml:id="id12"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="en-US"][@xml:id="id13"][preceding-sibling::*[position() = 2]][following-sibling::gamma[contains(concat(@number,"$"),"789$")][@xml:lang="nb"][@xml:id="id14"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//kappa[starts-with(@src,"attribute va")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[contains(concat(@att,"$"),"eValue$")][@xml:id="id15"][preceding-sibling::*[position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <gamma delete="100%" xml:id="id1"> + <alpha xml:lang="no-nb" xml:id="id2"/> + <delta attribute="attribute" xml:lang="no" xml:id="id3"> + <tau string="this-is-att-value" xml:lang="no" xml:id="id4"> + <psi and="this-is-att-value" xml:id="id5"> + <phi xml:id="id6"/> + <nu data="true"/> + <upsilon title="attribute value" xml:lang="nb"> + <nu or="false" xml:lang="no" xml:id="id7"/> + <beta/> + <psi> + <epsilon src="attribute" xml:id="id8"/> + <pi src="this-is-att-value" xml:id="id9"/> + <eta xml:lang="no" xml:id="id10"/> + <gamma xml:lang="en-GB"/> + <epsilon xml:lang="en-US"> + <delta content="100%" xml:lang="en" xml:id="id11"/> + <omega false="this-is-att-value" xml:id="id12"/> + <xi xml:lang="en-US" xml:id="id13"/> + <gamma number="123456789" xml:lang="nb" xml:id="id14"> + <kappa src="attribute value" xml:lang="en-US"/> + <phi att="this.nodeValue" xml:id="id15"> + <green>This text must be green</green> + </phi> + </gamma> + </epsilon> + </psi> + </upsilon> + </psi> + </tau> + </delta> + </gamma> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id1"]//rho[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[contains(@abort,"e")][not(following-sibling::*)]//delta[starts-with(concat(@desciption,"-"),"this.nodeValue-")][not(preceding-sibling::*)]/phi[@token][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@class,"$"),"789$")][@xml:id="id3"][not(child::node())][following-sibling::pi[contains(concat(@class,"$"),"e$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/kappa[not(child::node())][following-sibling::eta[@xml:id="id4"][preceding-sibling::*[position() = 1]]/psi[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[contains(concat(@class,"$"),"e$")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[not(preceding-sibling::*)][not(child::node())][following-sibling::nu[contains(concat(@attribute,"$"),"tribute-value$")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[@xml:id="id7"]/gamma[contains(concat(@att,"$"),"6789$")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@true="100%"][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)]/omicron[not(preceding-sibling::*)]/sigma[@desciption="attribute"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::sigma[@content="content"][@xml:id="id11"][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//iota[@src][@xml:lang="en-GB"][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa[@true][@xml:id="id12"][not(following-sibling::*)]/delta[@name][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <lambda att="attribute" xml:lang="en-US" xml:id="id1"> + <rho xml:lang="nb" xml:id="id2"/> + <phi abort="attribute"> + <delta desciption="this.nodeValue"> + <phi token="true" xml:lang="nb"/> + <alpha class="123456789" xml:id="id3"/> + <pi class="false" xml:lang="nb"> + <kappa/> + <eta xml:id="id4"> + <psi xml:id="id5"> + <omega class="attribute value" xml:lang="en-US"> + <eta/> + <nu attribute="attribute-value" xml:id="id6"/> + <phi xml:id="id7"> + <gamma att="123456789" xml:id="id8"> + <eta true="100%" xml:lang="nb" xml:id="id9"> + <omicron> + <sigma desciption="attribute" xml:id="id10"/> + <sigma content="content" xml:id="id11"/> + <upsilon> + <iota src="attribute" xml:lang="en-GB"/> + <phi> + <kappa true="123456789" xml:id="id12"> + <delta name="true" xml:lang="en-GB"> + <green>This text must be green</green> + </delta> + </kappa> + </phi> + </upsilon> + </omicron> + </eta> + </gamma> + </phi> + </omega> + </psi> + </eta> + </pi> + </delta> + </phi> + </lambda> + </tree> + </test> + <test> + <xpath>//lambda[@name][@xml:id="id1"]//omega[@xml:lang="no-nb"][following-sibling::psi[contains(@delete,"r attr")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@attribute][@xml:id="id2"][preceding-sibling::*[position() = 2]]/zeta[starts-with(concat(@number,"-"),"false-")][@xml:lang="en"][not(following-sibling::*)]/beta[starts-with(@abort,"100")][not(following-sibling::beta)]//chi[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::omega[following-sibling::iota[contains(@string,"lse")][@xml:lang="en"][@xml:id="id4"]/phi[@xml:id="id5"][not(following-sibling::*)]//gamma[@xml:lang="en-US"][@xml:id="id6"][following-sibling::alpha[@xml:lang="en-GB"][not(child::node())][following-sibling::psi[@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(concat(@number,"-"),"attribute-")][@xml:id="id8"]//omicron[contains(@true,"e")][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::omicron)]/mu[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omicron[contains(@desciption,"6789")][preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:id="id10"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/tau[starts-with(concat(@or,"-"),"attribute-")][@xml:lang="en-US"][not(child::node())][following-sibling::beta[position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <lambda name="attribute-value" xml:id="id1"> + <omega xml:lang="no-nb"/> + <psi delete="another attribute value" xml:lang="en-US"/> + <kappa attribute="123456789" xml:id="id2"> + <zeta number="false" xml:lang="en"> + <beta abort="100%"> + <chi xml:lang="no" xml:id="id3"/> + <omega/> + <iota string="false" xml:lang="en" xml:id="id4"> + <phi xml:id="id5"> + <gamma xml:lang="en-US" xml:id="id6"/> + <alpha xml:lang="en-GB"/> + <psi xml:id="id7"/> + <upsilon number="attribute" xml:id="id8"> + <omicron true="attribute-value" xml:lang="en" xml:id="id9"> + <mu/> + <omicron desciption="123456789"/> + <kappa xml:id="id10"> + <tau or="attribute" xml:lang="en-US"/> + <beta> + <green>This text must be green</green> + </beta> + </kappa> + </omicron> + </upsilon> + </phi> + </iota> + </beta> + </zeta> + </kappa> + </lambda> + </tree> + </test> + <test> + <xpath>//lambda[@xml:id="id1"]/beta[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::zeta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@att][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho[@name][@xml:id="id5"][preceding-sibling::*[position() = 3]]//pi[@xml:id="id6"]/gamma[starts-with(concat(@false,"-"),"attribute-")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[starts-with(@abort,"_bl")][@xml:lang="en"][@xml:id="id7"][following-sibling::gamma[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(@title,"solid 1px ")][@xml:id="id9"]//zeta[not(child::node())][following-sibling::zeta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[starts-with(@abort,"this")][@xml:lang="no-nb"][following-sibling::*[position()=3]][following-sibling::eta[@attr="attribute"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[preceding-sibling::*[position() = 4]][following-sibling::gamma[@desciption][@xml:lang="no"][preceding-sibling::*[position() = 5]][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:id="id1"> + <beta attr="attribute" xml:lang="nb" xml:id="id2"/> + <zeta xml:lang="no-nb"> + <chi xml:id="id3"/> + <phi xml:lang="no-nb" xml:id="id4"/> + <any att="false"/> + <rho name="true" xml:id="id5"> + <pi xml:id="id6"> + <gamma false="attribute-value" xml:lang="en"/> + <delta abort="_blank" xml:lang="en" xml:id="id7"/> + <gamma> + <omega xml:lang="en-GB" xml:id="id8"/> + <sigma title="solid 1px green" xml:id="id9"> + <zeta/> + <zeta xml:lang="en-US"/> + <lambda abort="this.nodeValue" xml:lang="no-nb"/> + <eta attr="attribute"/> + <epsilon/> + <gamma desciption="true" xml:lang="no"> + <green>This text must be green</green> + </gamma> + </sigma> + </gamma> + </pi> + </rho> + </zeta> + </lambda> + </tree> + </test> + <test> + <xpath>//tau[starts-with(concat(@desciption,"-"),"100%-")][@xml:lang="no"]/phi[@xml:lang="en"][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id1"][following-sibling::sigma[starts-with(concat(@or,"-"),"true-")][@xml:lang="en"][@xml:id="id2"]/pi[@insert="123456789"][@xml:lang="no-nb"][not(following-sibling::*)]//pi[@att][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::zeta[preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:lang="en"][preceding-sibling::*[position() = 2]]/lambda[@name][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <tau desciption="100%" xml:lang="no"> + <phi xml:lang="en"/> + <omicron xml:lang="en-US" xml:id="id1"/> + <sigma or="true" xml:lang="en" xml:id="id2"> + <pi insert="123456789" xml:lang="no-nb"> + <pi att="attribute" xml:lang="en"/> + <zeta/> + <phi xml:lang="en"> + <lambda name="true" xml:lang="no" xml:id="id3"> + <green>This text must be green</green> + </lambda> + </phi> + </pi> + </sigma> + </tau> + </tree> + </test> + <test> + <xpath>//phi//delta[starts-with(@data,"_bl")][not(preceding-sibling::*)][not(following-sibling::*)]/phi[contains(concat(@class,"$"),"id 1px green$")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[starts-with(@class,"fa")][@xml:id="id2"][not(following-sibling::*)]//beta[contains(concat(@class,"$"),"ribute$")][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[starts-with(concat(@insert,"-"),"true-")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="nb"][not(child::node())][following-sibling::theta[@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/chi[starts-with(@number,"10")][@xml:lang="en"][not(preceding-sibling::*)]//delta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[starts-with(concat(@title,"-"),"true-")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]/nu[contains(concat(@data,"$"),"odeValue$")][@xml:lang="no-nb"][not(following-sibling::*)]/upsilon[@xml:lang="en-US"]/phi[contains(@title,"odeV")][@xml:id="id7"][not(preceding-sibling::*)]//phi[starts-with(concat(@delete,"-"),"content-")][not(preceding-sibling::*)]/omega[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:lang="no"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::eta[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]/mu[@xml:id="id9"]/gamma[contains(concat(@att,"$"),"ank$")][@xml:id="id10"][not(following-sibling::*)]//sigma[@attrib][@xml:id="id11"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(@content,"tr")][@xml:lang="en"][not(following-sibling::*)]//chi[@xml:lang="en"][not(preceding-sibling::*)][not(preceding-sibling::chi)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <delta data="_blank"> + <phi class="solid 1px green" xml:id="id1"> + <nu class="false" xml:id="id2"> + <beta class="attribute"/> + <xi insert="true" xml:lang="en" xml:id="id3"/> + <xi xml:lang="nb"/> + <theta xml:id="id4"> + <chi number="100%" xml:lang="en"> + <delta xml:lang="en-GB" xml:id="id5"> + <rho title="true" xml:lang="nb" xml:id="id6"> + <nu data="this.nodeValue" xml:lang="no-nb"> + <upsilon xml:lang="en-US"> + <phi title="this.nodeValue" xml:id="id7"> + <phi delete="content"> + <omega xml:lang="no-nb"/> + <epsilon xml:lang="no" xml:id="id8"/> + <eta xml:lang="en-US"> + <mu xml:id="id9"> + <gamma att="_blank" xml:id="id10"> + <sigma attrib="solid 1px green" xml:id="id11"/> + <delta content="true" xml:lang="en"> + <chi xml:lang="en"> + <green>This text must be green</green> + </chi> + </delta> + </gamma> + </mu> + </eta> + </phi> + </phi> + </upsilon> + </nu> + </rho> + </delta> + </chi> + </theta> + </nu> + </phi> + </delta> + </phi> + </tree> + </test> + <test> + <xpath>//gamma[@and][@xml:lang="en-US"][@xml:id="id1"]//delta[@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[@xml:lang="en"][not(following-sibling::*)]/delta[contains(@data,"is.no")][@xml:id="id3"][not(preceding-sibling::*)]/eta[starts-with(@name,"this.node")][@xml:id="id4"]//*[starts-with(concat(@content,"-"),"this.nodeValue-")][not(following-sibling::*)]/rho[@string="solid 1px green"][@xml:lang="en-US"][following-sibling::*[position()=1]][not(preceding-sibling::rho)][following-sibling::epsilon[contains(@token,"attribute")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[@xml:lang="en-US"][not(preceding-sibling::*)]//sigma[@abort][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <gamma and="this.nodeValue" xml:lang="en-US" xml:id="id1"> + <delta xml:lang="en" xml:id="id2"/> + <kappa xml:lang="en"> + <delta data="this.nodeValue" xml:id="id3"> + <eta name="this.nodeValue" xml:id="id4"> + <any content="this.nodeValue"> + <rho string="solid 1px green" xml:lang="en-US"/> + <epsilon token="another attribute value" xml:lang="nb"> + <lambda xml:lang="en-US"> + <sigma abort="_blank"> + <green>This text must be green</green> + </sigma> + </lambda> + </epsilon> + </any> + </eta> + </delta> + </kappa> + </gamma> + </tree> + </test> + <test> + <xpath>//theta[@or][@xml:lang="nb"]//lambda[@src][@xml:id="id1"]/omega[contains(concat(@abort,"$"),"olid 1px green$")][@xml:lang="en"]/epsilon[not(preceding-sibling::*)][following-sibling::omega[contains(concat(@class,"$"),"ute-value$")][preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:id="id2"][not(following-sibling::*)]/rho[@xml:lang="no-nb"][not(preceding-sibling::*)][not(preceding-sibling::rho)]/tau[@true][following-sibling::beta[not(child::node())][following-sibling::iota[starts-with(concat(@object,"-"),"100%-")][@xml:lang="no"][not(following-sibling::*)]//nu[@attrib][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::iota//omicron[@title][not(following-sibling::*)]//*[@xml:id="id4"][not(preceding-sibling::*)][not(preceding-sibling::any)]//psi[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::zeta[preceding-sibling::*[position() = 1]]/mu[@string][@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]/rho[@xml:id="id7"][not(child::node())][following-sibling::*[not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <theta or="another attribute value" xml:lang="nb"> + <lambda src="100%" xml:id="id1"> + <omega abort="solid 1px green" xml:lang="en"> + <epsilon/> + <omega class="attribute-value"/> + <iota xml:id="id2"> + <rho xml:lang="no-nb"> + <tau true="content"/> + <beta/> + <iota object="100%" xml:lang="no"> + <nu attrib="false" xml:id="id3"/> + <iota> + <omicron title="_blank"> + <any xml:id="id4"> + <psi xml:lang="nb" xml:id="id5"/> + <zeta> + <mu string="attribute" xml:lang="en-GB" xml:id="id6"> + <rho xml:id="id7"/> + <any/> + <beta> + <green>This text must be green</green> + </beta> + </mu> + </zeta> + </any> + </omicron> + </iota> + </iota> + </rho> + </iota> + </omega> + </lambda> + </theta> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no"][@xml:id="id1"]//iota[contains(@true,"eVal")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::tau[@or][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::zeta[@token][@xml:lang="no"][following-sibling::upsilon[@false][@xml:id="id3"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//pi[@xml:id="id4"][not(preceding-sibling::*)][not(preceding-sibling::pi)]//phi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::lambda[@xml:id="id5"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no" xml:id="id1"> + <iota true="this.nodeValue" xml:lang="nb"/> + <tau or="_blank" xml:id="id2"/> + <omega/> + <zeta token="attribute-value" xml:lang="no"/> + <upsilon false="another attribute value" xml:id="id3"> + <pi xml:id="id4"> + <phi xml:lang="en"/> + <lambda xml:id="id5"> + <green>This text must be green</green> + </lambda> + </pi> + </upsilon> + </beta> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="en-US"]//psi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@token][@xml:lang="en-US"][not(following-sibling::*)]/rho[not(preceding-sibling::rho)][following-sibling::epsilon[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omicron[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[contains(concat(@and,"$"),"ntent$")][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@xml:lang="no-nb"]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="en-US"> + <psi xml:lang="no-nb"> + <chi token="_blank" xml:lang="en-US"> + <rho/> + <epsilon xml:id="id1"> + <omicron xml:lang="en-US"> + <eta and="content" xml:id="id2"/> + <zeta xml:lang="no-nb"> + <green>This text must be green</green> + </zeta> + </omicron> + </epsilon> + </chi> + </psi> + </zeta> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="nb"]/delta[not(child::node())][following-sibling::gamma[contains(@attr,"tt")][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/pi[contains(concat(@delete,"$"),"te$")][@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]/kappa[contains(@string,"t")][@xml:id="id4"][not(following-sibling::kappa)]/chi[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="nb"][@xml:id="id6"]/chi[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@att][@xml:lang="en"][not(preceding-sibling::psi or following-sibling::psi)][not(child::node())][following-sibling::upsilon[starts-with(concat(@title,"-"),"this-")][@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::*[@number="solid 1px green"][@xml:lang="no-nb"][@xml:id="id9"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::kappa[@name][preceding-sibling::*[position() = 3]][following-sibling::alpha[@content="attribute value"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//omega[contains(concat(@attribute,"$"),"ibute$")][@xml:lang="en-US"][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@object][@xml:lang="en-US"][@xml:id="id11"][preceding-sibling::*[position() = 1]]/sigma[@xml:lang="en-US"][@xml:id="id12"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::epsilon[@abort]//*[contains(concat(@or,"$"),"blank$")][@xml:lang="no-nb"][@xml:id="id13"][not(preceding-sibling::*)][following-sibling::kappa[@xml:lang="nb"][@xml:id="id14"][not(child::node())][following-sibling::beta[@att][@xml:lang="en-US"][@xml:id="id15"][following-sibling::tau[@xml:lang="no-nb"][@xml:id="id16"][preceding-sibling::*[position() = 3]][following-sibling::omega[@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="nb"> + <delta/> + <gamma attr="attribute-value" xml:id="id1"/> + <theta xml:id="id2"> + <pi delete="attribute" xml:lang="en-GB" xml:id="id3"> + <kappa string="attribute" xml:id="id4"> + <chi xml:lang="no-nb" xml:id="id5"/> + <sigma xml:lang="nb" xml:id="id6"> + <chi/> + <eta xml:id="id7"> + <psi att="100%" xml:lang="en"/> + <upsilon title="this-is-att-value" xml:lang="en-US" xml:id="id8"/> + <any number="solid 1px green" xml:lang="no-nb" xml:id="id9"/> + <kappa name="this.nodeValue"/> + <alpha content="attribute value"> + <omega attribute="attribute" xml:lang="en-US" xml:id="id10"/> + <sigma object="attribute-value" xml:lang="en-US" xml:id="id11"> + <sigma xml:lang="en-US" xml:id="id12"/> + <epsilon abort="this.nodeValue"> + <any or="_blank" xml:lang="no-nb" xml:id="id13"/> + <kappa xml:lang="nb" xml:id="id14"/> + <beta att="another attribute value" xml:lang="en-US" xml:id="id15"/> + <tau xml:lang="no-nb" xml:id="id16"/> + <omega xml:lang="nb"> + <green>This text must be green</green> + </omega> + </epsilon> + </sigma> + </alpha> + </eta> + </sigma> + </kappa> + </pi> + </theta> + </epsilon> + </tree> + </test> + <test> + <xpath>//rho[starts-with(@attrib,"a")][@xml:lang="no"]/tau[contains(@attr,"se")][not(child::node())][following-sibling::kappa[@xml:id="id1"]//pi[starts-with(@false,"this-is-att-valu")]/rho[not(following-sibling::*)]//eta[@attrib="attribute value"][not(preceding-sibling::*)][following-sibling::psi[@number="attribute value"][@xml:lang="en-US"][not(following-sibling::*)]//epsilon[@data="attribute"][@xml:lang="en-US"][@xml:id="id2"][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 1]]//theta[@att="100%"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="no-nb"][@xml:id="id4"]/omicron[not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[contains(@insert,"ibute")][preceding-sibling::*[position() = 1]]/omicron[contains(concat(@and,"$"),"e$")][@xml:lang="no-nb"][not(child::node())][following-sibling::*[starts-with(@attribute,"t")]/tau[starts-with(concat(@object,"-"),"attribute-")][@xml:lang="no-nb"][not(child::node())][following-sibling::psi[@xml:lang="en-US"][following-sibling::kappa[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//gamma[not(following-sibling::*)]//phi[@xml:lang="en-GB"][@xml:id="id5"]//upsilon[starts-with(@attr,"10")][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::eta[preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:id="id7"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <rho attrib="attribute" xml:lang="no"> + <tau attr="false"/> + <kappa xml:id="id1"> + <pi false="this-is-att-value"> + <rho> + <eta attrib="attribute value"/> + <psi number="attribute value" xml:lang="en-US"> + <epsilon data="attribute" xml:lang="en-US" xml:id="id2"/> + <beta xml:id="id3"> + <theta att="100%" xml:lang="no-nb"> + <delta xml:lang="no-nb" xml:id="id4"> + <omicron/> + <zeta insert="attribute"> + <omicron and="false" xml:lang="no-nb"/> + <any attribute="true"> + <tau object="attribute-value" xml:lang="no-nb"/> + <psi xml:lang="en-US"/> + <kappa xml:lang="en-GB"> + <gamma> + <phi xml:lang="en-GB" xml:id="id5"> + <upsilon attr="100%" xml:id="id6"/> + <eta/> + <omega xml:id="id7"> + <green>This text must be green</green> + </omega> + </phi> + </gamma> + </kappa> + </any> + </zeta> + </delta> + </theta> + </beta> + </psi> + </rho> + </pi> + </kappa> + </rho> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="no-nb"]/rho[@xml:lang="en-US"][not(preceding-sibling::*)]/omega[@xml:lang="en-US"][@xml:id="id1"][following-sibling::theta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@xml:lang="no"][@xml:id="id3"][following-sibling::theta[not(following-sibling::*)]/omega[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[starts-with(@abort,"attribute-valu")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::pi[starts-with(@att,"_")][@xml:id="id4"][following-sibling::xi[starts-with(@number,"at")][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[@data="attribute value"][@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="en-GB"][not(following-sibling::*)]//mu[following-sibling::gamma[starts-with(concat(@insert,"-"),"attribute-")][@xml:lang="no-nb"]/nu[@xml:id="id6"][not(preceding-sibling::*)]//kappa[@delete="_blank"][@xml:lang="nb"][@xml:id="id7"]/iota[@false][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::gamma[contains(concat(@attr,"$"),"lank$")][following-sibling::phi[@xml:id="id9"][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="no-nb"> + <rho xml:lang="en-US"> + <omega xml:lang="en-US" xml:id="id1"/> + <theta xml:id="id2"/> + <kappa xml:lang="no" xml:id="id3"/> + <theta> + <omega xml:lang="en-GB"> + <iota abort="attribute-value" xml:lang="nb"/> + <pi att="_blank" xml:id="id4"/> + <xi number="attribute" xml:id="id5"/> + <iota data="attribute value" xml:lang="nb"/> + <psi xml:lang="en-GB"> + <mu/> + <gamma insert="attribute" xml:lang="no-nb"> + <nu xml:id="id6"> + <kappa delete="_blank" xml:lang="nb" xml:id="id7"> + <iota false="content" xml:lang="en" xml:id="id8"/> + <gamma attr="_blank"/> + <phi xml:id="id9"> + <green>This text must be green</green> + </phi> + </kappa> + </nu> + </gamma> + </psi> + </omega> + </theta> + </rho> + </omicron> + </tree> + </test> + <test> + <xpath>//mu[@insert][@xml:lang="en-US"]/kappa[@xml:lang="en-GB"][not(following-sibling::*)]/beta[@attr][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@delete="this-is-att-value"][@xml:id="id1"][preceding-sibling::*[position() = 1]]/zeta[contains(@or,"th")][@xml:id="id2"][not(following-sibling::*)]//gamma[@token][@xml:id="id3"][not(following-sibling::*)]/beta[@token][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::gamma[@name="attribute-value"][@xml:id="id4"][not(child::node())][following-sibling::delta[@false][@xml:lang="no-nb"][not(child::node())][following-sibling::phi[contains(@src,"tribute valu")][@xml:id="id5"][not(following-sibling::*)]/zeta[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[following-sibling::upsilon[@attr][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//mu[starts-with(concat(@attr,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <mu insert="100%" xml:lang="en-US"> + <kappa xml:lang="en-GB"> + <beta attr="this.nodeValue"/> + <epsilon delete="this-is-att-value" xml:id="id1"> + <zeta or="this.nodeValue" xml:id="id2"> + <gamma token="attribute-value" xml:id="id3"> + <beta token="100%" xml:lang="nb"/> + <gamma name="attribute-value" xml:id="id4"/> + <delta false="this.nodeValue" xml:lang="no-nb"/> + <phi src="attribute value" xml:id="id5"> + <zeta xml:id="id6"> + <kappa/> + <upsilon attr="_blank"/> + <zeta xml:lang="en-US"> + <mu attr="123456789" xml:lang="en-US" xml:id="id7"> + <green>This text must be green</green> + </mu> + </zeta> + </zeta> + </phi> + </gamma> + </zeta> + </epsilon> + </kappa> + </mu> + </tree> + </test> + <test> + <xpath>//rho[contains(concat(@false,"$"),"e$")][@xml:id="id1"]/epsilon[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]//beta[@false="123456789"][@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/kappa//sigma[not(child::node())][following-sibling::nu[contains(@abort,"0%")][preceding-sibling::*[position() = 1]]/delta[@xml:id="id4"][not(following-sibling::*)]//upsilon[contains(concat(@attribute,"$"),"nt$")][@xml:lang="en-US"][not(preceding-sibling::*)]//delta[@xml:lang="nb"][following-sibling::*[starts-with(concat(@string,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[@insert][@xml:id="id5"]//iota[@false][@xml:lang="no"][following-sibling::xi[contains(concat(@string,"$"),"nk$")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[contains(concat(@true,"$")," green$")][@xml:lang="no-nb"][@xml:id="id7"][not(child::node())][following-sibling::rho[@string][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][following-sibling::xi[preceding-sibling::*[position() = 4]]//psi[not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::psi)]/omicron[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::chi[starts-with(@abort,"another attribute valu")][@xml:lang="en"][not(following-sibling::*)]/kappa[@attribute][@xml:lang="nb"][@xml:id="id9"][not(child::node())][following-sibling::beta[@name][@xml:lang="en-GB"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[@xml:id="id11"]/lambda[@attr][@xml:lang="no"][@xml:id="id12"][not(preceding-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <rho false="false" xml:id="id1"> + <epsilon xml:lang="en" xml:id="id2"> + <beta false="123456789" xml:lang="en" xml:id="id3"> + <kappa> + <sigma/> + <nu abort="100%"> + <delta xml:id="id4"> + <upsilon attribute="content" xml:lang="en-US"> + <delta xml:lang="nb"/> + <any string="solid 1px green"/> + <chi insert="another attribute value" xml:id="id5"> + <iota false="100%" xml:lang="no"/> + <xi string="_blank" xml:id="id6"/> + <eta true="solid 1px green" xml:lang="no-nb" xml:id="id7"/> + <rho string="_blank" xml:lang="no-nb"/> + <xi> + <psi> + <omicron xml:lang="en-GB" xml:id="id8"/> + <chi abort="another attribute value" xml:lang="en"> + <kappa attribute="another attribute value" xml:lang="nb" xml:id="id9"/> + <beta name="attribute-value" xml:lang="en-GB" xml:id="id10"> + <xi xml:id="id11"> + <lambda attr="content" xml:lang="no" xml:id="id12"> + <green>This text must be green</green> + </lambda> + </xi> + </beta> + </chi> + </psi> + </xi> + </chi> + </upsilon> + </delta> + </nu> + </kappa> + </beta> + </epsilon> + </rho> + </tree> + </test> + <test> + <xpath>//xi[@abort="attribute value"][@xml:id="id1"]/xi[@and][following-sibling::*[position()=1]][following-sibling::omega[@attrib][@xml:lang="en"][@xml:id="id2"]//omega[@attr][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[contains(@number,"is-att-value")][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 1]][following-sibling::gamma[starts-with(concat(@attrib,"-"),"another attribute value-")]/omega[@xml:lang="en-US"][following-sibling::tau[contains(@desciption,"attribute-value")][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[@insert][@xml:id="id4"][not(following-sibling::*)]/pi[@name="this-is-att-value"][@xml:id="id5"][not(following-sibling::*)]//kappa[contains(concat(@src,"$"),"is-att-value$")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[contains(@src,"%")][@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//zeta[@xml:id="id7"]//nu[starts-with(@attr,"fal")][@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]/omega[starts-with(concat(@delete,"-"),"attribute value-")][@xml:lang="nb"]//epsilon[@xml:lang="en-GB"][not(preceding-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>1</nth> + </result> + <tree> + <xi abort="attribute value" xml:id="id1"> + <xi and="100%"/> + <omega attrib="another attribute value" xml:lang="en" xml:id="id2"> + <omega attr="solid 1px green" xml:lang="nb"/> + <chi> + <nu number="this-is-att-value"/> + <phi/> + <gamma attrib="another attribute value"> + <omega xml:lang="en-US"/> + <tau desciption="attribute-value" xml:id="id3"/> + <delta insert="this.nodeValue" xml:id="id4"> + <pi name="this-is-att-value" xml:id="id5"> + <kappa src="this-is-att-value" xml:lang="no"> + <omicron src="100%" xml:lang="en-US" xml:id="id6"> + <zeta xml:id="id7"> + <nu attr="false" xml:lang="no" xml:id="id8"> + <omega delete="attribute value" xml:lang="nb"> + <epsilon xml:lang="en-GB"> + <green>This text must be green</green> + </epsilon> + </omega> + </nu> + </zeta> + </omicron> + </kappa> + </pi> + </delta> + </gamma> + </chi> + </omega> + </xi> + </tree> + </test> + <test> + <xpath>//delta[starts-with(@delete,"this.n")][@xml:lang="en"]//eta[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::zeta[following-sibling::zeta[contains(concat(@insert,"$"),"tribute-value$")][@xml:lang="en-GB"][@xml:id="id2"]//xi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@attr][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][not(child::node())][following-sibling::lambda[starts-with(@number,"10")][@xml:id="id3"][following-sibling::*[position()=4]][following-sibling::gamma[@class="content"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::kappa[contains(concat(@token,"$"),"bute-value$")][preceding-sibling::*[position() = 4]][following-sibling::*[position()=2]][following-sibling::theta[@title="attribute-value"][@xml:lang="nb"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::zeta[@delete]/sigma[starts-with(concat(@object,"-"),"123456789-")][not(preceding-sibling::*)][following-sibling::beta[contains(@att,"this-is-att-")][not(following-sibling::*)]/*[starts-with(concat(@content,"-"),"false-")][@xml:lang="no-nb"][not(child::node())][following-sibling::tau[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::omicron[contains(concat(@false,"$"),"23456789$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <delta delete="this.nodeValue" xml:lang="en"> + <eta xml:lang="en" xml:id="id1"/> + <zeta/> + <zeta insert="attribute-value" xml:lang="en-GB" xml:id="id2"> + <xi xml:lang="no-nb"/> + <epsilon attr="attribute-value" xml:lang="en-GB"/> + <lambda number="100%" xml:id="id3"/> + <gamma class="content" xml:id="id4"/> + <kappa token="attribute-value"/> + <theta title="attribute-value" xml:lang="nb"/> + <zeta delete="this-is-att-value"> + <sigma object="123456789"/> + <beta att="this-is-att-value"> + <any content="false" xml:lang="no-nb"/> + <tau xml:lang="en-US" xml:id="id5"/> + <omicron false="123456789"> + <green>This text must be green</green> + </omicron> + </beta> + </zeta> + </zeta> + </delta> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@and,"123456")][@xml:lang="en-US"]//alpha[@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]//sigma[@token="attribute value"][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::beta[@and="another attribute value"][@xml:id="id3"][following-sibling::psi[@attribute][@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::epsilon[contains(concat(@object,"$"),"lank$")][@xml:lang="no"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/psi[@xml:lang="en-GB"][@xml:id="id5"]/theta[@xml:lang="no-nb"][not(preceding-sibling::*)]/eta[contains(@attribute,"id 1px green")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::nu[@or][@xml:id="id6"][not(child::node())][following-sibling::nu[following-sibling::*[position()=2]][following-sibling::omicron[@xml:lang="no"][following-sibling::pi[@xml:lang="en"]/chi[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//*[@xml:lang="en-GB"][following-sibling::alpha[@xml:id="id8"][preceding-sibling::*[position() = 1]]//omicron[@content][not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 2]]//*[contains(@title,"tribute val")][@xml:lang="en-US"][not(following-sibling::*)]//delta[@xml:id="id9"][not(preceding-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omega and="123456789" xml:lang="en-US"> + <alpha xml:lang="en-GB" xml:id="id1"> + <sigma token="attribute value" xml:lang="en" xml:id="id2"/> + <gamma xml:lang="no"/> + <beta and="another attribute value" xml:id="id3"/> + <psi attribute="true" xml:lang="en-US" xml:id="id4"/> + <epsilon object="_blank" xml:lang="no"> + <psi xml:lang="en-GB" xml:id="id5"> + <theta xml:lang="no-nb"> + <eta attribute="solid 1px green" xml:lang="no-nb"/> + <nu or="123456789" xml:id="id6"/> + <nu/> + <omicron xml:lang="no"/> + <pi xml:lang="en"> + <chi xml:id="id7"> + <any xml:lang="en-GB"/> + <alpha xml:id="id8"> + <omicron content="100%"/> + <omicron/> + <alpha> + <any title="another attribute value" xml:lang="en-US"> + <delta xml:id="id9"> + <green>This text must be green</green> + </delta> + </any> + </alpha> + </alpha> + </chi> + </pi> + </theta> + </psi> + </epsilon> + </alpha> + </omega> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/kappa[@xml:lang="nb"][@xml:id="id2"][following-sibling::xi//theta[@src][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::mu[contains(@att,"blan")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::pi[contains(@or,"r attribute va")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//gamma[contains(@delete,"nodeValue")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[following-sibling::kappa[contains(@src,"tent")][@xml:id="id6"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <kappa xml:lang="nb" xml:id="id2"/> + <xi> + <theta src="attribute"/> + <rho xml:lang="no-nb" xml:id="id3"/> + <mu att="_blank"/> + <pi or="another attribute value"> + <gamma delete="this.nodeValue" xml:id="id4"/> + <pi xml:id="id5"/> + <alpha/> + <kappa src="content" xml:id="id6"> + <green>This text must be green</green> + </kappa> + </pi> + </xi> + </nu> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]/omega[starts-with(concat(@attrib,"-"),"true-")][@xml:id="id2"][not(preceding-sibling::*)]/gamma[not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:id="id3"][preceding-sibling::*[position() = 1]]//chi[@xml:lang="en"][not(child::node())][following-sibling::xi[@desciption][@xml:lang="no"][following-sibling::rho[@xml:id="id4"]//beta[not(preceding-sibling::*)][following-sibling::epsilon[@class][@xml:id="id5"][not(following-sibling::*)]//xi[@data][@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)]/omicron[@xml:id="id7"][following-sibling::beta[@data][@xml:id="id8"][not(following-sibling::*)]/alpha[starts-with(@insert,"cont")]//chi[contains(concat(@or,"$"),"n$")][not(preceding-sibling::chi)][not(child::node())][following-sibling::lambda[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:id="id9"][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id10"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::iota[@xml:lang="no"][@xml:id="id11"][following-sibling::iota[@xml:lang="en-GB"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]/kappa[@xml:lang="no"][@xml:id="id12"][following-sibling::mu[starts-with(concat(@delete,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id13"][not(following-sibling::*)]]][position() = 1]]]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <omega attrib="true" xml:id="id2"> + <gamma/> + <theta xml:id="id3"> + <chi xml:lang="en"/> + <xi desciption="true" xml:lang="no"/> + <rho xml:id="id4"> + <beta/> + <epsilon class="this-is-att-value" xml:id="id5"> + <xi data="123456789" xml:lang="no-nb" xml:id="id6"> + <omicron xml:id="id7"/> + <beta data="attribute" xml:id="id8"> + <alpha insert="content"> + <chi or="solid 1px green"/> + <lambda xml:lang="no-nb"/> + <sigma xml:id="id9"/> + <rho xml:lang="en-GB" xml:id="id10"/> + <iota xml:lang="no" xml:id="id11"/> + <iota xml:lang="en-GB"> + <kappa xml:lang="no" xml:id="id12"/> + <mu delete="attribute-value" xml:lang="en-US" xml:id="id13"> + <green>This text must be green</green> + </mu> + </iota> + </alpha> + </beta> + </xi> + </epsilon> + </rho> + </theta> + </omega> + </iota> + </tree> + </test> + <test> + <xpath>//nu/mu[contains(@true,"tribute")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[starts-with(concat(@attr,"-"),"attribute value-")][@xml:lang="no-nb"][not(child::node())][following-sibling::tau[starts-with(@object,"content")][not(following-sibling::*)]/nu[@name][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::epsilon[starts-with(@attrib,"this.n")][@xml:id="id2"][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <nu> + <mu true="attribute" xml:lang="en-US"> + <upsilon attr="attribute value" xml:lang="no-nb"/> + <tau object="content"> + <nu name="_blank" xml:lang="en-US" xml:id="id1"/> + <epsilon attrib="this.nodeValue" xml:id="id2"> + <green>This text must be green</green> + </epsilon> + </tau> + </mu> + </nu> + </tree> + </test> + <test> + <xpath>//kappa[@src][@xml:lang="no-nb"]/upsilon[@xml:lang="nb"]//xi[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@src][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/beta[not(child::node())][following-sibling::nu[@object][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::nu/nu[@desciption][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::beta[@xml:lang="en-GB"][@xml:id="id4"]/omicron[@data][not(following-sibling::*)]/gamma[@xml:lang="no-nb"][not(preceding-sibling::*)]/zeta[@att][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@number="another attribute value"][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::epsilon[following-sibling::*[contains(concat(@true,"$"),"r attribute value$")][@xml:id="id5"][not(following-sibling::*)]]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <kappa src="true" xml:lang="no-nb"> + <upsilon xml:lang="nb"> + <xi xml:id="id1"/> + <eta src="another attribute value"/> + <delta xml:lang="en"> + <beta/> + <nu object="false" xml:id="id2"/> + <nu> + <nu desciption="this.nodeValue" xml:id="id3"/> + <beta xml:lang="en-GB" xml:id="id4"> + <omicron data="content"> + <gamma xml:lang="no-nb"> + <zeta att="123456789" xml:lang="en-US"/> + <mu number="another attribute value" xml:lang="no"/> + <epsilon/> + <any true="another attribute value" xml:id="id5"> + <green>This text must be green</green> + </any> + </gamma> + </omicron> + </beta> + </nu> + </delta> + </upsilon> + </kappa> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(@data,"cont")][@xml:lang="nb"][@xml:id="id1"]//*[@xml:lang="en-GB"][following-sibling::rho[@xml:lang="en-GB"][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::epsilon[@xml:id="id2"][not(following-sibling::*)]/theta[starts-with(@object,"solid ")][@xml:id="id3"][not(preceding-sibling::*)]//rho[starts-with(@att,"this-is-att-val")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::nu[@xml:id="id5"]//xi[@xml:id="id6"][not(following-sibling::*)]//phi[contains(@content,"e")][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@src="false"][@xml:id="id7"][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@xml:lang="nb"][@xml:id="id8"][following-sibling::sigma[starts-with(concat(@false,"-"),"content-")][@xml:id="id9"][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <epsilon data="content" xml:lang="nb" xml:id="id1"> + <any xml:lang="en-GB"/> + <rho xml:lang="en-GB"/> + <omega/> + <epsilon xml:id="id2"> + <theta object="solid 1px green" xml:id="id3"> + <rho att="this-is-att-value" xml:lang="en-GB" xml:id="id4"/> + <nu xml:id="id5"> + <xi xml:id="id6"> + <phi content="this.nodeValue"/> + <chi src="false" xml:id="id7"/> + <any xml:lang="nb" xml:id="id8"/> + <sigma false="content" xml:id="id9"> + <green>This text must be green</green> + </sigma> + </xi> + </nu> + </theta> + </epsilon> + </epsilon> + </tree> + </test> + <test> + <xpath>//omicron[@src][@xml:id="id1"]//epsilon[@xml:id="id2"][not(following-sibling::*)]//sigma[starts-with(concat(@attribute,"-"),"123456789-")][following-sibling::*[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:id="id4"][preceding-sibling::*[position() = 3]]//pi[@data]//alpha[@xml:id="id5"][not(child::node())][following-sibling::chi[following-sibling::omicron[preceding-sibling::*[position() = 2]][not(following-sibling::*)]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omicron src="content" xml:id="id1"> + <epsilon xml:id="id2"> + <sigma attribute="123456789"/> + <any xml:id="id3"> + <psi/> + <omicron/> + <nu xml:lang="no-nb"/> + <phi xml:id="id4"> + <pi data="another attribute value"> + <alpha xml:id="id5"/> + <chi/> + <omicron> + <green>This text must be green</green> + </omicron> + </pi> + </phi> + </any> + </epsilon> + </omicron> + </tree> + </test> + <test> + <xpath>//tau[@xml:id="id1"]/theta[starts-with(concat(@delete,"-"),"_blank-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[contains(@true,"%")][preceding-sibling::*[position() = 1]]//lambda[@xml:lang="nb"][not(preceding-sibling::*)]//zeta[starts-with(concat(@and,"-"),"another attribute value-")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::kappa[@class="attribute-value"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omicron[@class="attribute-value"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/phi[@insert][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)]//phi[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[contains(@title,"ttribute")][@xml:lang="en"][not(child::node())][following-sibling::xi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//tau[following-sibling::kappa[@xml:id="id6"][preceding-sibling::*[position() = 1]]//mu[starts-with(concat(@abort,"-"),"attribute-")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[contains(@delete,"lid ")][@xml:id="id7"][not(preceding-sibling::*)]//nu[@xml:id="id8"][not(preceding-sibling::*)][following-sibling::rho[@xml:lang="nb"][@xml:id="id9"]/zeta[@desciption][@xml:id="id10"]//omicron[@title][@xml:lang="no-nb"][@xml:id="id11"][following-sibling::eta[contains(@string,"solid 1")][@xml:lang="no"][@xml:id="id12"]/iota[starts-with(concat(@token,"-"),"attribute value-")][not(child::node())][following-sibling::gamma[starts-with(concat(@object,"-"),"true-")][@xml:lang="en-GB"][@xml:id="id13"][not(following-sibling::*)]/lambda[contains(@attr,"ent")][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:id="id1"> + <theta delete="_blank" xml:lang="en-GB"/> + <tau true="100%"> + <lambda xml:lang="nb"> + <zeta and="another attribute value" xml:lang="no"/> + <kappa class="attribute-value"/> + <omicron class="attribute-value" xml:id="id2"> + <phi insert="attribute-value" xml:lang="nb" xml:id="id3"> + <phi xml:lang="no" xml:id="id4"> + <eta title="another attribute value" xml:lang="en"/> + <xi xml:id="id5"> + <tau/> + <kappa xml:id="id6"> + <mu abort="attribute-value" xml:lang="en-US"> + <omega delete="solid 1px green" xml:id="id7"> + <nu xml:id="id8"/> + <rho xml:lang="nb" xml:id="id9"> + <zeta desciption="100%" xml:id="id10"> + <omicron title="attribute value" xml:lang="no-nb" xml:id="id11"/> + <eta string="solid 1px green" xml:lang="no" xml:id="id12"> + <iota token="attribute value"/> + <gamma object="true" xml:lang="en-GB" xml:id="id13"> + <lambda attr="content"> + <green>This text must be green</green> + </lambda> + </gamma> + </eta> + </zeta> + </rho> + </omega> + </mu> + </kappa> + </xi> + </phi> + </phi> + </omicron> + </lambda> + </tau> + </tau> + </tree> + </test> + <test> + <xpath>//zeta[@delete="attribute value"][@xml:lang="en"]//mu[@xml:lang="en"][not(child::node())][following-sibling::omicron[contains(@token,"e")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]//rho[@xml:lang="no-nb"][@xml:id="id2"][not(child::node())][following-sibling::beta[@xml:id="id3"][following-sibling::*[starts-with(concat(@object,"-"),"this-")][@xml:lang="no-nb"][following-sibling::beta[@xml:id="id4"][following-sibling::*[position()=2]][preceding-sibling::beta[1]][not(child::node())][following-sibling::mu[@and="attribute-value"][@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::sigma[@xml:id="id6"][preceding-sibling::*[position() = 5]]/kappa[starts-with(concat(@attr,"-"),"this-")][@xml:lang="en-US"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@name="123456789"][@xml:id="id8"][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta delete="attribute value" xml:lang="en"> + <mu xml:lang="en"/> + <omicron token="false" xml:lang="nb"/> + <eta xml:lang="no" xml:id="id1"> + <rho xml:lang="no-nb" xml:id="id2"/> + <beta xml:id="id3"/> + <any object="this-is-att-value" xml:lang="no-nb"/> + <beta xml:id="id4"/> + <mu and="attribute-value" xml:lang="en-US" xml:id="id5"/> + <sigma xml:id="id6"> + <kappa attr="this-is-att-value" xml:lang="en-US" xml:id="id7"/> + <zeta name="123456789" xml:id="id8"> + <green>This text must be green</green> + </zeta> + </sigma> + </eta> + </zeta> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en"][@xml:id="id1"]//xi[@xml:id="id2"][not(following-sibling::*)]/tau[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[not(child::node())][following-sibling::zeta[@class][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::rho[not(following-sibling::*)]//xi[@class][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="nb"][@xml:id="id5"][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][following-sibling::tau[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][not(preceding-sibling::tau or following-sibling::tau)]//delta[contains(@number,"er at")][@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::epsilon[@xml:id="id7"]//tau[starts-with(@attrib,"tr")][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[contains(concat(@string,"$"),"alue$")][@xml:id="id9"][not(following-sibling::*)]//upsilon[@xml:lang="no-nb"][@xml:id="id10"]//epsilon[starts-with(@name,"attribute val")][@xml:id="id11"][following-sibling::nu[@xml:lang="nb"][@xml:id="id12"][preceding-sibling::*[position() = 1]]/psi[not(following-sibling::*)]/alpha[starts-with(@att,"attribut")][not(following-sibling::*)]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en" xml:id="id1"> + <xi xml:id="id2"> + <tau xml:id="id3"> + <beta/> + <zeta class="this-is-att-value" xml:lang="nb" xml:id="id4"/> + <rho> + <xi class="another attribute value"/> + <sigma xml:lang="nb" xml:id="id5"/> + <mu xml:lang="en-GB"/> + <tau xml:lang="no"> + <delta number="another attribute value" xml:lang="en-US" xml:id="id6"/> + <epsilon xml:id="id7"> + <tau attrib="true" xml:id="id8"/> + <any string="attribute-value" xml:id="id9"> + <upsilon xml:lang="no-nb" xml:id="id10"> + <epsilon name="attribute value" xml:id="id11"/> + <nu xml:lang="nb" xml:id="id12"> + <psi> + <alpha att="attribute"> + <green>This text must be green</green> + </alpha> + </psi> + </nu> + </upsilon> + </any> + </epsilon> + </tau> + </rho> + </tau> + </xi> + </delta> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-GB"]/zeta[contains(@title,"s")][@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]//chi[@attrib][not(preceding-sibling::*)][following-sibling::nu[@xml:id="id2"]//xi[starts-with(concat(@attribute,"-"),"attribute-")][@xml:lang="nb"]/nu[@number][@xml:id="id3"][not(following-sibling::*)]/nu[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(@src,"tru")][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/sigma[@xml:id="id5"][not(preceding-sibling::*)]//lambda[starts-with(concat(@and,"-"),"_blank-")][not(following-sibling::*)]/mu[not(child::node())][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(preceding-sibling::gamma)][following-sibling::mu[not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::alpha[starts-with(concat(@object,"-"),"true-")][following-sibling::zeta[@xml:lang="no"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//mu[contains(@attrib,"en")][@xml:lang="en-GB"][@xml:id="id7"][not(child::node())][following-sibling::eta[@token][@xml:id="id8"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[contains(concat(@attrib,"$"),"-value$")][preceding-sibling::*[position() = 2]]/gamma[@xml:id="id9"][not(child::node())][following-sibling::iota[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@object][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-GB"> + <zeta title="false" xml:lang="nb" xml:id="id1"> + <chi attrib="this.nodeValue"/> + <nu xml:id="id2"> + <xi attribute="attribute" xml:lang="nb"> + <nu number="true" xml:id="id3"> + <nu xml:lang="en"/> + <omicron src="true" xml:id="id4"> + <sigma xml:id="id5"> + <lambda and="_blank"> + <mu/> + <gamma xml:lang="no-nb" xml:id="id6"/> + <mu/> + <gamma/> + <alpha object="true"/> + <zeta xml:lang="no"> + <mu attrib="solid 1px green" xml:lang="en-GB" xml:id="id7"/> + <eta token="this.nodeValue" xml:id="id8"/> + <eta attrib="attribute-value"> + <gamma xml:id="id9"/> + <iota xml:lang="nb"> + <epsilon object="solid 1px green" xml:lang="nb" xml:id="id10"> + <green>This text must be green</green> + </epsilon> + </iota> + </eta> + </zeta> + </lambda> + </sigma> + </omicron> + </nu> + </xi> + </nu> + </zeta> + </kappa> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="en-GB"]/mu[@attrib="attribute"][@xml:lang="en-GB"][not(following-sibling::*)]//iota[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:id="id1"][not(following-sibling::*)]//phi[@class]//pi[@xml:lang="nb"][not(following-sibling::*)]/xi[@and="123456789"][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::psi[starts-with(@attrib,"fa")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//sigma[@attribute][@xml:id="id4"][not(child::node())][following-sibling::theta[@true][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::pi[@xml:lang="en-GB"][@xml:id="id6"][not(child::node())][following-sibling::nu[@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]//sigma[contains(@src,"alue")][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@data]//lambda[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::psi[contains(concat(@name,"$"),"ank$")]/tau[contains(@title,"deValue")][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[starts-with(@src,"_bl")][@xml:lang="en"][@xml:id="id12"][preceding-sibling::*[position() = 2]][following-sibling::pi[@abort][@xml:id="id13"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[contains(concat(@token,"$"),"nt$")][preceding-sibling::*[position() = 4]]]][position() = 1]]][position() = 1]][position() = 1]]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="en-GB"> + <mu attrib="attribute" xml:lang="en-GB"> + <iota xml:lang="en-US"/> + <kappa> + <beta xml:id="id1"> + <phi class="this.nodeValue"> + <pi xml:lang="nb"> + <xi and="123456789" xml:lang="no" xml:id="id2"/> + <psi attrib="false" xml:lang="nb" xml:id="id3"> + <sigma attribute="solid 1px green" xml:id="id4"/> + <theta true="another attribute value" xml:lang="en-US" xml:id="id5"/> + <pi xml:lang="en-GB" xml:id="id6"/> + <nu xml:lang="en" xml:id="id7"> + <sigma src="attribute value" xml:lang="en" xml:id="id8"/> + <mu xml:lang="no"/> + <iota data="this-is-att-value"> + <lambda xml:id="id9"/> + <psi xml:id="id10"/> + <psi name="_blank"> + <tau title="this.nodeValue"/> + <rho xml:id="id11"/> + <psi src="_blank" xml:lang="en" xml:id="id12"/> + <pi abort="attribute-value" xml:id="id13"/> + <lambda token="content"> + <green>This text must be green</green> + </lambda> + </psi> + </iota> + </nu> + </psi> + </pi> + </phi> + </beta> + </kappa> + </mu> + </pi> + </tree> + </test> + <test> + <xpath>//*[@or="solid 1px green"][@xml:lang="en-GB"]/eta[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id1"][not(preceding-sibling::*)]//sigma[@xml:id="id2"][not(preceding-sibling::*)]/omega//epsilon[contains(concat(@title,"$"),"lank$")]/phi[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:lang="no-nb"]//chi[@xml:lang="en"][not(preceding-sibling::*)]//rho[contains(concat(@att,"$"),"89$")]/lambda[@object][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <any or="solid 1px green" xml:lang="en-GB"> + <eta token="another attribute value" xml:id="id1"> + <sigma xml:id="id2"> + <omega> + <epsilon title="_blank"> + <phi xml:lang="no"/> + <rho xml:lang="no-nb"> + <chi xml:lang="en"> + <rho att="123456789"> + <lambda object="attribute-value" xml:lang="nb"> + <lambda> + <green>This text must be green</green> + </lambda> + </lambda> + </rho> + </chi> + </rho> + </epsilon> + </omega> + </sigma> + </eta> + </any> + </tree> + </test> + <test> + <xpath>//epsilon[contains(concat(@abort,"$"),"100%$")][@xml:id="id1"]/xi[not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[starts-with(@att,"tru")][not(child::node())][following-sibling::lambda[contains(concat(@insert,"$"),"_blank$")][@xml:id="id2"][following-sibling::psi[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//kappa[@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:lang="en"]/kappa[@xml:id="id5"][not(child::node())][following-sibling::beta[@class][@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::upsilon[@false][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::upsilon)][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 3]]//gamma[@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[contains(@true,"0%")][@xml:lang="en-US"][not(child::node())][following-sibling::epsilon[@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@delete="_blank"][not(preceding-sibling::kappa)][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][following-sibling::xi/iota[@xml:lang="en-US"][not(child::node())][following-sibling::epsilon[@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@xml:id="id11"]//alpha[starts-with(@delete,"th")][@xml:lang="en-GB"][@xml:id="id12"][not(preceding-sibling::*)]/xi[not(preceding-sibling::*)]//gamma[starts-with(@or,"tr")][@xml:id="id13"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon abort="100%" xml:id="id1"> + <xi/> + <zeta att="true"/> + <lambda insert="_blank" xml:id="id2"/> + <psi xml:lang="no" xml:id="id3"> + <kappa xml:id="id4"/> + <xi/> + <theta xml:lang="en"> + <kappa xml:id="id5"/> + <beta class="this-is-att-value" xml:lang="en-US" xml:id="id6"/> + <upsilon false="content" xml:id="id7"/> + <chi> + <gamma xml:id="id8"> + <omicron true="100%" xml:lang="en-US"/> + <epsilon xml:lang="en" xml:id="id9"/> + <kappa delete="_blank"/> + <kappa xml:lang="no-nb"/> + <xi> + <iota xml:lang="en-US"/> + <epsilon xml:id="id10"> + <any xml:id="id11"> + <alpha delete="this-is-att-value" xml:lang="en-GB" xml:id="id12"> + <xi> + <gamma or="true" xml:id="id13"> + <green>This text must be green</green> + </gamma> + </xi> + </alpha> + </any> + </epsilon> + </xi> + </gamma> + </chi> + </theta> + </psi> + </epsilon> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no"]/chi[not(child::node())][following-sibling::omicron[@abort][following-sibling::xi[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::tau[preceding-sibling::*[position() = 3]]//upsilon[contains(concat(@name,"$"),"te value$")][not(following-sibling::*)]//mu[not(child::node())][following-sibling::tau[@data="attribute value"][@xml:id="id1"][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::tau[@name="false"][@xml:lang="en"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][following-sibling::lambda[starts-with(@string,"this.node")][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::gamma[@xml:id="id2"]/epsilon[@xml:id="id3"][not(preceding-sibling::*)]//xi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omega[contains(@string,"ute")][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]//alpha[@class][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[@xml:lang="no"][following-sibling::*[position()=3]][following-sibling::psi[contains(@attribute,"lid 1px green")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@xml:id="id8"][not(child::node())][following-sibling::nu[starts-with(concat(@class,"-"),"100%-")][@xml:lang="no-nb"][@xml:id="id9"][preceding-sibling::*[position() = 3]]/beta[starts-with(@or,"conte")][@xml:lang="nb"][@xml:id="id10"][not(following-sibling::*)][position() = 1]]]]]]]]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no"> + <chi/> + <omicron abort="true"/> + <xi xml:lang="no"/> + <tau> + <upsilon name="attribute value"> + <mu/> + <tau data="attribute value" xml:id="id1"/> + <alpha/> + <tau name="false" xml:lang="en"/> + <lambda string="this.nodeValue" xml:lang="no-nb"/> + <gamma xml:id="id2"> + <epsilon xml:id="id3"> + <xi xml:lang="en"/> + <omega string="attribute"/> + <phi xml:lang="no-nb" xml:id="id4"> + <alpha class="another attribute value" xml:lang="no" xml:id="id5"/> + <alpha xml:lang="en-US" xml:id="id6"> + <theta xml:lang="no"/> + <psi attribute="solid 1px green" xml:id="id7"/> + <gamma xml:id="id8"/> + <nu class="100%" xml:lang="no-nb" xml:id="id9"> + <beta or="content" xml:lang="nb" xml:id="id10"> + <green>This text must be green</green> + </beta> + </nu> + </alpha> + </phi> + </epsilon> + </gamma> + </upsilon> + </tau> + </epsilon> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]//beta[@insert][@xml:id="id2"][following-sibling::*[position()=3]][not(child::node())][following-sibling::*[following-sibling::lambda[contains(@attr,"alue")][@xml:lang="no"][@xml:id="id3"][not(following-sibling::lambda)][not(child::node())][following-sibling::omega[@xml:lang="no"][@xml:id="id4"]/theta[@xml:id="id5"][not(preceding-sibling::*)]//epsilon[@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]//theta[@xml:lang="nb"][@xml:id="id7"][following-sibling::gamma[@xml:id="id8"][following-sibling::alpha[contains(concat(@attr,"$"),"ribute value$")][@xml:id="id9"][preceding-sibling::*[position() = 2]][following-sibling::theta[@xml:id="id10"][not(following-sibling::*)][not(following-sibling::theta)]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <beta insert="this-is-att-value" xml:id="id2"/> + <any/> + <lambda attr="this-is-att-value" xml:lang="no" xml:id="id3"/> + <omega xml:lang="no" xml:id="id4"> + <theta xml:id="id5"> + <epsilon xml:lang="nb" xml:id="id6"> + <theta xml:lang="nb" xml:id="id7"/> + <gamma xml:id="id8"/> + <alpha attr="another attribute value" xml:id="id9"/> + <theta xml:id="id10"> + <green>This text must be green</green> + </theta> + </epsilon> + </theta> + </omega> + </zeta> + </tree> + </test> + <test> + <xpath>//gamma[@attrib][@xml:id="id1"]//pi[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[not(preceding-sibling::*)][following-sibling::*[preceding-sibling::*[position() = 1]][following-sibling::omega[contains(concat(@data,"$"),"odeValue$")][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/zeta][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <gamma attrib="_blank" xml:id="id1"> + <pi token="attribute-value" xml:lang="en"/> + <xi xml:lang="no-nb"> + <mu/> + <any/> + <omega data="this.nodeValue" xml:lang="en" xml:id="id2"> + <zeta> + <green>This text must be green</green> + </zeta> + </omega> + </xi> + </gamma> + </tree> + </test> + <test> + <xpath>//rho[starts-with(@attr,"another attribute")][@xml:lang="no-nb"]/theta[@attrib][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::kappa[contains(concat(@true,"$"),"6789$")][@xml:lang="no-nb"][not(child::node())][following-sibling::mu[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::lambda[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::kappa[@delete][@xml:lang="en-GB"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::omicron[starts-with(@abort,"attribu")][@xml:lang="en-US"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::*[@xml:id="id2"]//chi[@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[contains(@abort,"ute")][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@attrib="123456789"][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]]/delta[@attr][@xml:lang="no-nb"][following-sibling::omicron[@xml:lang="en-GB"][not(following-sibling::*)]/pi[not(following-sibling::*)]/xi[following-sibling::tau[starts-with(@or,"at")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]//phi[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:id="id7"][not(child::node())][following-sibling::iota[@xml:lang="nb"][preceding-sibling::*[position() = 2]]/omega[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]]]]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <rho attr="another attribute value" xml:lang="no-nb"> + <theta attrib="false" xml:id="id1"/> + <kappa true="123456789" xml:lang="no-nb"/> + <mu xml:lang="nb"/> + <lambda/> + <kappa delete="this-is-att-value" xml:lang="en-GB"/> + <omicron abort="attribute" xml:lang="en-US"/> + <any xml:id="id2"> + <chi xml:lang="en-US" xml:id="id3"/> + <psi abort="attribute" xml:lang="no-nb" xml:id="id4"/> + <alpha attrib="123456789" xml:lang="en-US" xml:id="id5"> + <delta attr="this-is-att-value" xml:lang="no-nb"/> + <omicron xml:lang="en-GB"> + <pi> + <xi/> + <tau or="attribute-value" xml:lang="en-US"> + <phi xml:lang="en-GB" xml:id="id6"/> + <chi xml:id="id7"/> + <iota xml:lang="nb"> + <omega xml:lang="en-GB"> + <green>This text must be green</green> + </omega> + </iota> + </tau> + </pi> + </omicron> + </alpha> + </any> + </rho> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-US"][@xml:id="id1"]/psi[@xml:lang="en-US"][not(preceding-sibling::*)]/kappa[@number][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[starts-with(@delete,"attribute")][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::upsilon[@src][@xml:id="id2"][following-sibling::*[position()=3]][following-sibling::alpha[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[starts-with(@attribute,"12")][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id4"]//tau[@attrib="false"][@xml:lang="no-nb"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en-US" xml:id="id1"> + <psi xml:lang="en-US"> + <kappa number="123456789" xml:lang="en-US"> + <pi delete="attribute-value"/> + <upsilon src="100%" xml:id="id2"/> + <alpha xml:lang="no-nb" xml:id="id3"/> + <epsilon attribute="123456789"/> + <alpha xml:lang="en-GB" xml:id="id4"> + <tau attrib="false" xml:lang="no-nb"> + <green>This text must be green</green> + </tau> + </alpha> + </kappa> + </psi> + </chi> + </tree> + </test> + <test> + <xpath>//nu[starts-with(@token,"this.no")]//iota[@xml:lang="en"][following-sibling::alpha[@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]//phi[contains(@attr,"tribu")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::eta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::phi[starts-with(concat(@and,"-"),"another attribute value-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]]//sigma[not(preceding-sibling::*)][not(following-sibling::*)]//pi[@xml:lang="en"][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//tau[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="no-nb"][following-sibling::eta[@attr][@xml:lang="en-GB"][@xml:id="id5"]/tau[starts-with(@attr,"1234567")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[contains(@desciption,"co")][@xml:lang="en-GB"][@xml:id="id7"]//eta[not(following-sibling::*)]/gamma[contains(concat(@attribute,"$"),"lse$")][@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[not(preceding-sibling::*)]/psi[@or][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::nu[@object][@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <nu token="this.nodeValue"> + <iota xml:lang="en"/> + <alpha xml:lang="no-nb" xml:id="id1"> + <phi attr="attribute" xml:lang="en-US" xml:id="id2"/> + <eta/> + <phi and="another attribute value" xml:lang="no-nb"/> + <psi xml:lang="en-GB"> + <sigma> + <pi xml:lang="en"/> + <upsilon xml:lang="no-nb" xml:id="id3"> + <tau xml:lang="no" xml:id="id4"> + <rho xml:lang="no-nb"/> + <eta attr="another attribute value" xml:lang="en-GB" xml:id="id5"> + <tau attr="123456789" xml:lang="nb" xml:id="id6"/> + <xi desciption="content" xml:lang="en-GB" xml:id="id7"> + <eta> + <gamma attribute="false" xml:lang="en-US" xml:id="id8"> + <mu xml:id="id9"> + <omicron> + <psi or="another attribute value" xml:lang="no-nb"/> + <nu object="attribute" xml:lang="nb" xml:id="id10"> + <green>This text must be green</green> + </nu> + </omicron> + </mu> + </gamma> + </eta> + </xi> + </eta> + </tau> + </upsilon> + </sigma> + </psi> + </alpha> + </nu> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]//eta[contains(concat(@abort,"$"),"lue$")][@xml:id="id2"][not(child::node())][following-sibling::gamma[@number="solid 1px green"][@xml:id="id3"][following-sibling::phi[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::eta[preceding-sibling::*[position() = 3]][not(following-sibling::*)]//epsilon[contains(concat(@false,"$"),"ute value$")][not(following-sibling::*)]//eta[contains(concat(@and,"$"),"odeValue$")][@xml:lang="en-GB"][not(following-sibling::*)]//xi[@name][@xml:id="id4"][not(child::node())][following-sibling::sigma[starts-with(concat(@true,"-"),"attribute-")][@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::gamma[not(preceding-sibling::gamma or following-sibling::gamma)]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <eta abort="attribute value" xml:id="id2"/> + <gamma number="solid 1px green" xml:id="id3"/> + <phi false="123456789" xml:lang="no"/> + <eta> + <epsilon false="another attribute value"> + <eta and="this.nodeValue" xml:lang="en-GB"> + <xi name="this-is-att-value" xml:id="id4"/> + <sigma true="attribute" xml:lang="no" xml:id="id5"/> + <gamma> + <green>This text must be green</green> + </gamma> + </eta> + </epsilon> + </eta> + </iota> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(concat(@attribute,"-"),"this-")]/tau[not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@src][preceding-sibling::*[position() = 1]][following-sibling::iota[@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 2]][following-sibling::phi[contains(@object,"789")][following-sibling::*[position()=1]][following-sibling::alpha[@xml:id="id2"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//psi[@xml:id="id3"]//epsilon[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/xi[starts-with(concat(@class,"-"),"attribute value-")][@xml:lang="en-US"][not(preceding-sibling::*)]//epsilon[@xml:lang="en"][not(following-sibling::*)]//epsilon[@xml:lang="no"][not(preceding-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <upsilon attribute="this-is-att-value"> + <tau/> + <lambda src="true"/> + <iota xml:lang="no-nb" xml:id="id1"/> + <phi object="123456789"/> + <alpha xml:id="id2"> + <psi xml:id="id3"> + <epsilon xml:lang="no" xml:id="id4"/> + <theta xml:lang="no-nb"> + <xi class="attribute value" xml:lang="en-US"> + <epsilon xml:lang="en"> + <epsilon xml:lang="no"> + <green>This text must be green</green> + </epsilon> + </epsilon> + </xi> + </theta> + </psi> + </alpha> + </upsilon> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(concat(@and,"-"),"attribute value-")][@xml:lang="nb"]/zeta[contains(concat(@token,"$"),"this.nodeValue$")][@xml:lang="no"][@xml:id="id1"][following-sibling::iota[@xml:id="id2"][not(following-sibling::*)]//mu[@xml:lang="no"][@xml:id="id3"][not(following-sibling::*)]//tau[@xml:lang="en-US"][@xml:id="id4"]//upsilon[@xml:id="id5"][not(following-sibling::*)]//theta[@attribute][@xml:lang="en-US"][@xml:id="id6"][not(child::node())][following-sibling::upsilon[@abort="another attribute value"][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::upsilon)][not(child::node())][following-sibling::mu[@att="attribute value"][@xml:lang="no"]//tau[starts-with(concat(@string,"-"),"another attribute value-")][@xml:lang="no"][@xml:id="id8"][not(child::node())][following-sibling::rho[@xml:id="id9"]/delta[@xml:lang="en"][not(preceding-sibling::*)]//gamma[not(child::node())][following-sibling::epsilon[@att="this.nodeValue"][@xml:id="id10"][preceding-sibling::*[position() = 1]]/pi[@class="true"][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha and="attribute value" xml:lang="nb"> + <zeta token="this.nodeValue" xml:lang="no" xml:id="id1"/> + <iota xml:id="id2"> + <mu xml:lang="no" xml:id="id3"> + <tau xml:lang="en-US" xml:id="id4"> + <upsilon xml:id="id5"> + <theta attribute="true" xml:lang="en-US" xml:id="id6"/> + <upsilon abort="another attribute value" xml:lang="en-US" xml:id="id7"/> + <mu att="attribute value" xml:lang="no"> + <tau string="another attribute value" xml:lang="no" xml:id="id8"/> + <rho xml:id="id9"> + <delta xml:lang="en"> + <gamma/> + <epsilon att="this.nodeValue" xml:id="id10"> + <pi class="true" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </epsilon> + </delta> + </rho> + </mu> + </upsilon> + </tau> + </mu> + </iota> + </alpha> + </tree> + </test> + <test> + <xpath>//psi/theta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][not(parent::*/*[position()=2])]/omicron[starts-with(@abort,"attribut")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@desciption="content"][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::mu[@xml:lang="en-US"][not(following-sibling::*)]//eta[@object][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)]//chi[@xml:id="id2"][following-sibling::lambda[contains(@attribute,"45")][@xml:id="id3"][preceding-sibling::*[position() = 1]]//omega[@attr="100%"][not(preceding-sibling::*)][following-sibling::*[@attr="attribute"][@xml:lang="en"][@xml:id="id4"][not(following-sibling::*)]//rho[contains(concat(@desciption,"$"),"ttribute-value$")][@xml:id="id5"][not(child::node())][following-sibling::iota[@xml:lang="no"][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[@xml:lang="no"][following-sibling::delta[@xml:lang="nb"][@xml:id="id6"][position() = 1]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <psi> + <theta xml:lang="en-GB"> + <omicron abort="attribute" xml:lang="no"/> + <omicron desciption="content" xml:lang="no"/> + <mu xml:lang="en-US"> + <eta object="100%"> + <upsilon xml:lang="nb" xml:id="id1"> + <chi xml:id="id2"/> + <lambda attribute="123456789" xml:id="id3"> + <omega attr="100%"/> + <any attr="attribute" xml:lang="en" xml:id="id4"> + <rho desciption="attribute-value" xml:id="id5"/> + <iota xml:lang="no"/> + <chi xml:lang="no"/> + <delta xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </delta> + </any> + </lambda> + </upsilon> + </eta> + </mu> + </theta> + </psi> + </tree> + </test> + <test> + <xpath>//eta[contains(concat(@name,"$"),"ank$")]/iota[@number="another attribute value"][not(following-sibling::*)]/rho[@xml:lang="en-GB"][not(following-sibling::*)]//xi[@false][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@xml:lang="en"]//pi[contains(@desciption,"s-")][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[contains(@desciption,"en")][@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::nu[@xml:id="id3"][preceding-sibling::*[position() = 2]]//pi[not(child::node())][following-sibling::eta[not(following-sibling::*)]/xi[@xml:id="id4"]/tau[@xml:lang="nb"][following-sibling::sigma[contains(@att,"e")][@xml:lang="en-GB"][following-sibling::upsilon[@att][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/tau[not(following-sibling::*)]//omicron[starts-with(@data,"_blank")][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::phi)]//epsilon[@or][not(preceding-sibling::*)][following-sibling::tau[@desciption][@xml:id="id8"][preceding-sibling::*[position() = 1]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <eta name="_blank"> + <iota number="another attribute value"> + <rho xml:lang="en-GB"> + <xi false="true" xml:lang="en-US" xml:id="id1"> + <alpha xml:lang="en"> + <pi desciption="this-is-att-value"> + <delta xml:lang="en-GB" xml:id="id2"/> + <theta desciption="solid 1px green" xml:lang="en-US"/> + <nu xml:id="id3"> + <pi/> + <eta> + <xi xml:id="id4"> + <tau xml:lang="nb"/> + <sigma att="attribute value" xml:lang="en-GB"/> + <upsilon att="another attribute value" xml:id="id5"> + <tau> + <omicron data="_blank"> + <lambda xml:lang="no-nb" xml:id="id6"> + <phi xml:lang="en-GB" xml:id="id7"> + <epsilon or="attribute-value"/> + <tau desciption="this-is-att-value" xml:id="id8"> + <green>This text must be green</green> + </tau> + </phi> + </lambda> + </omicron> + </tau> + </upsilon> + </xi> + </eta> + </nu> + </pi> + </alpha> + </xi> + </rho> + </iota> + </eta> + </tree> + </test> + <test> + <xpath>//tau[@and][@xml:lang="nb"][@xml:id="id1"]/pi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[starts-with(@attribute,"tru")][@xml:lang="en"][@xml:id="id4"][not(child::node())][following-sibling::kappa[starts-with(concat(@or,"-"),"solid 1px green-")][not(following-sibling::kappa)]/iota[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::gamma[contains(concat(@false,"$"),"value$")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::*[position()=3]][following-sibling::delta[@xml:lang="nb"][@xml:id="id7"][following-sibling::chi[@xml:lang="no"][@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::theta[@attribute="content"]/lambda[@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@name="this.nodeValue"][@xml:lang="en"][following-sibling::*[position()=3]][following-sibling::kappa[following-sibling::beta[starts-with(concat(@attribute,"-"),"100%-")][@xml:id="id11"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@attrib][@xml:lang="no-nb"][@xml:id="id12"][preceding-sibling::*[position() = 5]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>1</nth> + </result> + <tree> + <tau and="this-is-att-value" xml:lang="nb" xml:id="id1"> + <pi xml:id="id2"> + <omega xml:lang="en-GB" xml:id="id3"> + <pi attribute="true" xml:lang="en" xml:id="id4"/> + <kappa or="solid 1px green"> + <iota xml:lang="no-nb" xml:id="id5"/> + <gamma false="attribute value" xml:lang="en-GB" xml:id="id6"/> + <delta xml:lang="nb" xml:id="id7"/> + <chi xml:lang="no" xml:id="id8"/> + <theta attribute="content"> + <lambda xml:id="id9"/> + <gamma xml:lang="nb" xml:id="id10"/> + <omega name="this.nodeValue" xml:lang="en"/> + <kappa/> + <beta attribute="100%" xml:id="id11"/> + <pi attrib="this.nodeValue" xml:lang="no-nb" xml:id="id12"> + <green>This text must be green</green> + </pi> + </theta> + </kappa> + </omega> + </pi> + </tau> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]/omega[@attribute][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::chi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::*[preceding-sibling::*[position() = 2]][following-sibling::alpha[@xml:id="id2"][not(child::node())][following-sibling::zeta[@xml:lang="nb"][not(following-sibling::*)]//pi[contains(concat(@false,"$"),"false$")][@xml:lang="en-US"]/alpha[contains(@content,"his.nodeV")][@xml:id="id3"][not(following-sibling::*)]/gamma[@xml:lang="en-US"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::pi[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <omega attribute="100%" xml:lang="no-nb"/> + <chi xml:lang="no-nb"/> + <any/> + <alpha xml:id="id2"/> + <zeta xml:lang="nb"> + <pi false="false" xml:lang="en-US"> + <alpha content="this.nodeValue" xml:id="id3"> + <gamma xml:lang="en-US" xml:id="id4"/> + <pi xml:lang="en-US" xml:id="id5"> + <green>This text must be green</green> + </pi> + </alpha> + </pi> + </zeta> + </xi> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="nb"]//pi[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//theta[starts-with(concat(@src,"-"),"content-")][@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::nu[contains(concat(@string,"$"),"ibute value$")][@xml:lang="en-US"][not(following-sibling::*)]//chi[@xml:lang="en-US"]/gamma[not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@xml:lang="nb"][@xml:id="id6"]/iota[@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]/iota[@string="100%"][following-sibling::*[position()=6]][not(child::node())][following-sibling::xi[starts-with(concat(@number,"-"),"false-")][@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(preceding-sibling::xi)][following-sibling::sigma[@and][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::rho[contains(@attribute,"0")][not(child::node())][following-sibling::kappa[starts-with(@att,"at")][not(child::node())][following-sibling::eta[@false][@xml:lang="en-GB"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::tau[@delete="false"][@xml:lang="en"][not(following-sibling::*)]/nu[@false][@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][not(preceding-sibling::nu or following-sibling::nu)][position() = 1]]][position() = 1]][position() = 1]]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="nb"> + <pi xml:id="id1"> + <beta xml:lang="no" xml:id="id2"/> + <sigma xml:lang="no"/> + <zeta xml:lang="en-US" xml:id="id3"> + <theta src="content" xml:lang="no"/> + <rho xml:lang="en-GB" xml:id="id4"/> + <psi xml:id="id5"/> + <nu string="attribute value" xml:lang="en-US"> + <chi xml:lang="en-US"> + <gamma> + <kappa xml:lang="nb" xml:id="id6"> + <iota xml:lang="no-nb" xml:id="id7"> + <iota string="100%"/> + <xi number="false" xml:lang="en-US" xml:id="id8"/> + <sigma and="attribute value" xml:lang="nb"/> + <rho attribute="100%"/> + <kappa att="attribute"/> + <eta false="content" xml:lang="en-GB"/> + <tau delete="false" xml:lang="en"> + <nu false="_blank" xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </nu> + </tau> + </iota> + </kappa> + </gamma> + </chi> + </nu> + </zeta> + </pi> + </upsilon> + </tree> + </test> + <test> + <xpath>//beta//omicron[not(child::node())][following-sibling::gamma[@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]//sigma[starts-with(@name,"at")][@xml:lang="no-nb"][following-sibling::*[position()=4]][following-sibling::iota[starts-with(concat(@title,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::iota[contains(@src,"odeValue")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::rho[contains(@data,"eValue")][@xml:id="id2"][not(following-sibling::*)]/kappa[contains(concat(@class,"$"),"alse$")][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::eta[starts-with(@desciption,"attribu")][@xml:id="id4"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <beta> + <omicron/> + <gamma xml:lang="en-GB" xml:id="id1"> + <sigma name="attribute-value" xml:lang="no-nb"/> + <iota title="solid 1px green"/> + <xi xml:lang="en-GB"/> + <iota src="this.nodeValue" xml:lang="nb"/> + <rho data="this.nodeValue" xml:id="id2"> + <kappa class="false" xml:lang="en" xml:id="id3"/> + <eta desciption="attribute-value" xml:id="id4"> + <green>This text must be green</green> + </eta> + </rho> + </gamma> + </beta> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]/eta[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[starts-with(concat(@title,"-"),"_blank-")][@xml:lang="en-GB"][following-sibling::mu[@attrib][@xml:id="id3"][following-sibling::mu[@string][not(following-sibling::*)]/lambda[@xml:lang="en-GB"][@xml:id="id4"][following-sibling::phi[contains(@object,"k")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <eta xml:lang="no-nb" xml:id="id2"> + <iota title="_blank" xml:lang="en-GB"/> + <mu attrib="false" xml:id="id3"/> + <mu string="123456789"> + <lambda xml:lang="en-GB" xml:id="id4"/> + <phi object="_blank" xml:id="id5"> + <green>This text must be green</green> + </phi> + </mu> + </eta> + </zeta> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="no-nb"]/rho[@xml:lang="no-nb"][following-sibling::*[position()=1]][not(following-sibling::rho)][following-sibling::mu[contains(concat(@insert,"$"),"eValue$")][@xml:lang="no-nb"]//kappa[contains(concat(@false,"$"),"attribute$")][following-sibling::*[position()=2]][following-sibling::sigma[starts-with(concat(@abort,"-"),"attribute-")][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[not(following-sibling::*)]//zeta[@xml:lang="nb"][not(following-sibling::*)]/upsilon[not(child::node())][following-sibling::sigma[starts-with(concat(@delete,"-"),"solid 1px green-")][@xml:lang="en-GB"][@xml:id="id1"][not(child::node())][following-sibling::psi[@desciption][@xml:id="id2"][preceding-sibling::*[position() = 2]]/xi[@string][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::upsilon[@or="attribute value"][@xml:id="id4"]//gamma[starts-with(@title,"this.")][@xml:lang="nb"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="no-nb"> + <rho xml:lang="no-nb"/> + <mu insert="this.nodeValue" xml:lang="no-nb"> + <kappa false="attribute"/> + <sigma abort="attribute-value" xml:lang="no-nb"/> + <pi> + <zeta xml:lang="nb"> + <upsilon/> + <sigma delete="solid 1px green" xml:lang="en-GB" xml:id="id1"/> + <psi desciption="123456789" xml:id="id2"> + <xi string="attribute" xml:lang="en" xml:id="id3"/> + <upsilon or="attribute value" xml:id="id4"> + <gamma title="this.nodeValue" xml:lang="nb"> + <green>This text must be green</green> + </gamma> + </upsilon> + </psi> + </zeta> + </pi> + </mu> + </chi> + </tree> + </test> + <test> + <xpath>//gamma[contains(concat(@object,"$"),"nodeValue$")][@xml:id="id1"]/phi[contains(@title,"thi")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[contains(@number,"ue")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//alpha[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::eta[@insert][preceding-sibling::*[position() = 1]][following-sibling::rho[@abort][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//beta[@desciption][following-sibling::*[position()=4]][following-sibling::psi[starts-with(concat(@false,"-"),"solid 1px green-")][@xml:id="id5"][following-sibling::zeta[starts-with(concat(@name,"-"),"100%-")][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[@and="content"][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::epsilon[starts-with(@desciption,"this-is-att-value")][@xml:lang="en"][not(following-sibling::*)]/alpha[@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@content][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/theta[contains(concat(@delete,"$"),"false$")][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]]/gamma[contains(concat(@true,"$"),"100%$")][@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <gamma object="this.nodeValue" xml:id="id1"> + <phi title="this.nodeValue" xml:id="id2"/> + <omicron number="this-is-att-value"> + <alpha xml:id="id3"/> + <eta insert="attribute value"/> + <rho abort="attribute" xml:id="id4"> + <beta desciption="content"/> + <psi false="solid 1px green" xml:id="id5"/> + <zeta name="100%"/> + <xi and="content" xml:lang="no" xml:id="id6"/> + <epsilon desciption="this-is-att-value" xml:lang="en"> + <alpha xml:lang="en-GB" xml:id="id7"/> + <iota content="attribute value" xml:lang="nb"> + <theta delete="false" xml:id="id8"/> + <phi xml:lang="nb" xml:id="id9"> + <gamma true="100%" xml:lang="en" xml:id="id10"> + <green>This text must be green</green> + </gamma> + </phi> + </iota> + </epsilon> + </rho> + </omicron> + </gamma> + </tree> + </test> + <test> + <xpath>//gamma[contains(concat(@class,"$"),"ue$")][@xml:lang="en"]/psi[@name][@xml:id="id1"][not(preceding-sibling::*)]/mu[not(preceding-sibling::*)][not(following-sibling::*)]//psi[starts-with(concat(@attribute,"-"),"false-")][@xml:lang="no"][not(following-sibling::*)]/omicron[starts-with(concat(@src,"-"),"content-")][not(preceding-sibling::*)][following-sibling::epsilon[contains(concat(@class,"$"),"ent$")][@xml:id="id2"]//eta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::zeta[@false="_blank"][@xml:lang="no"][preceding-sibling::*[position() = 1]]/epsilon[not(preceding-sibling::*)][following-sibling::epsilon[@xml:lang="nb"][not(child::node())][following-sibling::upsilon[@attribute]/lambda[@att][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[contains(@src,"89")][preceding-sibling::*[position() = 1]]/theta/chi[@xml:lang="en-GB"][not(following-sibling::*)]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <gamma class="attribute-value" xml:lang="en"> + <psi name="123456789" xml:id="id1"> + <mu> + <psi attribute="false" xml:lang="no"> + <omicron src="content"/> + <epsilon class="content" xml:id="id2"> + <eta xml:lang="en-US"/> + <zeta false="_blank" xml:lang="no"> + <epsilon/> + <epsilon xml:lang="nb"/> + <upsilon attribute="_blank"> + <lambda att="another attribute value"/> + <pi src="123456789"> + <theta> + <chi xml:lang="en-GB"> + <green>This text must be green</green> + </chi> + </theta> + </pi> + </upsilon> + </zeta> + </epsilon> + </psi> + </mu> + </psi> + </gamma> + </tree> + </test> + <test> + <xpath>//phi[@desciption]//tau[@attribute="solid 1px green"][@xml:id="id1"][following-sibling::theta[@attr][preceding-sibling::*[position() = 1]][following-sibling::chi[starts-with(@name,"this-is-att-v")][@xml:lang="en-US"][following-sibling::xi[@xml:id="id2"][not(child::node())][following-sibling::theta[starts-with(@desciption,"_bla")][@xml:id="id3"][not(following-sibling::*)]//alpha[@object][@xml:id="id4"][not(preceding-sibling::*)][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <phi desciption="solid 1px green"> + <tau attribute="solid 1px green" xml:id="id1"/> + <theta attr="another attribute value"/> + <chi name="this-is-att-value" xml:lang="en-US"/> + <xi xml:id="id2"/> + <theta desciption="_blank" xml:id="id3"> + <alpha object="_blank" xml:id="id4"> + <green>This text must be green</green> + </alpha> + </theta> + </phi> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]//xi[contains(@insert,"e")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[not(following-sibling::*)]//delta[@xml:lang="nb"][not(child::node())][following-sibling::pi[following-sibling::beta[starts-with(concat(@false,"-"),"true-")][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/beta[starts-with(@data,"another attr")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@xml:lang="en-US"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <xi insert="attribute value" xml:lang="en"/> + <epsilon> + <delta xml:lang="nb"/> + <pi/> + <beta false="true" xml:lang="no-nb" xml:id="id2"> + <beta data="another attribute value" xml:id="id3"> + <gamma xml:lang="en-US"> + <green>This text must be green</green> + </gamma> + </beta> + </beta> + </epsilon> + </iota> + </tree> + </test> + <test> + <xpath>//theta[@abort][@xml:lang="en-US"][@xml:id="id1"]//delta[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::epsilon[@title="true"][@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]/lambda[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::mu[@xml:lang="no"][@xml:id="id5"][following-sibling::epsilon[@xml:lang="no"][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <theta abort="_blank" xml:lang="en-US" xml:id="id1"> + <delta xml:lang="no-nb" xml:id="id2"/> + <upsilon xml:lang="en"/> + <epsilon title="true" xml:lang="nb" xml:id="id3"> + <lambda xml:id="id4"/> + <mu xml:lang="no" xml:id="id5"/> + <epsilon xml:lang="no"> + <green>This text must be green</green> + </epsilon> + </epsilon> + </theta> + </tree> + </test> + <test> + <xpath>//delta[contains(concat(@insert,"$"),"att-value$")][@xml:lang="en-GB"]//omicron[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id1"][preceding-sibling::*[position() = 1]]//theta[starts-with(@object,"t")][@xml:id="id2"][not(following-sibling::*)]//xi[starts-with(@content,"100%")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::omega[starts-with(@object,"another attribu")][@xml:id="id3"][not(child::node())][following-sibling::nu[@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <delta insert="this-is-att-value" xml:lang="en-GB"> + <omicron/> + <psi xml:lang="no" xml:id="id1"> + <theta object="this-is-att-value" xml:id="id2"> + <xi content="100%" xml:lang="no-nb"/> + <omega object="another attribute value" xml:id="id3"/> + <nu xml:lang="no"/> + <omega xml:lang="no"> + <green>This text must be green</green> + </omega> + </theta> + </psi> + </delta> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]/omicron[@xml:lang="en"][@xml:id="id2"][following-sibling::theta[@title="solid 1px green"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::omicron)]//psi[contains(concat(@false,"$"),"e$")][@xml:lang="nb"][@xml:id="id4"]/phi[@or][@xml:lang="en-US"][not(following-sibling::*)]//kappa[starts-with(@class,"12")][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@xml:lang="no-nb"][not(preceding-sibling::*)]/theta[contains(concat(@att,"$"),"rue$")][@xml:id="id5"][not(preceding-sibling::*)]/theta[@insert][@xml:lang="en-US"][not(preceding-sibling::*)]/rho[contains(concat(@attribute,"$"),"lank$")][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[@xml:id="id6"][not(child::node())][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id7"]//delta//psi[@xml:id="id8"][not(child::node())][following-sibling::kappa[@attr][@xml:lang="no"][@xml:id="id9"]//eta[@attrib="100%"][@xml:lang="en-GB"][@xml:id="id10"]/tau[starts-with(@number,"_blank")][@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <omicron xml:lang="en" xml:id="id2"/> + <theta title="solid 1px green"> + <delta> + <omicron xml:lang="nb" xml:id="id3"> + <psi false="false" xml:lang="nb" xml:id="id4"> + <phi or="attribute value" xml:lang="en-US"> + <kappa class="123456789"> + <gamma xml:lang="no-nb"> + <theta att="true" xml:id="id5"> + <theta insert="_blank" xml:lang="en-US"> + <rho attribute="_blank"/> + <sigma xml:id="id6"/> + <zeta xml:lang="en-GB" xml:id="id7"> + <delta> + <psi xml:id="id8"/> + <kappa attr="attribute-value" xml:lang="no" xml:id="id9"> + <eta attrib="100%" xml:lang="en-GB" xml:id="id10"> + <tau number="_blank" xml:lang="nb" xml:id="id11"> + <green>This text must be green</green> + </tau> + </eta> + </kappa> + </delta> + </zeta> + </theta> + </theta> + </gamma> + </kappa> + </phi> + </psi> + </omicron> + </delta> + </theta> + </rho> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="en-US"]//omega[contains(concat(@object,"$"),"123456789$")][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][following-sibling::*[position()=2]][following-sibling::rho[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@attr][@xml:id="id1"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/lambda[starts-with(@number,"this.nodeValu")][@xml:id="id2"][not(following-sibling::*)]//omicron[contains(concat(@class,"$"),"0%$")][not(following-sibling::*)]//mu[contains(concat(@data,"$"),"te$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::mu[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 1]]/rho[starts-with(concat(@attrib,"-"),"123456789-")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@false="attribute value"][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@attrib="this-is-att-value"][@xml:id="id7"]//theta[not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@abort][preceding-sibling::*[position() = 1]][following-sibling::delta[contains(@title,"ibute-")][@xml:lang="en-GB"]/epsilon[starts-with(@and,"tr")][@xml:lang="en-US"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="en-US"> + <omega object="123456789"/> + <mu xml:lang="en-GB"/> + <rho xml:lang="nb"/> + <iota attr="_blank" xml:id="id1"> + <lambda number="this.nodeValue" xml:id="id2"> + <omicron class="100%"> + <mu data="attribute" xml:id="id3"> + <phi xml:lang="no"/> + <mu xml:lang="en" xml:id="id4"> + <rho attrib="123456789" xml:id="id5"/> + <omicron false="attribute value" xml:id="id6"/> + <xi attrib="this-is-att-value" xml:id="id7"> + <theta/> + <epsilon abort="content"/> + <delta title="attribute-value" xml:lang="en-GB"> + <epsilon and="true" xml:lang="en-US"> + <green>This text must be green</green> + </epsilon> + </delta> + </xi> + </mu> + </mu> + </omicron> + </lambda> + </iota> + </xi> + </tree> + </test> + <test> + <xpath>//pi[contains(concat(@class,"$"),"true$")]/tau//gamma[contains(@object,"ibute")][@xml:id="id1"][not(preceding-sibling::*)]//pi//*[@or="true"][@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]//theta[starts-with(@or,"fa")][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:id="id4"][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]/tau[contains(@or,"lank")][@xml:id="id6"][not(preceding-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <pi class="true"> + <tau> + <gamma object="attribute" xml:id="id1"> + <pi> + <any or="true" xml:lang="no-nb" xml:id="id2"> + <theta or="false" xml:lang="en-US" xml:id="id3"> + <iota xml:id="id4"/> + <nu xml:id="id5"/> + <mu xml:lang="en-GB"> + <tau or="_blank" xml:id="id6"> + <green>This text must be green</green> + </tau> + </mu> + </theta> + </any> + </pi> + </gamma> + </tau> + </pi> + </tree> + </test> + <test> + <xpath>//nu[contains(@or,"00%")][@xml:id="id1"]//xi[@xml:lang="en-US"]//gamma[@title][@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]/chi[starts-with(concat(@data,"-"),"attribute-")][@xml:id="id3"][not(preceding-sibling::*)]//alpha[contains(concat(@attribute,"$"),"x green$")][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[starts-with(concat(@attr,"-"),"solid 1px green-")]//zeta[starts-with(@desciption,"this.node")][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::zeta)]/psi[@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//omicron[contains(concat(@desciption,"$"),"0%$")][@xml:id="id7"][not(preceding-sibling::*)]/iota[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::theta[starts-with(concat(@number,"-"),"123456789-")][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::chi[@content="attribute"][@xml:lang="no"][@xml:id="id9"][following-sibling::iota[@xml:id="id10"][preceding-sibling::*[position() = 4]][following-sibling::beta[contains(concat(@src,"$"),"ttribute$")][@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 5]]//upsilon[starts-with(@src,"a")][@xml:lang="nb"][@xml:id="id12"]//eta[starts-with(concat(@class,"-"),"123456789-")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@xml:id="id13"][not(preceding-sibling::*)]/xi[@xml:id="id14"][not(preceding-sibling::*)]//omicron[@data][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <nu or="100%" xml:id="id1"> + <xi xml:lang="en-US"> + <gamma title="attribute value" xml:lang="no" xml:id="id2"> + <chi data="attribute" xml:id="id3"> + <alpha attribute="solid 1px green" xml:id="id4"/> + <phi attr="solid 1px green"> + <zeta desciption="this.nodeValue" xml:lang="no" xml:id="id5"> + <psi xml:lang="en-US" xml:id="id6"> + <omicron desciption="100%" xml:id="id7"> + <iota xml:lang="en-GB"/> + <iota/> + <theta number="123456789" xml:lang="en-GB" xml:id="id8"/> + <chi content="attribute" xml:lang="no" xml:id="id9"/> + <iota xml:id="id10"/> + <beta src="attribute" xml:lang="no" xml:id="id11"> + <upsilon src="attribute" xml:lang="nb" xml:id="id12"> + <eta class="123456789" xml:lang="nb"> + <chi xml:id="id13"> + <xi xml:id="id14"> + <omicron data="solid 1px green"> + <green>This text must be green</green> + </omicron> + </xi> + </chi> + </eta> + </upsilon> + </beta> + </omicron> + </psi> + </zeta> + </phi> + </chi> + </gamma> + </xi> + </nu> + </tree> + </test> + <test> + <xpath>//tau[@att][@xml:lang="no-nb"][@xml:id="id1"]/omega[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]//eta[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)]//delta[@number][@xml:lang="en-US"][following-sibling::beta[@string="_blank"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[contains(@object,"e")][@xml:lang="en-GB"][not(preceding-sibling::*)]/eta[contains(concat(@object,"$"),"attribute$")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[starts-with(concat(@number,"-"),"true-")][not(following-sibling::*)]//alpha[@xml:id="id4"][following-sibling::upsilon[@abort="false"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:id="id5"][following-sibling::gamma[@title][@xml:id="id6"][following-sibling::sigma[contains(concat(@desciption,"$"),"e$")][@xml:lang="no"][preceding-sibling::*[position() = 2]]/epsilon[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[not(following-sibling::*)]/gamma[not(preceding-sibling::*)][following-sibling::alpha[contains(@and,"%")][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::alpha)]/eta[not(preceding-sibling::*)]//theta[starts-with(concat(@number,"-"),"solid 1px green-")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::theta)]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <tau att="123456789" xml:lang="no-nb" xml:id="id1"> + <omega xml:lang="en" xml:id="id2"> + <eta xml:lang="en-GB" xml:id="id3"> + <delta number="100%" xml:lang="en-US"/> + <beta string="_blank"> + <psi object="true" xml:lang="en-GB"> + <eta object="attribute" xml:lang="en-US"/> + <chi number="true"> + <alpha xml:id="id4"/> + <upsilon abort="false"> + <xi xml:id="id5"/> + <gamma title="this-is-att-value" xml:id="id6"/> + <sigma desciption="this.nodeValue" xml:lang="no"> + <epsilon xml:id="id7"/> + <eta> + <gamma/> + <alpha and="100%"> + <eta> + <theta number="solid 1px green" xml:lang="nb"> + <green>This text must be green</green> + </theta> + </eta> + </alpha> + </eta> + </sigma> + </upsilon> + </chi> + </psi> + </beta> + </eta> + </omega> + </tau> + </tree> + </test> + <test> + <xpath>//eta[starts-with(concat(@false,"-"),"content-")][@xml:lang="no"]/omicron[contains(@class,"tri")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:id="id1"][following-sibling::zeta[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::eta[starts-with(@class,"co")][@xml:lang="nb"][@xml:id="id3"][following-sibling::tau[contains(@class,"ute-")][preceding-sibling::*[position() = 4]]/iota[@insert="this.nodeValue"][following-sibling::eta[starts-with(concat(@title,"-"),"attribute value-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(@false,"3456789")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]//epsilon[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]/pi[starts-with(concat(@abort,"-"),"attribute value-")][@xml:lang="no"][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <eta false="content" xml:lang="no"> + <omicron class="attribute" xml:lang="no-nb"/> + <xi xml:id="id1"/> + <zeta xml:lang="en" xml:id="id2"/> + <eta class="content" xml:lang="nb" xml:id="id3"/> + <tau class="attribute-value"> + <iota insert="this.nodeValue"/> + <eta title="attribute value"/> + <delta false="123456789" xml:lang="nb"> + <epsilon xml:lang="en-US" xml:id="id4"> + <pi abort="attribute value" xml:lang="no"> + <green>This text must be green</green> + </pi> + </epsilon> + </delta> + </tau> + </eta> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(concat(@or,"-"),"true-")][@xml:id="id1"]/xi[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(@attribute,"1234567")]//zeta[@src="content"][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::pi[@true][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][following-sibling::psi[@class][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::psi[contains(concat(@data,"$"),"23456789$")]/alpha[@xml:lang="en"][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[starts-with(@att,"12345678")][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id5"]/upsilon[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(preceding-sibling::upsilon or following-sibling::upsilon)]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <alpha or="true" xml:id="id1"> + <xi/> + <delta attribute="123456789"> + <zeta src="content" xml:lang="nb" xml:id="id2"/> + <epsilon/> + <pi xml:lang="en" xml:id="id3"/> + <pi true="attribute-value"/> + <psi class="100%" xml:lang="no-nb"/> + <psi data="123456789"> + <alpha xml:lang="en"/> + <beta att="123456789" xml:id="id4"/> + <pi xml:lang="no-nb" xml:id="id5"> + <upsilon xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </upsilon> + </pi> + </psi> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//rho//tau[contains(@content,"this")][@xml:id="id1"][not(following-sibling::*)]//kappa[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=5]][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id3"][not(child::node())][following-sibling::rho[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::omega[@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::theta[preceding-sibling::*[position() = 4]][not(preceding-sibling::theta)][not(child::node())][following-sibling::sigma[contains(concat(@true,"$"),"%$")][@xml:id="id5"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <tau content="this-is-att-value" xml:id="id1"> + <kappa xml:id="id2"> + <pi> + <lambda xml:lang="no-nb"/> + <gamma xml:lang="no-nb" xml:id="id3"/> + <rho xml:lang="nb"/> + <omega xml:lang="en" xml:id="id4"/> + <theta/> + <sigma true="100%" xml:id="id5"> + <green>This text must be green</green> + </sigma> + </pi> + </kappa> + </tau> + </rho> + </tree> + </test> + <test> + <xpath>//tau[contains(concat(@insert,"$"),"eValue$")][@xml:id="id1"]/mu[@number="solid 1px green"][@xml:id="id2"]/gamma[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::sigma[preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::alpha[starts-with(concat(@or,"-"),"this.nodeValue-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[starts-with(concat(@and,"-"),"another attribute value-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <tau insert="this.nodeValue" xml:id="id1"> + <mu number="solid 1px green" xml:id="id2"> + <gamma xml:lang="en-US"/> + <sigma/> + <alpha or="this.nodeValue" xml:lang="no-nb"/> + <sigma and="another attribute value" xml:lang="en-GB"> + <green>This text must be green</green> + </sigma> + </mu> + </tau> + </tree> + </test> + <test> + <xpath>//omicron[@xml:id="id1"]//*[contains(@desciption,"this-is-att")][@xml:lang="en"][not(preceding-sibling::*)]//phi[starts-with(concat(@data,"-"),"attribute value-")][@xml:id="id2"][not(preceding-sibling::*)]/delta[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en"][@xml:id="id3"]/xi[contains(concat(@number,"$"),"ank$")][not(preceding-sibling::*)][not(following-sibling::*)]//phi[not(preceding-sibling::*)]//iota[starts-with(concat(@number,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@abort="attribute value"][@xml:lang="no"][following-sibling::upsilon[@name][preceding-sibling::*[position() = 1]]//omega[@token][@xml:lang="no-nb"][@xml:id="id4"]//phi[@xml:lang="en"][@xml:id="id5"][following-sibling::epsilon[contains(@content,"se")][@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[not(following-sibling::*)]/sigma[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[starts-with(@or,"at")][@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[contains(@object,"i")][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:id="id1"> + <any desciption="this-is-att-value" xml:lang="en"> + <phi data="attribute value" xml:id="id2"> + <delta xml:lang="no-nb"/> + <psi xml:lang="en" xml:id="id3"> + <xi number="_blank"> + <phi> + <iota number="this.nodeValue"> + <theta abort="attribute value" xml:lang="no"/> + <upsilon name="_blank"> + <omega token="content" xml:lang="no-nb" xml:id="id4"> + <phi xml:lang="en" xml:id="id5"/> + <epsilon content="false" xml:lang="nb" xml:id="id6"/> + <omega> + <sigma xml:lang="en-US"> + <zeta or="attribute-value" xml:lang="nb"/> + <iota object="attribute-value"> + <green>This text must be green</green> + </iota> + </sigma> + </omega> + </omega> + </upsilon> + </iota> + </phi> + </xi> + </psi> + </phi> + </any> + </omicron> + </tree> + </test> + <test> + <xpath>//chi[@attribute][@xml:id="id1"]//upsilon[@xml:id="id2"][not(preceding-sibling::*)]/rho[@xml:id="id3"][following-sibling::*[@xml:lang="no"][following-sibling::kappa[@xml:id="id4"]/tau[@xml:lang="en-GB"][not(preceding-sibling::*)]//pi[@attrib][@xml:id="id5"][not(preceding-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <chi attribute="another attribute value" xml:id="id1"> + <upsilon xml:id="id2"> + <rho xml:id="id3"/> + <any xml:lang="no"/> + <kappa xml:id="id4"> + <tau xml:lang="en-GB"> + <pi attrib="_blank" xml:id="id5"> + <green>This text must be green</green> + </pi> + </tau> + </kappa> + </upsilon> + </chi> + </tree> + </test> + <test> + <xpath>//rho//omega//nu[@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]//omega[starts-with(concat(@attr,"-"),"another attribute value-")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::mu[@desciption][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[starts-with(concat(@number,"-"),"content-")][@xml:lang="en-GB"][not(preceding-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>1</nth> + </result> + <tree> + <rho> + <omega> + <nu xml:lang="no" xml:id="id1"> + <omega attr="another attribute value" xml:lang="nb"/> + <mu desciption="100%" xml:lang="no" xml:id="id2"> + <pi number="content" xml:lang="en-GB"> + <green>This text must be green</green> + </pi> + </mu> + </nu> + </omega> + </rho> + </tree> + </test> + <test> + <xpath>//gamma[@title][@xml:id="id1"]//pi[not(child::node())][following-sibling::xi[@xml:lang="en-GB"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@token][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::sigma[@xml:lang="no-nb"]/xi[contains(@number,"lue")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//delta[@xml:lang="en-GB"][not(preceding-sibling::*)]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <gamma title="_blank" xml:id="id1"> + <pi/> + <xi xml:lang="en-GB"/> + <iota token="_blank" xml:id="id2"/> + <sigma xml:lang="no-nb"> + <xi number="this.nodeValue" xml:lang="en-US"/> + <psi xml:lang="no-nb" xml:id="id3"> + <delta xml:lang="en-GB"> + <green>This text must be green</green> + </delta> + </psi> + </sigma> + </gamma> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@desciption,"-"),"true-")][@xml:lang="nb"][@xml:id="id1"]//sigma[@name="true"][@xml:lang="en"][not(preceding-sibling::*)]//upsilon[@attr][@xml:lang="nb"]/iota[@att][@xml:lang="en"][not(preceding-sibling::*)]/beta[@true][@xml:id="id2"]//upsilon[@insert][not(preceding-sibling::*)][following-sibling::mu[starts-with(concat(@att,"-"),"attribute value-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::beta[@xml:id="id3"][not(child::node())][following-sibling::sigma[starts-with(concat(@title,"-"),"content-")][preceding-sibling::*[position() = 3]]//chi[@attribute][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id6"][following-sibling::eta[@delete][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::pi[@xml:id="id8"][not(following-sibling::*)]//zeta[@xml:lang="no-nb"][not(following-sibling::*)]/delta[@xml:lang="no"]/alpha[@xml:lang="en-US"][@xml:id="id9"][not(preceding-sibling::*)]/delta[starts-with(concat(@class,"-"),"_blank-")][not(preceding-sibling::*)]//xi[not(preceding-sibling::*)]/nu[@src][@xml:lang="en"][not(preceding-sibling::nu)][following-sibling::alpha[@xml:lang="no"][not(child::node())][following-sibling::omega[@src][@xml:lang="no"][@xml:id="id10"][not(child::node())][following-sibling::tau[starts-with(concat(@number,"-"),"123456789-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>1</nth> + </result> + <tree> + <delta desciption="true" xml:lang="nb" xml:id="id1"> + <sigma name="true" xml:lang="en"> + <upsilon attr="attribute" xml:lang="nb"> + <iota att="this-is-att-value" xml:lang="en"> + <beta true="attribute" xml:id="id2"> + <upsilon insert="attribute-value"/> + <mu att="attribute value" xml:lang="en"/> + <beta xml:id="id3"/> + <sigma title="content"> + <chi attribute="attribute value" xml:lang="en" xml:id="id4"> + <eta xml:lang="en" xml:id="id5"/> + <delta xml:id="id6"/> + <eta delete="solid 1px green" xml:id="id7"/> + <pi xml:id="id8"> + <zeta xml:lang="no-nb"> + <delta xml:lang="no"> + <alpha xml:lang="en-US" xml:id="id9"> + <delta class="_blank"> + <xi> + <nu src="100%" xml:lang="en"/> + <alpha xml:lang="no"/> + <omega src="attribute" xml:lang="no" xml:id="id10"/> + <tau number="123456789"> + <green>This text must be green</green> + </tau> + </xi> + </delta> + </alpha> + </delta> + </zeta> + </pi> + </chi> + </sigma> + </beta> + </iota> + </upsilon> + </sigma> + </delta> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//tau[@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]/delta[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@attribute][@xml:id="id4"][not(following-sibling::*)]//epsilon[@attribute][@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::rho[@and][@xml:lang="en-US"][not(following-sibling::*)]//alpha[@false][@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::alpha[@xml:id="id5"][not(following-sibling::*)]/omicron[@xml:lang="en-US"][@xml:id="id6"][following-sibling::xi[@xml:lang="en"][not(following-sibling::*)]/epsilon[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]/delta[starts-with(concat(@or,"-"),"false-")][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id8"][following-sibling::pi[contains(@and,"ute")][@xml:lang="en"][@xml:id="id9"][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <tau xml:lang="no-nb" xml:id="id2"> + <delta xml:lang="nb" xml:id="id3"/> + <theta attribute="this.nodeValue" xml:id="id4"> + <epsilon attribute="false" xml:lang="en-US"/> + <rho and="false" xml:lang="en-US"> + <alpha false="false" xml:lang="no"/> + <alpha xml:id="id5"> + <omicron xml:lang="en-US" xml:id="id6"/> + <xi xml:lang="en"> + <epsilon xml:lang="en-US"> + <lambda xml:lang="no-nb" xml:id="id7"> + <delta or="false"/> + <delta xml:lang="en-GB" xml:id="id8"/> + <pi and="attribute" xml:lang="en" xml:id="id9"> + <green>This text must be green</green> + </pi> + </lambda> + </epsilon> + </xi> + </alpha> + </rho> + </theta> + </tau> + </chi> + </tree> + </test> + <test> + <xpath>//mu[starts-with(@abort,"1")]//*[@delete="100%"][@xml:lang="en"][following-sibling::omicron[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[@xml:lang="nb"]/kappa[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]//chi[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <mu abort="123456789"> + <any delete="100%" xml:lang="en"/> + <omicron xml:id="id1"/> + <mu xml:lang="nb"> + <kappa xml:lang="no" xml:id="id2"> + <chi xml:lang="nb" xml:id="id3"> + <green>This text must be green</green> + </chi> + </kappa> + </mu> + </mu> + </tree> + </test> + <test> + <xpath>//eta[contains(concat(@class,"$"),"100%$")][@xml:lang="nb"]//delta[starts-with(@or,"another attribute val")][@xml:id="id1"][not(preceding-sibling::delta)]/nu[contains(@false,"6789")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]//pi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[contains(@abort,"t")][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::psi[not(following-sibling::*)]/tau[@xml:id="id4"][not(child::node())][following-sibling::nu[contains(@token,"e")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[@content][@xml:id="id6"]//pi[contains(concat(@object,"$"),"23456789$")][@xml:lang="no-nb"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@false][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::psi[not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho[@xml:id="id9"][preceding-sibling::*[position() = 3]]/xi[@attribute][@xml:lang="no"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::iota[contains(@src,"nk")][@xml:lang="no-nb"][not(child::node())][following-sibling::delta[starts-with(concat(@content,"-"),"100%-")][preceding-sibling::*[position() = 2]]//iota[@number][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <eta class="100%" xml:lang="nb"> + <delta or="another attribute value" xml:id="id1"> + <nu false="123456789" xml:lang="nb" xml:id="id2"> + <pi xml:lang="en-GB"/> + <psi abort="content" xml:lang="en" xml:id="id3"/> + <psi> + <tau xml:id="id4"/> + <nu token="attribute-value" xml:id="id5"> + <tau content="this.nodeValue" xml:id="id6"> + <pi object="123456789" xml:lang="no-nb" xml:id="id7"> + <upsilon false="attribute value" xml:id="id8"/> + <psi/> + <theta/> + <rho xml:id="id9"> + <xi attribute="this-is-att-value" xml:lang="no" xml:id="id10"/> + <iota src="_blank" xml:lang="no-nb"/> + <delta content="100%"> + <iota number="content" xml:id="id11"> + <green>This text must be green</green> + </iota> + </delta> + </rho> + </pi> + </tau> + </nu> + </psi> + </nu> + </delta> + </eta> + </tree> + </test> + <test> + <xpath>//nu/sigma[starts-with(@number,"attribu")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::kappa[contains(@src,"en")][not(following-sibling::*)]//zeta[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[@attrib][@xml:id="id2"][not(following-sibling::*)]//theta//chi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::kappa[@title][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="no"][@xml:id="id4"][following-sibling::lambda[@object][@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]//chi[starts-with(@object,"_b")][@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]/chi[@xml:id="id7"][not(following-sibling::*)]//phi[not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <nu> + <sigma number="attribute" xml:lang="en-GB"/> + <psi xml:lang="en-US" xml:id="id1"/> + <kappa src="solid 1px green"> + <zeta xml:lang="no-nb"/> + <sigma attrib="123456789" xml:id="id2"> + <theta> + <chi xml:lang="no-nb"/> + <kappa title="false" xml:lang="en-US" xml:id="id3"/> + <xi xml:lang="no" xml:id="id4"/> + <lambda object="attribute value" xml:lang="en" xml:id="id5"> + <chi object="_blank" xml:lang="en-US" xml:id="id6"> + <chi xml:id="id7"> + <phi> + <green>This text must be green</green> + </phi> + </chi> + </chi> + </lambda> + </theta> + </sigma> + </kappa> + </nu> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@attrib,"$"),"89$")][@xml:id="id1"]//phi[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:lang="en"][not(following-sibling::*)]/kappa[contains(@abort,"eValue")][@xml:lang="no"][not(preceding-sibling::*)]//upsilon[@attr="this.nodeValue"][not(child::node())][following-sibling::sigma//omega[@class][@xml:lang="en"][following-sibling::phi[@xml:id="id2"]/gamma[contains(concat(@abort,"$"),"eValue$")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::zeta[starts-with(@attr,"1")][@xml:id="id4"][preceding-sibling::*[position() = 1]]/psi[starts-with(concat(@insert,"-"),"_blank-")][@xml:lang="no-nb"][@xml:id="id5"]//zeta[@attrib][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/omega[@true="content"]/alpha[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@data][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[@xml:id="id6"][not(following-sibling::*)]//rho[contains(concat(@att,"$"),"ue$")][@xml:id="id7"][not(preceding-sibling::*)]//*[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <alpha attrib="123456789" xml:id="id1"> + <phi src="this.nodeValue" xml:lang="en"> + <kappa abort="this.nodeValue" xml:lang="no"> + <upsilon attr="this.nodeValue"/> + <sigma> + <omega class="100%" xml:lang="en"/> + <phi xml:id="id2"> + <gamma abort="this.nodeValue" xml:lang="no-nb" xml:id="id3"/> + <zeta attr="100%" xml:id="id4"> + <psi insert="_blank" xml:lang="no-nb" xml:id="id5"> + <zeta attrib="attribute value" xml:lang="en-US"> + <omega true="content"> + <alpha xml:lang="nb"/> + <kappa data="_blank"/> + <chi xml:id="id6"> + <rho att="true" xml:id="id7"> + <any xml:lang="no"> + <green>This text must be green</green> + </any> + </rho> + </chi> + </omega> + </zeta> + </psi> + </zeta> + </phi> + </sigma> + </kappa> + </phi> + </alpha> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-GB"]//delta[@src="123456789"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[contains(@string,"ue")][@xml:lang="en-GB"][@xml:id="id1"][not(child::node())][following-sibling::chi[@xml:id="id2"][following-sibling::chi[@token="attribute-value"][@xml:lang="en"][preceding-sibling::*[position() = 2]]//alpha[contains(@or,"ute value")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::tau[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(following-sibling::omega)]/theta[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@delete][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::phi[@xml:id="id6"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-GB"> + <delta src="123456789" xml:lang="no-nb"> + <nu string="true" xml:lang="en-GB" xml:id="id1"/> + <chi xml:id="id2"/> + <chi token="attribute-value" xml:lang="en"> + <alpha or="another attribute value" xml:lang="no-nb" xml:id="id3"/> + <tau xml:id="id4"/> + <omega xml:lang="en" xml:id="id5"> + <theta xml:lang="no"> + <nu delete="attribute-value" xml:lang="no"/> + <phi xml:id="id6"> + <green>This text must be green</green> + </phi> + </theta> + </omega> + </chi> + </delta> + </phi> + </tree> + </test> + <test> + <xpath>//zeta[@token="attribute"][@xml:lang="no"]/chi[@object][not(following-sibling::*)]/pi[@xml:id="id1"][not(child::node())][following-sibling::psi[contains(concat(@abort,"$"),"x green$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/*[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[contains(@insert,"e")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[@src][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="en-US"][not(following-sibling::*)]/pi[@attr][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <zeta token="attribute" xml:lang="no"> + <chi object="true"> + <pi xml:id="id1"/> + <psi abort="solid 1px green" xml:lang="en-US"> + <any xml:lang="en-GB"/> + <omega insert="false" xml:lang="nb"> + <tau xml:lang="no-nb" xml:id="id2"/> + <theta> + <mu src="another attribute value" xml:lang="no-nb"/> + <tau xml:lang="en-US"> + <pi attr="this.nodeValue" xml:id="id3"> + <green>This text must be green</green> + </pi> + </tau> + </theta> + </omega> + </psi> + </chi> + </zeta> + </tree> + </test> + <test> + <xpath>//zeta/psi[contains(@data,"nt")][not(preceding-sibling::*)][not(following-sibling::*)]//omega[@xml:id="id1"][following-sibling::beta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:lang="no"][not(preceding-sibling::*)]//delta[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::psi[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="en"][not(following-sibling::*)]//sigma[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi/pi[@xml:lang="nb"][@xml:id="id5"]/alpha[starts-with(@data,"att")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[starts-with(@object,"tr")][@xml:lang="no"]//xi[@false="attribute"][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@string]//phi[contains(@or,"nt")][not(preceding-sibling::*)][not(following-sibling::*)]//xi[starts-with(concat(@string,"-"),"100%-")][@xml:id="id7"][not(following-sibling::*)]/nu[@data="attribute-value"][@xml:lang="en-GB"][@xml:id="id8"]/eta[starts-with(concat(@desciption,"-"),"content-")][@xml:lang="no-nb"][not(following-sibling::*)]/beta[starts-with(@string,"f")][@xml:id="id9"]/omega[not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:id="id10"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <zeta> + <psi data="content"> + <omega xml:id="id1"/> + <beta> + <xi xml:lang="no"> + <delta xml:lang="nb" xml:id="id2"/> + <psi xml:id="id3"/> + <lambda xml:lang="en"> + <sigma xml:lang="no-nb" xml:id="id4"/> + <chi> + <pi xml:lang="nb" xml:id="id5"> + <alpha data="attribute value" xml:id="id6"> + <delta object="true" xml:lang="no"> + <xi false="attribute" xml:lang="en-US"> + <pi string="attribute-value"> + <phi or="content"> + <xi string="100%" xml:id="id7"> + <nu data="attribute-value" xml:lang="en-GB" xml:id="id8"> + <eta desciption="content" xml:lang="no-nb"> + <beta string="false" xml:id="id9"> + <omega/> + <any xml:id="id10"> + <green>This text must be green</green> + </any> + </beta> + </eta> + </nu> + </xi> + </phi> + </pi> + </xi> + </delta> + </alpha> + </pi> + </chi> + </lambda> + </xi> + </beta> + </psi> + </zeta> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(concat(@desciption,"-"),"false-")][@xml:lang="en-US"]/iota[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(concat(@attrib,"-"),"false-")][@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(preceding-sibling::upsilon)]//zeta[@xml:lang="nb"][@xml:id="id3"][not(child::node())][following-sibling::eta[@xml:lang="en-US"]/iota[@xml:lang="no"][not(preceding-sibling::*)]//kappa[contains(concat(@title,"$"),"k$")][not(preceding-sibling::*)][following-sibling::gamma[@object][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:id="id5"][following-sibling::xi[@xml:id="id6"][not(following-sibling::*)]/rho[@false][following-sibling::theta[starts-with(@attr,"attribut")][@xml:lang="en-GB"][not(following-sibling::*)]/*[@xml:lang="en"][not(following-sibling::*)]//nu[contains(concat(@delete,"$"),"nk$")][@xml:lang="en"][@xml:id="id7"][following-sibling::iota[starts-with(concat(@att,"-"),"attribute-")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@or="attribute-value"][@xml:lang="no"][not(following-sibling::*)][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>1</nth> + </result> + <tree> + <epsilon desciption="false" xml:lang="en-US"> + <iota xml:lang="nb"> + <iota xml:lang="nb" xml:id="id1"/> + <upsilon attrib="false" xml:lang="en-US" xml:id="id2"> + <zeta xml:lang="nb" xml:id="id3"/> + <eta xml:lang="en-US"> + <iota xml:lang="no"> + <kappa title="_blank"/> + <gamma object="this.nodeValue" xml:id="id4"/> + <mu xml:id="id5"/> + <xi xml:id="id6"> + <rho false="true"/> + <theta attr="attribute value" xml:lang="en-GB"> + <any xml:lang="en"> + <nu delete="_blank" xml:lang="en" xml:id="id7"/> + <iota att="attribute"/> + <iota or="attribute-value" xml:lang="no"> + <green>This text must be green</green> + </iota> + </any> + </theta> + </xi> + </iota> + </eta> + </upsilon> + </iota> + </epsilon> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no"]/mu[@title][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[contains(concat(@false,"$"),"ue$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::theta[@attrib="false"][@xml:lang="en-US"][preceding-sibling::*[position() = 2]]/omicron[contains(concat(@insert,"$"),"deValue$")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@xml:lang="nb"][not(child::node())][following-sibling::iota[contains(@desciption,"ut")][@xml:id="id5"][preceding-sibling::*[position() = 3]]//sigma[contains(@src,"e")][@xml:id="id6"]/beta[starts-with(concat(@false,"-"),"true-")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[starts-with(@att,"fal")][@xml:id="id8"][not(preceding-sibling::eta)][not(child::node())][following-sibling::xi[@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::mu[preceding-sibling::*[position() = 3]][following-sibling::nu[@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:id="id9"]//omicron[@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@title][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no"> + <mu title="this-is-att-value" xml:lang="en-US" xml:id="id1"/> + <chi false="true" xml:id="id2"/> + <theta attrib="false" xml:lang="en-US"> + <omicron insert="this.nodeValue" xml:lang="no-nb" xml:id="id3"/> + <xi xml:lang="en" xml:id="id4"/> + <gamma xml:lang="nb"/> + <iota desciption="attribute-value" xml:id="id5"> + <sigma src="false" xml:id="id6"> + <beta false="true" xml:lang="no" xml:id="id7"/> + <eta att="false" xml:id="id8"/> + <xi xml:lang="no"/> + <mu/> + <nu xml:lang="en-GB"/> + <mu xml:id="id9"> + <omicron xml:id="id10"> + <beta title="attribute" xml:id="id11"> + <green>This text must be green</green> + </beta> + </omicron> + </mu> + </sigma> + </iota> + </theta> + </tau> + </tree> + </test> + <test> + <xpath>//rho[@xml:lang="no"][@xml:id="id1"]//iota[@data][not(preceding-sibling::*)]//upsilon[@attrib][not(child::node())][following-sibling::lambda[@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]/psi[contains(concat(@delete,"$"),"nk$")][@xml:lang="no-nb"][not(following-sibling::*)]/zeta[@or][@xml:lang="en-US"][@xml:id="id3"][not(child::node())][following-sibling::xi[contains(@abort,"ue")][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::gamma[starts-with(@false,"conten")][@xml:id="id5"][not(following-sibling::*)]/psi[starts-with(concat(@or,"-"),"100%-")][@xml:id="id6"][not(following-sibling::*)]/pi[@xml:id="id7"]/phi[starts-with(@insert,"false")][not(child::node())][following-sibling::tau[@data][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/gamma[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[contains(concat(@att,"$"),"tribute-value$")][@xml:lang="nb"][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//beta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[starts-with(concat(@desciption,"-"),"attribute value-")][@xml:id="id9"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:lang="no"][@xml:id="id10"][not(following-sibling::rho)]//beta[@xml:lang="nb"]/zeta[@xml:lang="no-nb"][@xml:id="id11"][not(following-sibling::*)]//upsilon[@true="true"][@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:lang="no" xml:id="id1"> + <iota data="attribute value"> + <upsilon attrib="solid 1px green"/> + <lambda xml:lang="nb" xml:id="id2"> + <psi delete="_blank" xml:lang="no-nb"> + <zeta or="_blank" xml:lang="en-US" xml:id="id3"/> + <xi abort="true" xml:id="id4"/> + <gamma false="content" xml:id="id5"> + <psi or="100%" xml:id="id6"> + <pi xml:id="id7"> + <phi insert="false"/> + <tau data="100%"> + <gamma xml:lang="no-nb" xml:id="id8"> + <alpha att="attribute-value" xml:lang="nb"/> + <sigma xml:lang="en-GB"> + <beta xml:lang="no"/> + <any desciption="attribute value" xml:id="id9"/> + <rho xml:lang="no" xml:id="id10"> + <beta xml:lang="nb"> + <zeta xml:lang="no-nb" xml:id="id11"> + <upsilon true="true" xml:id="id12"> + <rho xml:lang="nb"> + <green>This text must be green</green> + </rho> + </upsilon> + </zeta> + </beta> + </rho> + </sigma> + </gamma> + </tau> + </pi> + </psi> + </gamma> + </psi> + </lambda> + </iota> + </rho> + </tree> + </test> + <test> + <xpath>//rho//rho[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::nu[@class][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[not(preceding-sibling::*)][not(following-sibling::*)]/xi[starts-with(@abort,"attribu")][@xml:lang="en-GB"][@xml:id="id3"]//theta[@xml:id="id4"][not(child::node())][following-sibling::nu[starts-with(@delete,"another attrib")][@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@class][@xml:id="id6"][following-sibling::iota[@attrib][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@xml:id="id8"]//gamma[contains(concat(@attrib,"$"),"lue$")][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[not(child::node())][following-sibling::*[@or][@xml:id="id10"][following-sibling::psi[@xml:lang="nb"][not(following-sibling::*)]/gamma[@content][@xml:lang="no-nb"][not(following-sibling::*)]//lambda[@xml:id="id11"][not(child::node())][following-sibling::gamma[@xml:id="id12"]/mu[@xml:id="id13"][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>1</nth> + </result> + <tree> + <rho> + <rho xml:lang="no-nb" xml:id="id1"/> + <sigma xml:lang="en-GB" xml:id="id2"/> + <nu class="false"> + <nu> + <xi abort="attribute-value" xml:lang="en-GB" xml:id="id3"> + <theta xml:id="id4"/> + <nu delete="another attribute value" xml:lang="no" xml:id="id5"> + <kappa class="_blank" xml:id="id6"/> + <iota attrib="content" xml:lang="nb" xml:id="id7"> + <psi xml:id="id8"> + <gamma attrib="this-is-att-value" xml:id="id9"> + <theta/> + <any or="attribute value" xml:id="id10"/> + <psi xml:lang="nb"> + <gamma content="123456789" xml:lang="no-nb"> + <lambda xml:id="id11"/> + <gamma xml:id="id12"> + <mu xml:id="id13"> + <green>This text must be green</green> + </mu> + </gamma> + </gamma> + </psi> + </gamma> + </psi> + </iota> + </nu> + </xi> + </nu> + </nu> + </rho> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-US"]/psi[contains(concat(@src,"$"),"value$")][@xml:id="id1"]//zeta[not(child::node())][following-sibling::pi[starts-with(@abort,"this-is-att-va")][@xml:id="id2"]//sigma[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 2]]//eta[contains(@attrib,"e")][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@true][@xml:lang="no"][following-sibling::kappa[contains(concat(@desciption,"$"),"0%$")][@xml:id="id6"][not(child::node())][following-sibling::omicron[starts-with(@attrib,"attribute-v")]/*[@and][not(preceding-sibling::any)][following-sibling::omicron[contains(@number,"ribute-value")][@xml:lang="nb"][following-sibling::eta[@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-US"> + <psi src="attribute value" xml:id="id1"> + <zeta/> + <pi abort="this-is-att-value" xml:id="id2"> + <sigma xml:lang="en-US" xml:id="id3"/> + <omega xml:lang="en-GB"/> + <theta xml:lang="en-US" xml:id="id4"> + <eta attrib="false"> + <upsilon xml:id="id5"/> + <lambda true="this.nodeValue" xml:lang="no"/> + <kappa desciption="100%" xml:id="id6"/> + <omicron attrib="attribute-value"> + <any and="true"/> + <omicron number="attribute-value" xml:lang="nb"/> + <eta xml:lang="nb" xml:id="id7"> + <green>This text must be green</green> + </eta> + </omicron> + </eta> + </theta> + </pi> + </psi> + </phi> + </tree> + </test> + <test> + <xpath>//rho[@object="false"]/phi[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::*[@xml:id="id2"][not(following-sibling::*)]//nu[@title="attribute value"][@xml:lang="no"]/upsilon[starts-with(@desciption,"solid ")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[@attrib][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[starts-with(@true,"1")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="en"][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 2]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <rho object="false"> + <phi xml:id="id1"/> + <any xml:id="id2"> + <nu title="attribute value" xml:lang="no"> + <upsilon desciption="solid 1px green" xml:lang="nb" xml:id="id3"/> + <tau attrib="attribute" xml:id="id4"> + <eta true="100%" xml:lang="en-US"/> + <psi xml:lang="en"/> + <eta> + <green>This text must be green</green> + </eta> + </tau> + </nu> + </any> + </rho> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]/omega[not(child::node())][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[starts-with(concat(@title,"-"),"false-")]/delta[@true="true"]//zeta[contains(concat(@object,"$"),"nk$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <omega/> + <delta xml:id="id2"> + <omega title="false"> + <delta true="true"> + <zeta object="_blank" xml:id="id3"> + <green>This text must be green</green> + </zeta> + </delta> + </omega> + </delta> + </zeta> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no-nb"]//*[@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]/xi[@xml:lang="no-nb"][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::chi[@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::lambda[@insert]//mu[@title][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::psi[@xml:lang="en-GB"][@xml:id="id5"][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"]/delta[starts-with(@src,"t")][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no-nb"> + <any xml:lang="no-nb" xml:id="id1"> + <xi xml:lang="no-nb"/> + <delta xml:lang="en-GB" xml:id="id2"/> + <chi xml:id="id3"/> + <lambda insert="this.nodeValue"> + <mu title="_blank" xml:id="id4"/> + <lambda xml:lang="no"/> + <psi xml:lang="en-GB" xml:id="id5"/> + <epsilon xml:lang="en-GB"> + <delta src="true" xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </delta> + </epsilon> + </lambda> + </any> + </kappa> + </tree> + </test> + <test> + <xpath>//epsilon[@or][@xml:lang="no-nb"]/eta[@false][following-sibling::mu[@false="another attribute value"][@xml:lang="en"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[@object="this-is-att-value"][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[@xml:lang="nb"][not(child::node())][following-sibling::mu[preceding-sibling::*[position() = 1]]/pi[starts-with(concat(@delete,"-"),"content-")][@xml:lang="no"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <epsilon or="attribute-value" xml:lang="no-nb"> + <eta false="this.nodeValue"/> + <mu false="another attribute value" xml:lang="en" xml:id="id1"> + <upsilon object="this-is-att-value" xml:lang="en-US"/> + <lambda xml:lang="nb" xml:id="id2"> + <eta xml:lang="nb"/> + <mu> + <pi delete="content" xml:lang="no"> + <green>This text must be green</green> + </pi> + </mu> + </lambda> + </mu> + </epsilon> + </tree> + </test> + <test> + <xpath>//omega[contains(@attribute,"u")][@xml:lang="en-US"]/zeta[@object="100%"][@xml:id="id1"][not(preceding-sibling::*)]//eta[@xml:id="id2"][not(following-sibling::*)]//upsilon[starts-with(concat(@token,"-"),"solid 1px green-")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@insert][following-sibling::*[position()=1]][following-sibling::tau[contains(@string,"bute")][preceding-sibling::*[position() = 1]]/omega[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[starts-with(concat(@content,"-"),"content-")][@xml:id="id6"][preceding-sibling::*[position() = 1]]//omicron[starts-with(@insert,"_bl")][@xml:lang="no"]//zeta[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id8"][following-sibling::*[position()=2]][not(preceding-sibling::alpha)][following-sibling::psi[@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::nu[@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//alpha[@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[@xml:lang="en"][@xml:id="id12"][not(preceding-sibling::*)]/epsilon[contains(@true,"Value")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[@true][@xml:lang="no-nb"][@xml:id="id13"][not(child::node())][following-sibling::tau[@xml:id="id14"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega attribute="true" xml:lang="en-US"> + <zeta object="100%" xml:id="id1"> + <eta xml:id="id2"> + <upsilon token="solid 1px green" xml:lang="nb" xml:id="id3"> + <iota insert="another attribute value"/> + <tau string="attribute value"> + <omega and="this.nodeValue" xml:lang="en" xml:id="id4"> + <eta xml:id="id5"/> + <nu content="content" xml:id="id6"> + <omicron insert="_blank" xml:lang="no"> + <zeta xml:id="id7"/> + <alpha xml:id="id8"/> + <psi xml:lang="no" xml:id="id9"/> + <nu xml:lang="nb" xml:id="id10"> + <alpha xml:id="id11"/> + <beta xml:lang="nb"> + <lambda xml:lang="en" xml:id="id12"> + <epsilon true="this.nodeValue" xml:lang="en-US"> + <tau true="123456789" xml:lang="no-nb" xml:id="id13"/> + <tau xml:id="id14"> + <green>This text must be green</green> + </tau> + </epsilon> + </lambda> + </beta> + </nu> + </omicron> + </nu> + </omega> + </tau> + </upsilon> + </eta> + </zeta> + </omega> + </tree> + </test> + <test> + <xpath>//xi[@true]//xi[not(preceding-sibling::*)][following-sibling::upsilon[contains(@or,"tent")][preceding-sibling::*[position() = 1]]/kappa[@attrib][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@name][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::xi[contains(@abort,"23456789")][@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 2]][following-sibling::alpha[following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//beta[@object][@xml:lang="en-US"][not(preceding-sibling::*)]/phi[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(preceding-sibling::phi)][not(child::node())][following-sibling::gamma[starts-with(concat(@attribute,"-"),"this-")][following-sibling::theta[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>1</nth> + </result> + <tree> + <xi true="123456789"> + <xi/> + <upsilon or="content"> + <kappa attrib="false"/> + <phi name="another attribute value" xml:lang="no-nb"/> + <xi abort="123456789" xml:lang="en-US" xml:id="id1"/> + <alpha/> + <omicron xml:lang="nb" xml:id="id2"> + <beta object="this-is-att-value" xml:lang="en-US"> + <phi xml:lang="en-US" xml:id="id3"/> + <gamma attribute="this-is-att-value"/> + <theta xml:lang="en" xml:id="id4"> + <green>This text must be green</green> + </theta> + </beta> + </omicron> + </upsilon> + </xi> + </tree> + </test> + <test> + <xpath>//lambda[contains(concat(@attr,"$"),"ontent$")][@xml:lang="no-nb"][@xml:id="id1"]/pi[@xml:lang="en-US"][@xml:id="id2"]//sigma[starts-with(concat(@true,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::psi[starts-with(concat(@src,"-"),"_blank-")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[starts-with(@name,"_b")][not(following-sibling::*)]//theta[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[@attrib="attribute-value"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta[contains(concat(@object,"$"),"rue$")][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[starts-with(@false,"tru")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/*[@xml:lang="no-nb"][not(preceding-sibling::*)]/epsilon[@xml:lang="no"][not(following-sibling::*)]/tau[@abort][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[contains(concat(@insert,"$"),"is-att-value$")][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@attrib="false"][@xml:id="id9"][not(following-sibling::*)]/psi[@abort][@xml:lang="no-nb"][not(preceding-sibling::*)]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <lambda attr="content" xml:lang="no-nb" xml:id="id1"> + <pi xml:lang="en-US" xml:id="id2"> + <sigma true="attribute-value"> + <delta xml:lang="en-GB" xml:id="id3"/> + <psi src="_blank" xml:lang="nb" xml:id="id4"/> + <omicron xml:lang="no" xml:id="id5"> + <alpha/> + <theta name="_blank"> + <theta/> + <chi attrib="attribute-value"> + <zeta object="true"/> + <theta false="true" xml:lang="en-US" xml:id="id6"> + <any xml:lang="no-nb"> + <epsilon xml:lang="no"> + <tau abort="attribute-value" xml:lang="en" xml:id="id7"/> + <beta insert="this-is-att-value" xml:id="id8"/> + <zeta attrib="false" xml:id="id9"> + <psi abort="100%" xml:lang="no-nb"> + <green>This text must be green</green> + </psi> + </zeta> + </epsilon> + </any> + </theta> + </chi> + </theta> + </omicron> + </sigma> + </pi> + </lambda> + </tree> + </test> + <test> + <xpath>//sigma/lambda[not(preceding-sibling::*)]//delta[@true][not(child::node())][following-sibling::delta[starts-with(concat(@desciption,"-"),"attribute-")][following-sibling::*[position()=2]][following-sibling::pi[@delete="123456789"][@xml:lang="no"][@xml:id="id1"][following-sibling::zeta[contains(concat(@or,"$"),"6789$")]//gamma[@xml:id="id2"][following-sibling::pi[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//lambda[@xml:id="id4"]/zeta[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::kappa[not(child::node())][following-sibling::epsilon[@abort][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 2]]/alpha[@false][@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]//zeta[contains(@desciption,"t")][@xml:id="id8"][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <lambda> + <delta true="123456789"/> + <delta desciption="attribute-value"/> + <pi delete="123456789" xml:lang="no" xml:id="id1"/> + <zeta or="123456789"> + <gamma xml:id="id2"/> + <pi xml:lang="nb" xml:id="id3"> + <lambda xml:id="id4"> + <zeta xml:lang="no-nb" xml:id="id5"/> + <kappa/> + <epsilon abort="100%" xml:lang="no-nb" xml:id="id6"> + <alpha false="attribute" xml:lang="no-nb" xml:id="id7"> + <zeta desciption="content" xml:id="id8"> + <green>This text must be green</green> + </zeta> + </alpha> + </epsilon> + </lambda> + </pi> + </zeta> + </lambda> + </sigma> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no"]//gamma[not(preceding-sibling::*)]//chi[contains(@or,"ue")][not(child::node())][following-sibling::sigma[@xml:lang="en"]/iota[@xml:id="id1"][not(child::node())][following-sibling::eta[starts-with(@object,"solid 1px ")][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no"> + <gamma> + <chi or="true"/> + <sigma xml:lang="en"> + <iota xml:id="id1"/> + <eta object="solid 1px green" xml:lang="no" xml:id="id2"> + <green>This text must be green</green> + </eta> + </sigma> + </gamma> + </lambda> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="en-GB"]//beta[contains(@content,"ten")][@xml:lang="no"][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[contains(@delete,"_bl")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/psi[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)]//delta[starts-with(concat(@title,"-"),"another attribute value-")][not(preceding-sibling::*)]/alpha[@attrib][@xml:id="id3"][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::epsilon)]//omicron[contains(concat(@attribute,"$"),"s-is-att-value$")][@xml:id="id6"][following-sibling::tau[@xml:id="id7"][not(following-sibling::*)]/xi[@object="false"][@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@number][preceding-sibling::*[position() = 1]][following-sibling::gamma[contains(concat(@attrib,"$"),"ue$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]//eta[@number][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[not(following-sibling::*)]//epsilon[starts-with(@name,"con")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="no"][following-sibling::zeta[starts-with(@token,"con")][@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//upsilon[contains(@class,"lue")][@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::kappa[@xml:lang="no"][@xml:id="id11"]//mu/tau[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>1</nth> + </result> + <tree> + <beta xml:lang="en-GB"> + <beta content="content" xml:lang="no" xml:id="id1"/> + <eta delete="_blank" xml:lang="en-US"> + <psi xml:lang="en-GB" xml:id="id2"> + <delta title="another attribute value"> + <alpha attrib="_blank" xml:id="id3"/> + <alpha xml:lang="en-GB" xml:id="id4"> + <epsilon xml:lang="en-GB" xml:id="id5"> + <omicron attribute="this-is-att-value" xml:id="id6"/> + <tau xml:id="id7"> + <xi object="false" xml:lang="en-US" xml:id="id8"/> + <xi number="100%"/> + <gamma attrib="attribute value" xml:lang="nb"> + <eta number="solid 1px green" xml:id="id9"> + <epsilon> + <epsilon name="content"/> + <omicron xml:lang="no"/> + <zeta token="content" xml:lang="no" xml:id="id10"> + <upsilon class="another attribute value" xml:lang="no-nb"/> + <kappa xml:lang="no" xml:id="id11"> + <mu> + <tau> + <green>This text must be green</green> + </tau> + </mu> + </kappa> + </zeta> + </epsilon> + </eta> + </gamma> + </tau> + </epsilon> + </alpha> + </delta> + </psi> + </eta> + </beta> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-US"]//sigma[starts-with(concat(@name,"-"),"_blank-")][@xml:id="id1"][following-sibling::delta[starts-with(@false,"1")][not(following-sibling::*)]/delta[starts-with(@delete,"attr")][not(preceding-sibling::*)][not(following-sibling::*)]/pi[starts-with(concat(@class,"-"),"attribute-")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::eta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[@abort][not(preceding-sibling::*)][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 1]]/lambda[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="nb"][preceding-sibling::*[position() = 1]]//kappa[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::kappa or following-sibling::kappa)]//mu[contains(@abort,"green")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id6"]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-US"> + <sigma name="_blank" xml:id="id1"/> + <delta false="123456789"> + <delta delete="attribute-value"> + <pi class="attribute-value" xml:lang="no" xml:id="id2"/> + <eta xml:lang="en-GB"> + <epsilon abort="false"/> + <beta xml:id="id3"> + <lambda xml:id="id4"> + <upsilon xml:id="id5"> + <gamma xml:lang="no-nb"/> + <gamma xml:lang="nb"> + <kappa xml:lang="en-GB"> + <mu abort="solid 1px green" xml:lang="en-GB"/> + <alpha xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </alpha> + </kappa> + </gamma> + </upsilon> + </lambda> + </beta> + </eta> + </delta> + </delta> + </any> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="nb"]//pi[@abort][@xml:lang="en-US"]//*[starts-with(@string,"att")][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::iota[@class][@xml:id="id1"][not(following-sibling::*)]//rho[not(preceding-sibling::*)][not(following-sibling::*)]//beta[@xml:lang="en-US"][not(following-sibling::*)]//*[@xml:id="id2"]//beta[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::gamma[starts-with(concat(@src,"-"),"_blank-")][preceding-sibling::*[position() = 1]][following-sibling::epsilon[@object][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]/kappa[starts-with(@content,"at")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[contains(@att,"lid 1px g")][preceding-sibling::*[position() = 1]]/delta[@xml:lang="en-US"][@xml:id="id4"][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//iota[@attribute="attribute"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::upsilon[starts-with(@false,"attribute-v")][@xml:id="id6"][following-sibling::kappa[contains(@delete,"od")][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="nb"> + <pi abort="attribute value" xml:lang="en-US"> + <any string="attribute"> + <delta xml:lang="en-GB"/> + <iota class="123456789" xml:id="id1"> + <rho> + <beta xml:lang="en-US"> + <any xml:id="id2"> + <beta xml:id="id3"/> + <gamma src="_blank"/> + <epsilon object="attribute" xml:lang="en-GB"> + <kappa content="attribute-value" xml:lang="nb"/> + <nu att="solid 1px green"> + <delta xml:lang="en-US" xml:id="id4"/> + <pi xml:lang="no-nb"> + <iota attribute="attribute" xml:id="id5"/> + <upsilon false="attribute-value" xml:id="id6"/> + <kappa delete="this.nodeValue" xml:id="id7"> + <green>This text must be green</green> + </kappa> + </pi> + </nu> + </epsilon> + </any> + </beta> + </rho> + </iota> + </any> + </pi> + </eta> + </tree> + </test> + <test> + <xpath>//phi/beta[contains(@and,"e")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@abort="attribute value"][@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]//omicron[@content][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[contains(concat(@title,"$"),"lue$")][@xml:lang="en-US"][not(following-sibling::*)]//omega[starts-with(@token,"123")][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[starts-with(concat(@and,"-"),"false-")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::nu[starts-with(@title,"attri")][@xml:lang="nb"][@xml:id="id5"]/kappa[starts-with(@token,"this-is-at")][@xml:lang="en"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::tau[@string]//psi[@desciption][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//psi[@content][not(following-sibling::*)]//zeta[@attr][not(preceding-sibling::*)]/mu[@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::psi[@string="true"][@xml:lang="no"][@xml:id="id9"]//gamma[@title="attribute"][@xml:id="id10"][following-sibling::delta[position() = 1]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <beta and="true" xml:lang="en"/> + <chi abort="attribute value" xml:lang="no-nb" xml:id="id1"> + <omicron content="100%" xml:lang="en" xml:id="id2"> + <zeta title="attribute value" xml:lang="en-US"> + <omega token="123456789" xml:id="id3"/> + <beta and="false" xml:lang="no" xml:id="id4"/> + <nu title="attribute" xml:lang="nb" xml:id="id5"> + <kappa token="this-is-att-value" xml:lang="en" xml:id="id6"/> + <tau string="attribute value"> + <psi desciption="123456789" xml:id="id7"/> + <sigma xml:id="id8"> + <psi content="attribute value"> + <zeta attr="solid 1px green"> + <mu xml:lang="nb"/> + <psi string="true" xml:lang="no" xml:id="id9"> + <gamma title="attribute" xml:id="id10"/> + <delta> + <green>This text must be green</green> + </delta> + </psi> + </zeta> + </psi> + </sigma> + </tau> + </nu> + </zeta> + </omicron> + </chi> + </phi> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]/tau[@or][@xml:id="id2"][not(following-sibling::*)]/xi[contains(concat(@or,"$"),"6789$")][not(preceding-sibling::*)]/lambda[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@content][not(following-sibling::*)]/delta[@insert][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[starts-with(concat(@class,"-"),"false-")][@xml:id="id4"][preceding-sibling::*[position() = 1]]//pi[@xml:lang="en"][@xml:id="id5"][following-sibling::theta[contains(@string,"te-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/delta[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)]//sigma[@xml:lang="no"][not(preceding-sibling::*)]/omega[@xml:lang="en"][@xml:id="id7"]/pi[contains(concat(@token,"$"),"e$")][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <tau or="content" xml:id="id2"> + <xi or="123456789"> + <lambda xml:lang="en-US" xml:id="id3"> + <rho content="false"> + <delta insert="attribute-value"/> + <psi class="false" xml:id="id4"> + <pi xml:lang="en" xml:id="id5"/> + <theta string="attribute-value" xml:lang="no-nb"> + <delta xml:lang="no" xml:id="id6"> + <sigma xml:lang="no"> + <omega xml:lang="en" xml:id="id7"> + <pi token="attribute-value" xml:lang="no" xml:id="id8"> + <green>This text must be green</green> + </pi> + </omega> + </sigma> + </delta> + </theta> + </psi> + </rho> + </lambda> + </xi> + </tau> + </psi> + </tree> + </test> + <test> + <xpath>//eta[starts-with(concat(@abort,"-"),"another attribute value-")][@xml:lang="nb"]//tau[@xml:id="id1"][not(preceding-sibling::*)]//beta[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::phi[@xml:id="id2"][following-sibling::omicron[contains(concat(@attribute,"$"),"e$")][@xml:id="id3"][not(child::node())][following-sibling::pi[@xml:lang="en"][preceding-sibling::*[position() = 3]][following-sibling::pi[@number][@xml:lang="nb"][preceding-sibling::*[position() = 4]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta abort="another attribute value" xml:lang="nb"> + <tau xml:id="id1"> + <beta xml:lang="en-US"/> + <phi xml:id="id2"/> + <omicron attribute="true" xml:id="id3"/> + <pi xml:lang="en"/> + <pi number="_blank" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </tau> + </eta> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(@delete,"solid 1px gre")][@xml:id="id1"]/beta/upsilon[not(child::node())][following-sibling::gamma[contains(concat(@false,"$"),"ute-value$")][@xml:lang="no"][not(following-sibling::*)]//mu[not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::omicron[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@object][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::chi[@class="this-is-att-value"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/pi[contains(concat(@token,"$"),"other attribute value$")][@xml:lang="en"][not(preceding-sibling::*)]//lambda[@xml:id="id2"][not(preceding-sibling::*)]//tau[@xml:id="id3"]/pi[starts-with(@data,"_blank")][not(child::node())][following-sibling::pi[starts-with(@name,"anot")][@xml:lang="no-nb"]//eta[@xml:lang="en-GB"][not(following-sibling::*)]//phi[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>1</nth> + </result> + <tree> + <upsilon delete="solid 1px green" xml:id="id1"> + <beta> + <upsilon/> + <gamma false="attribute-value" xml:lang="no"> + <mu/> + <omicron xml:lang="en-US"/> + <epsilon object="attribute-value" xml:lang="en"/> + <chi class="this-is-att-value"> + <pi token="another attribute value" xml:lang="en"> + <lambda xml:id="id2"> + <tau xml:id="id3"> + <pi data="_blank"/> + <pi name="another attribute value" xml:lang="no-nb"> + <eta xml:lang="en-GB"> + <phi xml:id="id4"> + <green>This text must be green</green> + </phi> + </eta> + </pi> + </tau> + </lambda> + </pi> + </chi> + </gamma> + </beta> + </upsilon> + </tree> + </test> + <test> + <xpath>//eta[@or][@xml:lang="en-US"]/iota[@token][following-sibling::tau[@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[contains(@token,"other ")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/kappa[@xml:lang="no-nb"]//xi[@xml:lang="en"][not(preceding-sibling::*)]/tau[@xml:lang="en-GB"][@xml:id="id1"][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[@token="100%"][following-sibling::theta[@xml:id="id2"][not(following-sibling::*)]/chi[@xml:id="id3"][not(child::node())][following-sibling::iota[contains(concat(@false,"$"),"odeValue$")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(preceding-sibling::lambda)]/delta[contains(concat(@abort,"$"),"other attribute value$")][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@attribute="another attribute value"][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/lambda[@attribute][@xml:lang="no"][not(following-sibling::*)]//*[@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::sigma[not(following-sibling::*)]/epsilon[not(preceding-sibling::*)]/theta[starts-with(@abort,"an")][@xml:id="id8"][not(following-sibling::*)]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <eta or="123456789" xml:lang="en-US"> + <iota token="_blank"/> + <tau xml:lang="nb"/> + <rho token="another attribute value" xml:lang="en-GB"> + <kappa xml:lang="no-nb"> + <xi xml:lang="en"> + <tau xml:lang="en-GB" xml:id="id1"/> + <omicron token="100%"/> + <theta xml:id="id2"> + <chi xml:id="id3"/> + <iota false="this.nodeValue" xml:lang="no" xml:id="id4"> + <mu/> + <lambda xml:id="id5"> + <delta abort="another attribute value"/> + <sigma attribute="another attribute value" xml:lang="en" xml:id="id6"> + <lambda attribute="content" xml:lang="no"> + <any xml:lang="en-US" xml:id="id7"/> + <sigma> + <epsilon> + <theta abort="another attribute value" xml:id="id8"> + <green>This text must be green</green> + </theta> + </epsilon> + </sigma> + </lambda> + </sigma> + </lambda> + </iota> + </theta> + </xi> + </kappa> + </rho> + </eta> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no-nb"]//xi[@xml:lang="en-US"][not(preceding-sibling::*)]/gamma[@attr][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:id="id1"]/psi[contains(@attribute,"this.n")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(@attribute,"attribu")][@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::beta[@xml:lang="en-US"][@xml:id="id3"][following-sibling::upsilon[@xml:id="id4"][following-sibling::gamma[starts-with(@title,"10")][not(child::node())][following-sibling::nu//beta[starts-with(@delete,"solid 1p")][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:id="id5"]/rho[not(child::node())][following-sibling::omega[@title][following-sibling::omicron[starts-with(concat(@src,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 2]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no-nb"> + <xi xml:lang="en-US"> + <gamma attr="this-is-att-value"/> + <psi xml:id="id1"> + <psi attribute="this.nodeValue" xml:lang="en-US"/> + <omega attribute="attribute" xml:lang="en-US" xml:id="id2"/> + <beta xml:lang="en-US" xml:id="id3"/> + <upsilon xml:id="id4"/> + <gamma title="100%"/> + <nu> + <beta delete="solid 1px green"/> + <gamma xml:id="id5"> + <rho/> + <omega title="_blank"/> + <omicron src="attribute" xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </gamma> + </nu> + </psi> + </xi> + </epsilon> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@title,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id1"]//theta[@xml:lang="en"][@xml:id="id2"][following-sibling::lambda[starts-with(concat(@token,"-"),"true-")][following-sibling::*[position()=2]][following-sibling::upsilon[@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::delta[@true][not(following-sibling::*)]/*[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[@xml:id="id3"][not(child::node())][following-sibling::delta[starts-with(@content,"anothe")][@xml:id="id4"][not(following-sibling::*)]//lambda[not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]]/rho[starts-with(@desciption,"this.nodeVa")][@xml:id="id6"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <delta title="attribute" xml:lang="nb" xml:id="id1"> + <theta xml:lang="en" xml:id="id2"/> + <lambda token="true"/> + <upsilon xml:lang="en"/> + <delta true="123456789"> + <any/> + <sigma xml:id="id3"/> + <delta content="another attribute value" xml:id="id4"> + <lambda/> + <pi xml:lang="no" xml:id="id5"> + <rho desciption="this.nodeValue" xml:id="id6"> + <green>This text must be green</green> + </rho> + </pi> + </delta> + </delta> + </delta> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no-nb"]//*[starts-with(concat(@insert,"-"),"_blank-")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::eta[@xml:id="id1"]/beta[starts-with(concat(@abort,"-"),"false-")][@xml:lang="nb"][@xml:id="id2"][following-sibling::nu[starts-with(concat(@object,"-"),"_blank-")][@xml:lang="no"][not(following-sibling::*)]/gamma[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="en"][following-sibling::psi[contains(concat(@title,"$")," green$")][@xml:id="id3"][following-sibling::*[position()=3]][following-sibling::kappa[@object][preceding-sibling::*[position() = 2]][following-sibling::gamma[@att="attribute"][@xml:id="id4"][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]//xi[starts-with(@class,"cont")][@xml:id="id6"][not(preceding-sibling::*)]//pi[@token][@xml:lang="en"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::epsilon[contains(concat(@attr,"$"),"0%$")][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]]/gamma[@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::chi[@token][@xml:id="id11"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::phi[@object="attribute value"][not(following-sibling::*)]/sigma[@xml:lang="en"][not(preceding-sibling::*)]]]]]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no-nb"> + <any insert="_blank" xml:lang="en"/> + <eta xml:id="id1"> + <beta abort="false" xml:lang="nb" xml:id="id2"/> + <nu object="_blank" xml:lang="no"> + <gamma att="attribute-value" xml:lang="en"/> + <psi title="solid 1px green" xml:id="id3"/> + <kappa object="solid 1px green"/> + <gamma att="attribute" xml:id="id4"/> + <xi xml:lang="en-GB" xml:id="id5"> + <xi class="content" xml:id="id6"> + <pi token="another attribute value" xml:lang="en" xml:id="id7"/> + <epsilon attr="100%" xml:lang="en-GB" xml:id="id8"> + <gamma xml:lang="en-GB" xml:id="id9"> + <omicron xml:lang="no-nb"/> + <gamma/> + <rho xml:id="id10"/> + <chi token="_blank" xml:id="id11"/> + <phi object="attribute value"> + <sigma xml:lang="en"> + <green>This text must be green</green> + </sigma> + </phi> + </gamma> + </epsilon> + </xi> + </xi> + </nu> + </eta> + </iota> + </tree> + </test> + <test> + <xpath>//chi[contains(concat(@insert,"$"),"ank$")][@xml:lang="no"]//omicron[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)]//mu[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=9]][following-sibling::*[@xml:id="id3"][following-sibling::rho[@xml:lang="no-nb"][@xml:id="id4"][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][following-sibling::beta[starts-with(@title,"fa")][following-sibling::*[preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::phi[@name="true"][@xml:lang="no-nb"][not(child::node())][following-sibling::zeta[starts-with(concat(@number,"-"),"this-")][@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 7]][following-sibling::phi[@xml:lang="en-GB"][@xml:id="id6"][not(child::node())][following-sibling::upsilon//mu[following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:id="id7"]//kappa[not(following-sibling::*)]/delta[@xml:id="id8"][following-sibling::gamma[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:id="id10"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <chi insert="_blank" xml:lang="no"> + <omicron xml:lang="nb" xml:id="id1"> + <mu xml:lang="en" xml:id="id2"/> + <any xml:id="id3"/> + <rho xml:lang="no-nb" xml:id="id4"/> + <tau xml:lang="no-nb"/> + <beta title="false"/> + <any/> + <phi name="true" xml:lang="no-nb"/> + <zeta number="this-is-att-value" xml:lang="en" xml:id="id5"/> + <phi xml:lang="en-GB" xml:id="id6"/> + <upsilon> + <mu/> + <rho xml:id="id7"> + <kappa> + <delta xml:id="id8"/> + <gamma xml:id="id9"/> + <kappa xml:id="id10"> + <green>This text must be green</green> + </kappa> + </kappa> + </rho> + </upsilon> + </omicron> + </chi> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="no-nb"][@xml:id="id1"]/iota[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::mu[preceding-sibling::*[position() = 1]][following-sibling::pi[contains(concat(@desciption,"$"),"e$")][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::upsilon[starts-with(concat(@att,"-"),"attribute value-")][@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]//delta[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::eta[following-sibling::nu[starts-with(concat(@insert,"-"),"this-")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="no-nb" xml:id="id1"> + <iota xml:lang="en-GB" xml:id="id2"/> + <mu/> + <pi desciption="true" xml:lang="en" xml:id="id3"/> + <upsilon att="attribute value" xml:lang="no-nb" xml:id="id4"> + <delta xml:lang="en"/> + <eta/> + <nu insert="this-is-att-value"> + <phi xml:lang="nb"> + <green>This text must be green</green> + </phi> + </nu> + </upsilon> + </theta> + </tree> + </test> + <test> + <xpath>//alpha[@content="content"][@xml:id="id1"]/delta[@token="attribute"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/sigma[@class][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[starts-with(@title,"solid 1px gre")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[@xml:lang="en"][@xml:id="id4"]//alpha[@abort="another attribute value"][@xml:id="id5"]/eta[starts-with(@abort,"another attribute ")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::*[position()=9]][following-sibling::rho[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=8]][following-sibling::*[contains(concat(@token,"$"),"ank$")][@xml:lang="en"][@xml:id="id7"][not(child::node())][following-sibling::chi[@xml:id="id8"][preceding-sibling::*[position() = 3]][following-sibling::epsilon[@xml:id="id9"][not(child::node())][following-sibling::pi[@xml:id="id10"][preceding-sibling::*[position() = 5]][following-sibling::tau[@name][@xml:lang="en"][preceding-sibling::*[position() = 6]][not(child::node())][following-sibling::upsilon[contains(concat(@object,"$"),"e$")][@xml:lang="no"][@xml:id="id11"][following-sibling::*[position()=2]][following-sibling::epsilon[preceding-sibling::*[position() = 8]][following-sibling::*[position()=1]][following-sibling::lambda[starts-with(@data,"attribute-")][preceding-sibling::*[position() = 9]]//eta[@xml:lang="en-US"][not(preceding-sibling::*)]/psi[@xml:lang="en"][@xml:id="id12"][not(preceding-sibling::*)][not(following-sibling::*)]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <alpha content="content" xml:id="id1"> + <delta token="attribute" xml:id="id2"/> + <chi xml:lang="en-GB"> + <sigma class="attribute-value" xml:lang="en-GB"/> + <omicron title="solid 1px green" xml:id="id3"> + <nu/> + <kappa xml:lang="en" xml:id="id4"> + <alpha abort="another attribute value" xml:id="id5"> + <eta abort="another attribute value" xml:lang="en-GB" xml:id="id6"/> + <rho xml:lang="en-GB"/> + <any token="_blank" xml:lang="en" xml:id="id7"/> + <chi xml:id="id8"/> + <epsilon xml:id="id9"/> + <pi xml:id="id10"/> + <tau name="false" xml:lang="en"/> + <upsilon object="false" xml:lang="no" xml:id="id11"/> + <epsilon/> + <lambda data="attribute-value"> + <eta xml:lang="en-US"> + <psi xml:lang="en" xml:id="id12"> + <green>This text must be green</green> + </psi> + </eta> + </lambda> + </alpha> + </kappa> + </omicron> + </chi> + </alpha> + </tree> + </test> + <test> + <xpath>//xi[contains(concat(@data,"$"),"k$")][@xml:lang="en"]/omicron[contains(concat(@or,"$"),"lse$")][@xml:lang="en-US"][not(following-sibling::*)]//phi[contains(concat(@object,"$"),"00%$")][@xml:lang="en-US"][@xml:id="id1"][not(child::node())][following-sibling::psi[@insert="true"][not(child::node())][following-sibling::epsilon[starts-with(concat(@false,"-"),"attribute value-")][@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]/sigma[@xml:id="id3"][not(following-sibling::*)]/delta[not(preceding-sibling::*)][not(following-sibling::*)]/omega[starts-with(@false,"tr")][@xml:lang="en-US"][not(preceding-sibling::*)]/delta[starts-with(@and,"123456789")][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <xi data="_blank" xml:lang="en"> + <omicron or="false" xml:lang="en-US"> + <phi object="100%" xml:lang="en-US" xml:id="id1"/> + <psi insert="true"/> + <epsilon false="attribute value" xml:lang="no" xml:id="id2"> + <sigma xml:id="id3"> + <delta> + <omega false="true" xml:lang="en-US"> + <delta and="123456789"> + <green>This text must be green</green> + </delta> + </omega> + </delta> + </sigma> + </epsilon> + </omicron> + </xi> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="no"][@xml:id="id1"]//*[@attribute][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::zeta[@xml:id="id2"][preceding-sibling::*[position() = 1]]//lambda[@content="attribute"][not(child::node())][following-sibling::mu[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa[@class="attribute-value"][not(following-sibling::*)][not(preceding-sibling::kappa)]//lambda[starts-with(@token,"a")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::zeta[@or][@xml:lang="en-US"][not(following-sibling::*)]/alpha[@xml:id="id5"][not(child::node())][following-sibling::pi[@xml:lang="en-GB"]//alpha[starts-with(@false,"at")][@xml:id="id6"]//eta[starts-with(@content,"so")][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::eta/sigma[@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::alpha[starts-with(@false,"attribute-")][@xml:lang="no-nb"]//lambda[@false][not(following-sibling::*)]/pi[@false="_blank"][not(preceding-sibling::*)]//upsilon[not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="no" xml:id="id1"> + <any attribute="this.nodeValue" xml:lang="en-US"/> + <zeta xml:id="id2"> + <lambda content="attribute"/> + <mu xml:lang="en-GB" xml:id="id3"> + <kappa class="attribute-value"> + <lambda token="attribute-value" xml:lang="en-GB" xml:id="id4"/> + <zeta or="attribute" xml:lang="en-US"> + <alpha xml:id="id5"/> + <pi xml:lang="en-GB"> + <alpha false="attribute" xml:id="id6"> + <eta content="solid 1px green" xml:id="id7"/> + <eta> + <sigma xml:lang="en-GB" xml:id="id8"/> + <alpha false="attribute-value" xml:lang="no-nb"> + <lambda false="content"> + <pi false="_blank"> + <upsilon> + <green>This text must be green</green> + </upsilon> + </pi> + </lambda> + </alpha> + </eta> + </alpha> + </pi> + </zeta> + </kappa> + </mu> + </zeta> + </omega> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-GB"][@xml:id="id1"]//gamma[@xml:lang="en-GB"][not(child::node())][following-sibling::*//gamma[@xml:id="id2"][following-sibling::delta[@object][not(preceding-sibling::delta)]//omega[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(preceding-sibling::epsilon)]//rho[@xml:lang="no-nb"]/kappa[@xml:lang="en-GB"]/kappa[not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@class="this.nodeValue"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/tau[@xml:lang="no-nb"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="en-GB"][not(following-sibling::*)]//nu[@xml:lang="nb"][not(preceding-sibling::*)]/phi[@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@true][@xml:id="id9"]/alpha[@xml:id="id10"][not(child::node())][following-sibling::mu[@src="attribute value"][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::mu)]//nu[starts-with(concat(@object,"-"),"true-")][not(preceding-sibling::*)][not(child::node())][following-sibling::*[starts-with(concat(@true,"-"),"true-")][@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[starts-with(@token,"_bla")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-GB" xml:id="id1"> + <gamma xml:lang="en-GB"/> + <any> + <gamma xml:id="id2"/> + <delta object="another attribute value"> + <omega xml:lang="no-nb" xml:id="id3"/> + <epsilon xml:id="id4"> + <rho xml:lang="no-nb"> + <kappa xml:lang="en-GB"> + <kappa> + <alpha xml:lang="no" xml:id="id5"/> + <chi class="this.nodeValue" xml:id="id6"> + <tau xml:lang="no-nb" xml:id="id7"/> + <iota xml:lang="en-GB"> + <nu xml:lang="nb"> + <phi xml:lang="no-nb" xml:id="id8"> + <psi true="123456789" xml:id="id9"> + <alpha xml:id="id10"/> + <mu src="attribute value" xml:lang="no-nb"> + <nu object="true"/> + <any true="true" xml:lang="nb" xml:id="id11"> + <lambda token="_blank"> + <green>This text must be green</green> + </lambda> + </any> + </mu> + </psi> + </phi> + </nu> + </iota> + </chi> + </kappa> + </kappa> + </rho> + </epsilon> + </delta> + </any> + </kappa> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="no-nb"][@xml:id="id1"]/delta[@false][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]//nu[contains(@number,"0")][@xml:id="id3"][not(preceding-sibling::*)][not(preceding-sibling::nu)]/upsilon[starts-with(@src,"ano")][@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]//xi[contains(concat(@attrib,"$"),"se$")][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="no"][not(following-sibling::*)]//rho[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::rho)]//phi[@src][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[starts-with(concat(@content,"-"),"attribute value-")][@xml:lang="nb"][not(following-sibling::*)]//psi[@attribute][@xml:lang="en"][not(preceding-sibling::*)]/upsilon[contains(@insert,"nother attri")]//delta[@number]/psi[@true="this-is-att-value"][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(preceding-sibling::psi)][following-sibling::tau[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::alpha[@content="false"][not(child::node())][following-sibling::beta[contains(concat(@content,"$"),"false$")][@xml:lang="nb"]//delta[@xml:lang="no-nb"][@xml:id="id10"]//iota[@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)]//gamma[@src][@xml:id="id12"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="no-nb" xml:id="id1"> + <delta false="attribute-value" xml:lang="en-GB" xml:id="id2"> + <nu number="100%" xml:id="id3"> + <upsilon src="another attribute value" xml:lang="nb" xml:id="id4"/> + <theta xml:lang="en" xml:id="id5"> + <xi attrib="false" xml:lang="en" xml:id="id6"/> + <nu xml:lang="no"> + <rho xml:id="id7"> + <phi src="this.nodeValue" xml:id="id8"> + <kappa content="attribute value" xml:lang="nb"> + <psi attribute="content" xml:lang="en"> + <upsilon insert="another attribute value"> + <delta number="attribute value"> + <psi true="this-is-att-value" xml:lang="en"/> + <tau xml:lang="nb" xml:id="id9"/> + <alpha content="false"/> + <beta content="false" xml:lang="nb"> + <delta xml:lang="no-nb" xml:id="id10"> + <iota xml:lang="no" xml:id="id11"> + <gamma src="100%" xml:id="id12"> + <green>This text must be green</green> + </gamma> + </iota> + </delta> + </beta> + </delta> + </upsilon> + </psi> + </kappa> + </phi> + </rho> + </nu> + </theta> + </nu> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//mu[@xml:lang="no-nb"][@xml:id="id1"]//tau[@xml:id="id2"][not(following-sibling::*)]//omicron[@xml:lang="en-US"][@xml:id="id3"][following-sibling::delta[@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[contains(concat(@att,"$")," value$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[contains(@abort,"1px green")][not(preceding-sibling::*)]/zeta[@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::upsilon[@attr][@xml:lang="no"]/epsilon[contains(concat(@object,"$"),"ttribute value$")][@xml:lang="nb"][@xml:id="id6"]//omega[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::omega)][not(child::node())][following-sibling::beta[@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::omicron[@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/rho[@xml:id="id10"]//psi[@attr][@xml:lang="en-GB"][@xml:id="id11"][not(following-sibling::psi)][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id12"][preceding-sibling::*[position() = 1]]//pi[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:lang="en-GB"][not(following-sibling::*)]/xi[@xml:lang="en-US"][not(preceding-sibling::*)]/kappa[@xml:lang="en-US"][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id13"]/zeta[contains(concat(@number,"$"),"ribute-value$")][not(preceding-sibling::*)]//omicron[@xml:lang="en"][@xml:id="id14"][not(preceding-sibling::*)][following-sibling::iota[contains(concat(@attrib,"$"),"-value$")][@xml:lang="no"][@xml:id="id15"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:lang="no"][@xml:id="id16"]][position() = 1]]]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:lang="no-nb" xml:id="id1"> + <tau xml:id="id2"> + <omicron xml:lang="en-US" xml:id="id3"/> + <delta xml:id="id4"/> + <gamma att="attribute value" xml:lang="nb"> + <theta abort="solid 1px green"> + <zeta xml:lang="no" xml:id="id5"/> + <upsilon attr="123456789" xml:lang="no"> + <epsilon object="another attribute value" xml:lang="nb" xml:id="id6"> + <omega xml:id="id7"/> + <beta xml:id="id8"/> + <omicron xml:id="id9"> + <rho xml:id="id10"> + <psi attr="attribute value" xml:lang="en-GB" xml:id="id11"/> + <omicron xml:lang="en-US" xml:id="id12"> + <pi/> + <gamma xml:lang="en-GB"> + <xi xml:lang="en-US"> + <kappa xml:lang="en-US"/> + <pi xml:lang="no-nb" xml:id="id13"> + <zeta number="attribute-value"> + <omicron xml:lang="en" xml:id="id14"/> + <iota attrib="attribute-value" xml:lang="no" xml:id="id15"> + <omicron xml:lang="no" xml:id="id16"> + <green>This text must be green</green> + </omicron> + </iota> + </zeta> + </pi> + </xi> + </gamma> + </omicron> + </rho> + </omicron> + </epsilon> + </upsilon> + </theta> + </gamma> + </tau> + </mu> + </tree> + </test> + <test> + <xpath>//phi//zeta[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//alpha[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@xml:lang="en-US"][@xml:id="id1"]/epsilon[@token="this.nodeValue"][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::kappa[@data][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//mu[@string="false"][@xml:lang="nb"][not(preceding-sibling::*)]//epsilon[not(preceding-sibling::*)][not(following-sibling::*)]//pi[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::iota[starts-with(@content,"123")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/sigma[not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-US"][not(following-sibling::*)]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <zeta/> + <kappa xml:lang="no-nb"> + <alpha xml:lang="en-US"> + <epsilon xml:lang="en-US" xml:id="id1"> + <epsilon token="this.nodeValue" xml:lang="no-nb" xml:id="id2"/> + <pi xml:lang="en-US"/> + <kappa data="true" xml:lang="no"> + <mu string="false" xml:lang="nb"> + <epsilon> + <pi xml:lang="no" xml:id="id3"/> + <iota content="123456789" xml:lang="no" xml:id="id4"/> + <omicron xml:lang="no" xml:id="id5"> + <sigma> + <delta xml:lang="en-US"> + <green>This text must be green</green> + </delta> + </sigma> + </omicron> + </epsilon> + </mu> + </kappa> + </epsilon> + </alpha> + </kappa> + </phi> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="no-nb"][@xml:id="id1"]/omega[contains(@content,"%")][@xml:lang="en-US"]//psi[@insert][not(preceding-sibling::*)][not(following-sibling::*)]/*[not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@content][@xml:lang="en"]//sigma[not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@xml:lang="no-nb"][following-sibling::xi[starts-with(@false,"12")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="no-nb" xml:id="id1"> + <omega content="100%" xml:lang="en-US"> + <psi insert="this.nodeValue"> + <any> + <zeta content="this.nodeValue" xml:lang="en"> + <sigma> + <omicron xml:lang="no-nb"/> + <xi false="123456789" xml:lang="nb"> + <green>This text must be green</green> + </xi> + </sigma> + </zeta> + </any> + </psi> + </omega> + </alpha> + </tree> + </test> + <test> + <xpath>//psi[contains(@src,"n")]//gamma[@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]//beta[@xml:id="id2"][not(preceding-sibling::*)]//sigma[contains(concat(@false,"$"),"rue$")][@xml:lang="no-nb"][not(preceding-sibling::*)]/xi[contains(concat(@number,"$")," 1px green$")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]/pi[contains(concat(@src,"$"),"ontent$")][not(child::node())][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::rho[starts-with(@attr,"tr")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/zeta[contains(@attribute,"e")][@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[starts-with(concat(@desciption,"-"),"true-")][@xml:lang="en"][not(following-sibling::*)]//xi[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@insert="this.nodeValue"][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//omega[starts-with(concat(@delete,"-"),"solid 1px green-")]/psi[contains(@or,"te value")][@xml:lang="en-GB"][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::phi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(following-sibling::phi)][not(child::node())][following-sibling::theta[@false="solid 1px green"][following-sibling::eta[preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="en-GB"][preceding-sibling::*[position() = 4]]/alpha[@xml:id="id9"]][position() = 1]]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <psi src="solid 1px green"> + <gamma xml:lang="en-US" xml:id="id1"> + <beta xml:id="id2"> + <sigma false="true" xml:lang="no-nb"> + <xi number="solid 1px green" xml:lang="nb" xml:id="id3"/> + <zeta xml:lang="en-US" xml:id="id4"> + <pi src="content"/> + <mu xml:lang="no"/> + <rho attr="true" xml:lang="no-nb"> + <zeta attribute="true" xml:lang="en-US" xml:id="id5"/> + <nu> + <phi desciption="true" xml:lang="en"> + <xi xml:lang="en-US" xml:id="id6"/> + <delta insert="this.nodeValue" xml:lang="no-nb"> + <omega delete="solid 1px green"> + <psi or="attribute value" xml:lang="en-GB"/> + <zeta xml:lang="en-GB" xml:id="id7"> + <phi xml:id="id8"/> + <phi xml:lang="en-US"/> + <theta false="solid 1px green"/> + <eta/> + <alpha xml:lang="en-GB"> + <alpha xml:id="id9"> + <green>This text must be green</green> + </alpha> + </alpha> + </zeta> + </omega> + </delta> + </phi> + </nu> + </rho> + </zeta> + </sigma> + </beta> + </gamma> + </psi> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@object,"$"),"9$")][@xml:id="id1"]/xi[following-sibling::*[position()=1]][following-sibling::omicron[preceding-sibling::*[position() = 1]]//lambda[not(preceding-sibling::*)][not(child::node())][following-sibling::beta[starts-with(concat(@attribute,"-"),"_blank-")][following-sibling::chi[@xml:id="id2"][following-sibling::sigma[@and][@xml:lang="en"][@xml:id="id3"]/eta[contains(@false,"tr")][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]/iota[starts-with(concat(@abort,"-"),"solid 1px green-")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@content="content"][not(preceding-sibling::*)]//mu[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)]//mu[@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::mu[contains(@insert,"another")]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <phi object="123456789" xml:id="id1"> + <xi/> + <omicron> + <lambda/> + <beta attribute="_blank"/> + <chi xml:id="id2"/> + <sigma and="_blank" xml:lang="en" xml:id="id3"> + <eta false="attribute-value" xml:lang="nb" xml:id="id4"> + <iota abort="solid 1px green" xml:id="id5"> + <delta content="content"> + <mu xml:id="id6"/> + <lambda xml:lang="nb" xml:id="id7"> + <mu xml:lang="no-nb"/> + <mu insert="another attribute value"> + <green>This text must be green</green> + </mu> + </lambda> + </delta> + </iota> + </eta> + </sigma> + </omicron> + </phi> + </tree> + </test> + <test> + <xpath>//chi[starts-with(@true,"this.nod")]//sigma[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@insert][@xml:lang="no-nb"][not(child::node())][following-sibling::phi[@title][@xml:lang="en-GB"][following-sibling::pi[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::lambda[starts-with(@data,"_")][@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]//iota[@xml:lang="en"][@xml:id="id3"]//lambda[contains(concat(@att,"$"),"100%$")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <chi true="this.nodeValue"> + <sigma xml:id="id1"/> + <zeta xml:lang="no"> + <mu insert="attribute value" xml:lang="no-nb"/> + <phi title="true" xml:lang="en-GB"/> + <pi/> + <lambda data="_blank" xml:lang="en-GB"/> + <rho xml:lang="en" xml:id="id2"> + <iota xml:lang="en" xml:id="id3"> + <lambda att="100%" xml:lang="no"> + <green>This text must be green</green> + </lambda> + </iota> + </rho> + </zeta> + </chi> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="no"]/kappa[starts-with(concat(@title,"-"),"100%-")][@xml:lang="en"][not(child::node())][following-sibling::omicron[starts-with(@attribute,"solid ")][@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]//alpha[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@attr="false"][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//upsilon[not(preceding-sibling::*)][following-sibling::gamma[contains(@attribute,"ank")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="no"> + <kappa title="100%" xml:lang="en"/> + <omicron attribute="solid 1px green" xml:lang="no-nb" xml:id="id1"> + <alpha xml:lang="en"/> + <gamma attr="false" xml:lang="no"> + <upsilon/> + <gamma attribute="_blank" xml:lang="en-GB"> + <green>This text must be green</green> + </gamma> + </gamma> + </omicron> + </any> + </tree> + </test> + <test> + <xpath>//lambda[contains(@att,"e")][@xml:lang="en-GB"]//kappa[@object="solid 1px green"][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::lambda[contains(@string,"her attri")][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::rho[@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[starts-with(concat(@true,"-"),"123456789-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/alpha//zeta[following-sibling::*[position()=1]][following-sibling::*[@data][preceding-sibling::*[position() = 1]]//xi[contains(concat(@abort,"$"),"green$")][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[starts-with(concat(@title,"-"),"123456789-")][@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/psi[contains(@delete,"e")][@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)]/epsilon[@string][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@xml:id="id7"][not(following-sibling::*)]//delta[contains(concat(@abort,"$"),"nother attribute value$")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@xml:id="id8"][not(following-sibling::*)]/lambda[@xml:lang="nb"][@xml:id="id9"][following-sibling::gamma[@desciption][@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]]/rho[contains(@and,"100")]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <lambda att="true" xml:lang="en-GB"> + <kappa object="solid 1px green" xml:lang="nb"/> + <lambda string="another attribute value" xml:id="id1"/> + <rho xml:id="id2"/> + <rho true="123456789"> + <alpha> + <zeta/> + <any data="_blank"> + <xi abort="solid 1px green" xml:id="id3"/> + <omicron title="123456789" xml:lang="en" xml:id="id4"/> + <upsilon xml:lang="en"> + <psi delete="attribute" xml:lang="no-nb" xml:id="id5"> + <epsilon string="100%" xml:lang="en-GB" xml:id="id6"> + <any xml:id="id7"> + <delta abort="another attribute value" xml:lang="en-US"> + <epsilon xml:id="id8"> + <lambda xml:lang="nb" xml:id="id9"/> + <gamma desciption="another attribute value" xml:lang="nb" xml:id="id10"> + <rho and="100%"> + <green>This text must be green</green> + </rho> + </gamma> + </epsilon> + </delta> + </any> + </epsilon> + </psi> + </upsilon> + </any> + </alpha> + </rho> + </lambda> + </tree> + </test> + <test> + <xpath>//eta[starts-with(@src,"solid ")][@xml:lang="en-US"]//chi[@xml:id="id1"]//rho[@xml:lang="en-US"][following-sibling::delta[starts-with(@string,"attribut")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[following-sibling::phi//omicron[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::gamma[not(child::node())][following-sibling::omega[contains(concat(@attr,"$"),"e$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega[@class][not(following-sibling::*)]/eta//iota[@xml:lang="no-nb"][not(child::node())][following-sibling::omega[contains(concat(@delete,"$"),"56789$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:lang="en-US"][not(preceding-sibling::*)]//delta[@src][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@delete][following-sibling::mu[@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@attr="123456789"][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]]//delta[contains(concat(@and,"$"),"value$")][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@number][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@string][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <eta src="solid 1px green" xml:lang="en-US"> + <chi xml:id="id1"> + <rho xml:lang="en-US"/> + <delta string="attribute value" xml:lang="en-US"/> + <nu xml:lang="nb"/> + <sigma/> + <phi> + <omicron xml:lang="en-GB"/> + <gamma/> + <omega attr="true" xml:lang="nb"/> + <omega class="attribute value"> + <eta> + <iota xml:lang="no-nb"/> + <omega delete="123456789"> + <mu xml:lang="en-US"> + <delta src="content" xml:lang="nb"> + <any delete="solid 1px green"/> + <mu xml:id="id2"/> + <eta attr="123456789" xml:lang="en-GB"> + <delta and="another attribute value"/> + <nu number="content" xml:id="id3"/> + <pi string="true"> + <green>This text must be green</green> + </pi> + </eta> + </delta> + </mu> + </omega> + </eta> + </omega> + </phi> + </chi> + </eta> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="en-US"]/kappa[not(following-sibling::*)]//eta[contains(@abort,"789")][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(concat(@or,"$"),"te$")]/phi[not(preceding-sibling::*)]//*[@or="solid 1px green"][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:id="id2"]//omega[starts-with(concat(@delete,"-"),"attribute-")][@xml:lang="en-GB"][following-sibling::mu[@xml:lang="no"][not(following-sibling::*)]/omega[contains(concat(@title,"$"),"ribute value$")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="no"][not(child::node())][following-sibling::nu[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:id="id5"][not(following-sibling::*)]/pi[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[not(preceding-sibling::xi)]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="en-US"> + <kappa> + <eta abort="123456789"> + <psi or="attribute"> + <phi> + <any or="solid 1px green" xml:lang="en-GB" xml:id="id1"> + <gamma xml:id="id2"> + <omega delete="attribute-value" xml:lang="en-GB"/> + <mu xml:lang="no"> + <omega title="another attribute value" xml:lang="nb" xml:id="id3"/> + <tau xml:lang="no"/> + <nu xml:id="id4"/> + <alpha xml:id="id5"> + <pi xml:lang="en-US"> + <xi> + <green>This text must be green</green> + </xi> + </pi> + </alpha> + </mu> + </gamma> + </any> + </phi> + </psi> + </eta> + </kappa> + </lambda> + </tree> + </test> + <test> + <xpath>//omicron[@xml:lang="no"][@xml:id="id1"]//omicron[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::omicron or following-sibling::omicron)]//zeta[starts-with(concat(@src,"-"),"false-")][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[starts-with(concat(@abort,"-"),"123456789-")][not(following-sibling::*)]/iota[following-sibling::kappa[contains(concat(@or,"$"),"ttribute-value$")][@xml:id="id4"][preceding-sibling::*[position() = 1]]/gamma[@true][not(following-sibling::*)]//sigma[@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::rho[@xml:lang="en-US"]//nu[@xml:lang="en"][not(following-sibling::*)]//epsilon[@name][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[starts-with(concat(@data,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)]//xi[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[contains(@number,"00%")][@xml:lang="en-GB"][following-sibling::omicron[contains(@true,"d 1px ")][@xml:id="id8"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:lang="no" xml:id="id1"> + <omicron xml:lang="en" xml:id="id2"> + <zeta src="false" xml:id="id3"/> + <eta abort="123456789"> + <iota/> + <kappa or="attribute-value" xml:id="id4"> + <gamma true="true"> + <sigma xml:lang="en-US" xml:id="id5"/> + <rho xml:lang="en-US"> + <nu xml:lang="en"> + <epsilon name="123456789"> + <upsilon data="attribute" xml:lang="en-GB" xml:id="id6"> + <xi xml:lang="nb"> + <omega xml:id="id7"/> + <chi number="100%" xml:lang="en-GB"/> + <omicron true="solid 1px green" xml:id="id8"> + <green>This text must be green</green> + </omicron> + </xi> + </upsilon> + </epsilon> + </nu> + </rho> + </gamma> + </kappa> + </eta> + </omicron> + </omicron> + </tree> + </test> + <test> + <xpath>//theta[@attr][@xml:lang="en-US"][@xml:id="id1"]//epsilon[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::nu[contains(@attr,"-")][preceding-sibling::*[position() = 2]]/epsilon[not(preceding-sibling::*)]//nu[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@abort][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@and][@xml:lang="no"]//alpha[starts-with(@desciption,"att")][@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <theta attr="attribute" xml:lang="en-US" xml:id="id1"> + <epsilon xml:lang="en" xml:id="id2"/> + <upsilon xml:lang="no"/> + <nu attr="attribute-value"> + <epsilon> + <nu xml:lang="no-nb" xml:id="id3"/> + <alpha abort="attribute" xml:lang="no"/> + <alpha and="100%" xml:lang="no"> + <alpha desciption="attribute" xml:lang="no-nb" xml:id="id4"> + <green>This text must be green</green> + </alpha> + </alpha> + </epsilon> + </nu> + </theta> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@or,"$"),"0%$")][@xml:lang="en-GB"][@xml:id="id1"]/upsilon[@data][not(preceding-sibling::*)][following-sibling::eta[starts-with(@attribute,"th")]//xi[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::rho[@and][@xml:id="id4"][following-sibling::delta[starts-with(concat(@abort,"-"),"100%-")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/eta[@xml:lang="en"][following-sibling::iota[following-sibling::nu[preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[contains(concat(@string,"$"),"0%$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@string][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[starts-with(concat(@string,"-"),"another attribute value-")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::rho[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]/chi[not(preceding-sibling::*)][not(child::node())][following-sibling::rho[starts-with(concat(@content,"-"),"100%-")][@xml:lang="no"]//mu[@xml:lang="en-GB"][not(following-sibling::*)]/pi[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[starts-with(@false,"t")][@xml:lang="nb"][not(following-sibling::*)]//rho[@xml:lang="en-US"][not(child::node())][following-sibling::theta[not(following-sibling::*)]/beta[@desciption][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <iota or="100%" xml:lang="en-GB" xml:id="id1"> + <upsilon data="100%"/> + <eta attribute="this.nodeValue"> + <xi xml:lang="nb" xml:id="id2"/> + <upsilon xml:lang="no-nb" xml:id="id3"/> + <rho and="false" xml:id="id4"/> + <delta abort="100%" xml:lang="no-nb" xml:id="id5"> + <eta xml:lang="en"/> + <iota/> + <nu> + <lambda string="100%"/> + <chi> + <chi string="100%" xml:id="id6"> + <rho string="another attribute value" xml:lang="en"/> + <rho xml:lang="en-GB" xml:id="id7"> + <chi/> + <rho content="100%" xml:lang="no"> + <mu xml:lang="en-GB"> + <pi xml:lang="nb"/> + <tau false="true" xml:lang="nb"> + <rho xml:lang="en-US"/> + <theta> + <beta desciption="attribute-value"> + <green>This text must be green</green> + </beta> + </theta> + </tau> + </mu> + </rho> + </rho> + </chi> + </chi> + </nu> + </delta> + </eta> + </iota> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no"][@xml:id="id1"]//tau[contains(@delete,"5678")][@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]//gamma[@xml:lang="en"][not(following-sibling::*)]//nu[@xml:id="id3"][following-sibling::*[position()=2]][following-sibling::sigma[@xml:lang="en-US"][@xml:id="id4"][following-sibling::alpha[@src="content"][@xml:id="id5"]/lambda[not(child::node())][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::nu[starts-with(concat(@title,"-"),"another attribute value-")][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[starts-with(@delete,"t")][not(child::node())][following-sibling::lambda[@xml:id="id7"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::xi[starts-with(@src,"_blank")][@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//upsilon[contains(concat(@delete,"$"),"ontent$")][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[contains(@content,"9")][@xml:id="id10"][preceding-sibling::*[position() = 2]]//xi[contains(@abort,"ue")][@xml:lang="no"][@xml:id="id11"][following-sibling::*[position()=4]][not(child::node())][following-sibling::psi[starts-with(concat(@content,"-"),"solid 1px green-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::pi[contains(@delete,"green")][@xml:id="id12"][following-sibling::*[position()=2]][following-sibling::phi[@xml:id="id13"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::pi[contains(@data,"_")]]]][position() = 1]]][position() = 1]]][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no" xml:id="id1"> + <tau delete="123456789" xml:lang="no-nb" xml:id="id2"> + <gamma xml:lang="en"> + <nu xml:id="id3"/> + <sigma xml:lang="en-US" xml:id="id4"/> + <alpha src="content" xml:id="id5"> + <lambda/> + <mu xml:lang="no"/> + <nu title="another attribute value" xml:id="id6"/> + <any delete="this.nodeValue"/> + <lambda xml:id="id7"/> + <xi src="_blank" xml:lang="en" xml:id="id8"> + <upsilon delete="content" xml:lang="nb" xml:id="id9"/> + <nu xml:lang="no-nb"/> + <upsilon content="123456789" xml:id="id10"> + <xi abort="another attribute value" xml:lang="no" xml:id="id11"/> + <psi content="solid 1px green" xml:lang="no-nb"/> + <pi delete="solid 1px green" xml:id="id12"/> + <phi xml:id="id13"/> + <pi data="_blank"> + <green>This text must be green</green> + </pi> + </upsilon> + </xi> + </alpha> + </gamma> + </tau> + </lambda> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no-nb"]/eta[@data][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)]//lambda[@xml:lang="nb"][not(following-sibling::*)]//iota[not(following-sibling::*)]//kappa[@or][@xml:id="id2"][not(child::node())][following-sibling::rho[@name="another attribute value"][@xml:lang="no"]/delta[starts-with(concat(@class,"-"),"false-")][@xml:lang="en"][not(preceding-sibling::*)]/eta[@src="another attribute value"][@xml:id="id3"][following-sibling::nu[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[starts-with(@content,"at")][@xml:lang="en-GB"][@xml:id="id4"]//lambda[starts-with(concat(@att,"-"),"this.nodeValue-")][@xml:lang="nb"][not(preceding-sibling::*)]//beta[@insert="attribute value"][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@xml:lang="no"][following-sibling::theta[starts-with(@or,"attribu")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@class][@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[starts-with(concat(@att,"-"),"123456789-")][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@xml:lang="no"][following-sibling::upsilon[@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 2]][following-sibling::epsilon[@or][not(child::node())][following-sibling::omega[@xml:id="id8"][preceding-sibling::*[position() = 4]][not(preceding-sibling::omega)]/iota[@xml:lang="nb"][@xml:id="id9"][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no-nb"> + <eta data="this-is-att-value" xml:lang="nb" xml:id="id1"> + <lambda xml:lang="nb"> + <iota> + <kappa or="attribute value" xml:id="id2"/> + <rho name="another attribute value" xml:lang="no"> + <delta class="false" xml:lang="en"> + <eta src="another attribute value" xml:id="id3"/> + <nu xml:lang="no-nb"> + <upsilon content="attribute value" xml:lang="en-GB" xml:id="id4"> + <lambda att="this.nodeValue" xml:lang="nb"> + <beta insert="attribute value" xml:lang="nb" xml:id="id5"> + <chi xml:lang="no"/> + <theta or="attribute-value"> + <alpha class="solid 1px green" xml:lang="en-US" xml:id="id6"> + <phi att="123456789"/> + <beta> + <kappa xml:lang="no"/> + <upsilon xml:id="id7"/> + <nu/> + <epsilon or="attribute-value"/> + <omega xml:id="id8"> + <iota xml:lang="nb" xml:id="id9"> + <green>This text must be green</green> + </iota> + </omega> + </beta> + </alpha> + </theta> + </beta> + </lambda> + </upsilon> + </nu> + </delta> + </rho> + </iota> + </lambda> + </eta> + </tau> + </tree> + </test> + <test> + <xpath>//eta/iota[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(preceding-sibling::iota)]//theta[contains(concat(@true,"$"),"en$")][@xml:lang="no-nb"][not(following-sibling::*)]//delta[contains(concat(@number,"$"),"blank$")][@xml:lang="en"][@xml:id="id2"]/eta[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[starts-with(concat(@title,"-"),"solid 1px green-")][@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::*[starts-with(@content,"anoth")][@xml:lang="en-US"][@xml:id="id5"][not(child::node())][following-sibling::gamma[@and="another attribute value"][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[@class="this-is-att-value"][@xml:id="id6"][not(preceding-sibling::*)]//theta[contains(@title,"%")][@xml:lang="no-nb"][not(child::node())][following-sibling::pi[@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::psi[contains(@delete,"tru")][following-sibling::*[position()=2]][following-sibling::kappa[@att="another attribute value"][preceding-sibling::*[position() = 3]][following-sibling::alpha[@xml:lang="no-nb"]//gamma]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <eta> + <iota xml:lang="en-GB" xml:id="id1"> + <theta true="solid 1px green" xml:lang="no-nb"> + <delta number="_blank" xml:lang="en" xml:id="id2"> + <eta xml:lang="en-US" xml:id="id3"> + <rho title="solid 1px green" xml:lang="en" xml:id="id4"/> + <any content="another attribute value" xml:lang="en-US" xml:id="id5"/> + <gamma and="another attribute value" xml:lang="en-GB"> + <alpha class="this-is-att-value" xml:id="id6"> + <theta title="100%" xml:lang="no-nb"/> + <pi xml:id="id7"/> + <psi delete="true"/> + <kappa att="another attribute value"/> + <alpha xml:lang="no-nb"> + <gamma> + <green>This text must be green</green> + </gamma> + </alpha> + </alpha> + </gamma> + </eta> + </delta> + </theta> + </iota> + </eta> + </tree> + </test> + <test> + <xpath>//sigma[contains(concat(@attribute,"$"),"bute value$")][@xml:id="id1"]//epsilon[contains(concat(@false,"$"),"e$")][@xml:lang="nb"][@xml:id="id2"]/alpha[following-sibling::*[@attribute][not(child::node())][following-sibling::*[@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega/theta[not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id4"][not(child::node())][following-sibling::zeta[@attribute]//xi[starts-with(@name,"this-is-at")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@false][@xml:lang="en-US"][not(child::node())][following-sibling::epsilon[@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@name][@xml:id="id7"]//gamma[following-sibling::lambda[@xml:lang="nb"]/mu[starts-with(concat(@and,"-"),"false-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="no-nb"]//lambda[@xml:lang="nb"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[contains(@and,"e")][following-sibling::gamma[@insert][@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]][position() = 1]][position() = 1]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <sigma attribute="another attribute value" xml:id="id1"> + <epsilon false="false" xml:lang="nb" xml:id="id2"> + <alpha/> + <any attribute="attribute"/> + <any xml:lang="nb"/> + <omega> + <theta> + <delta xml:lang="en-GB" xml:id="id3"/> + <iota xml:id="id4"/> + <zeta attribute="attribute value"> + <xi name="this-is-att-value" xml:lang="en-GB" xml:id="id5"/> + <pi false="attribute-value" xml:lang="en-US"/> + <epsilon xml:lang="nb" xml:id="id6"/> + <phi name="100%" xml:id="id7"> + <gamma/> + <lambda xml:lang="nb"> + <mu and="false" xml:lang="no-nb"> + <mu xml:lang="no-nb"> + <lambda xml:lang="nb" xml:id="id8"> + <iota and="attribute"/> + <gamma insert="false" xml:lang="nb" xml:id="id9"> + <green>This text must be green</green> + </gamma> + </lambda> + </mu> + </mu> + </lambda> + </phi> + </zeta> + </theta> + </omega> + </epsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@desciption,"$"),"e$")][@xml:lang="en"][@xml:id="id1"]/theta[contains(concat(@desciption,"$"),"23456789$")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]/psi[starts-with(@data,"fal")][@xml:lang="en-GB"][@xml:id="id3"]/iota[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::omicron[starts-with(@false,"attribut")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]/xi[@token="attribute"][@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <beta desciption="true" xml:lang="en" xml:id="id1"> + <theta desciption="123456789" xml:lang="en" xml:id="id2"> + <psi data="false" xml:lang="en-GB" xml:id="id3"> + <iota xml:lang="en-GB" xml:id="id4"/> + <omicron false="attribute" xml:lang="no-nb" xml:id="id5"> + <xi token="attribute" xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </xi> + </omicron> + </psi> + </theta> + </beta> + </tree> + </test> + <test> + <xpath>//iota[starts-with(concat(@and,"-"),"solid 1px green-")]//psi//theta[not(preceding-sibling::*)][following-sibling::alpha[@desciption="_blank"][following-sibling::*[position()=2]][following-sibling::sigma[@xml:lang="en-GB"][following-sibling::kappa[contains(concat(@true,"$"),"en$")][@xml:lang="no"][@xml:id="id1"]//pi[@class="solid 1px green"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::pi)]//upsilon[starts-with(concat(@token,"-"),"123456789-")][@xml:lang="no"][not(following-sibling::*)]//phi[@insert][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::kappa[contains(concat(@delete,"$"),"alue$")][@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::*[@xml:lang="no-nb"][not(preceding-sibling::any)]//rho[@false][following-sibling::chi[contains(concat(@attrib,"$"),"lid 1px green$")][@xml:lang="en-US"][following-sibling::*[position()=3]][following-sibling::epsilon[@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::beta[@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::omicron[contains(concat(@attr,"$")," value$")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <iota and="solid 1px green"> + <psi> + <theta/> + <alpha desciption="_blank"/> + <sigma xml:lang="en-GB"/> + <kappa true="solid 1px green" xml:lang="no" xml:id="id1"> + <pi class="solid 1px green" xml:id="id2"> + <upsilon token="123456789" xml:lang="no"> + <phi insert="this-is-att-value" xml:id="id3"/> + <kappa delete="attribute-value" xml:lang="no" xml:id="id4"/> + <any xml:lang="no-nb"> + <rho false="this.nodeValue"/> + <chi attrib="solid 1px green" xml:lang="en-US"/> + <epsilon xml:lang="no"/> + <beta xml:lang="en" xml:id="id5"/> + <omicron attr="attribute value" xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </any> + </upsilon> + </pi> + </kappa> + </psi> + </iota> + </tree> + </test> + <test> + <xpath>//xi[@attrib="attribute-value"][@xml:lang="no-nb"]/beta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::upsilon[@att][not(child::node())][following-sibling::beta[@true="123456789"][@xml:lang="nb"]/eta[not(preceding-sibling::*)][not(following-sibling::*)]//theta[starts-with(concat(@class,"-"),"attribute value-")][@xml:lang="no-nb"][not(child::node())][following-sibling::*[@xml:lang="en-GB"][not(following-sibling::*)]/*[starts-with(@token,"solid ")][not(following-sibling::*)]/tau[contains(concat(@class,"$"),"_blank$")][@xml:lang="en-GB"][@xml:id="id1"][following-sibling::eta[starts-with(@token,"t")][@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//theta[@or][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[not(following-sibling::*)]//rho[@and="attribute value"][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[not(following-sibling::*)]/omicron[starts-with(concat(@string,"-"),"content-")][@xml:lang="nb"][not(preceding-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <xi attrib="attribute-value" xml:lang="no-nb"> + <beta xml:lang="en-GB"/> + <nu/> + <mu xml:lang="en-GB"/> + <upsilon att="attribute value"/> + <beta true="123456789" xml:lang="nb"> + <eta> + <theta class="attribute value" xml:lang="no-nb"/> + <any xml:lang="en-GB"> + <any token="solid 1px green"> + <tau class="_blank" xml:lang="en-GB" xml:id="id1"/> + <eta token="this.nodeValue" xml:lang="no" xml:id="id2"/> + <delta xml:lang="no-nb" xml:id="id3"> + <theta or="100%"/> + <psi> + <rho and="attribute value" xml:lang="en-GB" xml:id="id4"/> + <any> + <omicron string="content" xml:lang="nb"> + <green>This text must be green</green> + </omicron> + </any> + </psi> + </delta> + </any> + </any> + </eta> + </beta> + </xi> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en"][@xml:id="id1"]//lambda[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[contains(@insert,"is-is-att-value")][@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)][not(preceding-sibling::xi)]/omega[@xml:id="id3"][not(following-sibling::*)]//alpha[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[contains(@token,"%")][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en" xml:id="id1"> + <lambda xml:lang="nb"/> + <xi insert="this-is-att-value" xml:lang="en" xml:id="id2"> + <omega xml:id="id3"> + <alpha xml:id="id4"> + <sigma token="100%"> + <green>This text must be green</green> + </sigma> + </alpha> + </omega> + </xi> + </upsilon> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//iota[contains(@object,"%")][not(preceding-sibling::*)][not(child::node())][following-sibling::*[contains(concat(@attrib,"$"),"value$")][@xml:id="id2"]/phi[contains(@attrib,"ent")][@xml:lang="en"]/eta[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@xml:lang="no-nb"][not(child::node())][following-sibling::xi[@xml:lang="nb"][not(following-sibling::*)]/delta[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="en-US"][@xml:id="id4"][following-sibling::omicron[contains(@name,"9")][@xml:lang="nb"]//epsilon[@number][@xml:id="id5"][not(child::node())][following-sibling::zeta[@true][@xml:lang="en-GB"][following-sibling::*[position()=7]][not(child::node())][following-sibling::theta[starts-with(concat(@insert,"-"),"true-")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=6]][following-sibling::eta[@attrib="false"][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=5]][following-sibling::omicron[starts-with(concat(@content,"-"),"attribute-")][@xml:id="id7"][not(child::node())][following-sibling::zeta[@xml:id="id8"][not(child::node())][following-sibling::gamma[@desciption="true"][@xml:id="id9"][preceding-sibling::*[position() = 6]][following-sibling::kappa[@xml:id="id10"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][not(following-sibling::*)]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <iota object="100%"/> + <any attrib="attribute-value" xml:id="id2"> + <phi attrib="content" xml:lang="en"> + <eta xml:id="id3"> + <beta xml:lang="no-nb"/> + <xi xml:lang="nb"> + <delta false="123456789" xml:lang="en-US" xml:id="id4"/> + <omicron name="123456789" xml:lang="nb"> + <epsilon number="100%" xml:id="id5"/> + <zeta true="100%" xml:lang="en-GB"/> + <theta insert="true"/> + <eta attrib="false" xml:id="id6"/> + <omicron content="attribute" xml:id="id7"/> + <zeta xml:id="id8"/> + <gamma desciption="true" xml:id="id9"/> + <kappa xml:id="id10"/> + <tau xml:lang="no-nb"> + <green>This text must be green</green> + </tau> + </omicron> + </xi> + </eta> + </phi> + </any> + </psi> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en-US"]/zeta[@xml:lang="en"][not(child::node())][following-sibling::theta[@token][@xml:lang="nb"][not(preceding-sibling::theta or following-sibling::theta)][not(child::node())][following-sibling::psi[contains(@token,"ribu")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::epsilon[@xml:id="id1"][preceding-sibling::*[position() = 3]][following-sibling::upsilon[@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::chi[contains(concat(@or,"$"),"blank$")][@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 5]][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en-US"> + <zeta xml:lang="en"/> + <theta token="123456789" xml:lang="nb"/> + <psi token="attribute" xml:lang="nb"/> + <epsilon xml:id="id1"/> + <upsilon xml:lang="nb"/> + <chi or="_blank" xml:lang="en-GB" xml:id="id2"> + <green>This text must be green</green> + </chi> + </sigma> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en-GB"]/psi[@xml:id="id1"][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@xml:lang="nb"][not(following-sibling::*)]/rho[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[starts-with(@insert,"thi")][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::alpha[not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en-GB"> + <psi xml:id="id1"/> + <phi> + <any xml:lang="nb"> + <rho xml:id="id2"/> + <omega insert="this.nodeValue" xml:id="id3"/> + <alpha> + <green>This text must be green</green> + </alpha> + </any> + </phi> + </omega> + </tree> + </test> + <test> + <xpath>//xi[contains(@attr,"tru")][@xml:lang="en-US"][@xml:id="id1"]/theta[not(following-sibling::*)]//omega[contains(@object,"this")][@xml:id="id2"][not(preceding-sibling::*)]/zeta[contains(concat(@title,"$"),"nk$")][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="no-nb"][not(following-sibling::*)]//pi[@xml:id="id4"][not(child::node())][following-sibling::nu[@attrib][@xml:lang="nb"][@xml:id="id5"][following-sibling::omega[contains(@and,"e")][@xml:lang="en"][following-sibling::iota[@xml:lang="en-GB"][not(following-sibling::*)]//beta[@xml:lang="no"][following-sibling::sigma[contains(concat(@false,"$"),"k$")][not(child::node())][following-sibling::sigma[@string="attribute-value"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@or="attribute"][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/iota[starts-with(@name,"attrib")][@xml:id="id8"][not(child::node())][following-sibling::theta[@content][@xml:id="id9"]]][position() = 1]]]]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <xi attr="true" xml:lang="en-US" xml:id="id1"> + <theta> + <omega object="this.nodeValue" xml:id="id2"> + <zeta title="_blank" xml:id="id3"/> + <iota xml:lang="no-nb"> + <pi xml:id="id4"/> + <nu attrib="attribute-value" xml:lang="nb" xml:id="id5"/> + <omega and="false" xml:lang="en"/> + <iota xml:lang="en-GB"> + <beta xml:lang="no"/> + <sigma false="_blank"/> + <sigma string="attribute-value"/> + <any or="attribute" xml:id="id6"/> + <chi xml:lang="no" xml:id="id7"> + <iota name="attribute-value" xml:id="id8"/> + <theta content="this-is-att-value" xml:id="id9"> + <green>This text must be green</green> + </theta> + </chi> + </iota> + </iota> + </omega> + </theta> + </xi> + </tree> + </test> + <test> + <xpath>//sigma[@token]//eta[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[@number][@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//omicron[@data][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::lambda[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::tau[not(following-sibling::*)]/lambda[@xml:id="id4"][not(preceding-sibling::*)]/mu[starts-with(@title,"s")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omicron[@src][@xml:lang="no"][not(child::node())][following-sibling::psi[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:lang="no-nb"][not(following-sibling::*)]/beta[contains(concat(@token,"$"),"r attribute value$")][@xml:lang="no-nb"][not(preceding-sibling::*)]//chi[@token][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@title="false"][@xml:lang="en-US"][@xml:id="id7"]//lambda[@desciption][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:lang="en-US"][not(following-sibling::*)]//iota/mu[@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:id="id9"][not(child::node())][following-sibling::gamma[contains(concat(@string,"$"),"tent$")][@xml:lang="nb"][@xml:id="id10"]/lambda[@desciption][@xml:lang="en"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::xi[@xml:id="id12"][preceding-sibling::*[position() = 1]][not(following-sibling::xi)][following-sibling::theta[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id13"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <sigma token="attribute value"> + <eta xml:lang="no" xml:id="id1"/> + <any number="123456789" xml:lang="no-nb" xml:id="id2"> + <omicron data="attribute value" xml:lang="nb"/> + <lambda xml:id="id3"/> + <tau> + <lambda xml:id="id4"> + <mu title="solid 1px green" xml:id="id5"/> + <iota xml:lang="en"> + <omicron src="false" xml:lang="no"/> + <psi xml:lang="nb"/> + <theta xml:lang="no-nb"> + <beta token="another attribute value" xml:lang="no-nb"> + <chi token="_blank" xml:lang="no" xml:id="id6"> + <nu title="false" xml:lang="en-US" xml:id="id7"> + <lambda desciption="100%" xml:lang="en-GB"> + <chi xml:lang="en-US"> + <iota> + <mu xml:id="id8"> + <lambda xml:id="id9"/> + <gamma string="content" xml:lang="nb" xml:id="id10"> + <lambda desciption="_blank" xml:lang="en" xml:id="id11"/> + <xi xml:id="id12"/> + <theta content="attribute" xml:lang="en-GB" xml:id="id13"> + <green>This text must be green</green> + </theta> + </gamma> + </mu> + </iota> + </chi> + </lambda> + </nu> + </chi> + </beta> + </theta> + </iota> + </lambda> + </tau> + </any> + </sigma> + </tree> + </test> + <test> + <xpath>//omicron[@xml:id="id1"]/phi[contains(concat(@title,"$"),"1px green$")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//tau[@xml:id="id3"][not(child::node())][following-sibling::delta[@true="true"][not(following-sibling::*)]//epsilon[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:lang="no"][following-sibling::psi[@number][@xml:lang="nb"][following-sibling::gamma[following-sibling::zeta[contains(concat(@object,"$"),"%$")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[starts-with(@att,"f")][not(preceding-sibling::sigma)]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:id="id1"> + <phi title="solid 1px green" xml:lang="nb" xml:id="id2"> + <tau xml:id="id3"/> + <delta true="true"> + <epsilon xml:lang="no" xml:id="id4"> + <tau xml:lang="no"/> + <psi number="100%" xml:lang="nb"/> + <gamma/> + <zeta object="100%" xml:lang="nb"/> + <sigma att="false"> + <green>This text must be green</green> + </sigma> + </epsilon> + </delta> + </phi> + </omicron> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="no"]//lambda[following-sibling::*[position()=1]][following-sibling::phi[@content="this.nodeValue"][@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]//theta[@abort][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@data][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[starts-with(concat(@number,"-"),"true-")][@xml:id="id3"][not(following-sibling::zeta)][not(child::node())][following-sibling::beta[@xml:id="id4"][not(following-sibling::*)]/rho[@xml:lang="nb"]//zeta[@content="attribute"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::beta[contains(concat(@attribute,"$"),"n$")][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]//sigma[contains(concat(@class,"$"),"789$")][@xml:lang="en-US"]/eta[@number][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:id="id8"][preceding-sibling::*[position() = 1]]/omicron[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::iota[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[@xml:lang="en-US"][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="no"> + <lambda/> + <phi content="this.nodeValue" xml:lang="no-nb" xml:id="id1"> + <theta abort="another attribute value"> + <delta data="attribute" xml:id="id2"/> + <zeta number="true" xml:id="id3"/> + <beta xml:id="id4"> + <rho xml:lang="nb"> + <zeta content="attribute" xml:id="id5"/> + <beta attribute="solid 1px green" xml:lang="en" xml:id="id6"> + <sigma class="123456789" xml:lang="en-US"> + <eta number="123456789" xml:id="id7"/> + <phi xml:id="id8"> + <omicron/> + <iota> + <theta xml:lang="en-US"> + <green>This text must be green</green> + </theta> + </iota> + </phi> + </sigma> + </beta> + </rho> + </beta> + </theta> + </phi> + </sigma> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="no-nb"][@xml:id="id1"]//omega[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@delete][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]]/lambda[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@xml:id="id3"][not(child::node())][following-sibling::alpha[@title][@xml:lang="no"][@xml:id="id4"]//delta[not(preceding-sibling::*)][not(following-sibling::*)]//eta[@att][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[not(preceding-sibling::*)]//psi[@and="false"][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@attribute][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@token,"-"),"123456789-")][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::delta[following-sibling::mu[@data="another attribute value"]//omega[@data][@xml:lang="en-US"][not(preceding-sibling::*)]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="no-nb" xml:id="id1"> + <omega xml:lang="no-nb"> + <any delete="true"/> + <nu> + <lambda xml:id="id2"> + <theta xml:id="id3"/> + <alpha title="attribute" xml:lang="no" xml:id="id4"> + <delta> + <eta att="this-is-att-value"> + <omicron> + <psi and="false" xml:lang="en" xml:id="id5"> + <lambda attribute="_blank" xml:lang="no"/> + <nu token="123456789" xml:id="id6"/> + <delta/> + <mu data="another attribute value"> + <omega data="false" xml:lang="en-US"> + <green>This text must be green</green> + </omega> + </mu> + </psi> + </omicron> + </eta> + </delta> + </alpha> + </lambda> + </nu> + </omega> + </nu> + </tree> + </test> + <test> + <xpath>//kappa//kappa[contains(concat(@false,"$"),"tent$")][@xml:id="id1"][not(child::node())][following-sibling::iota[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@att]//sigma[@xml:lang="en"][@xml:id="id2"][not(child::node())][following-sibling::delta[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[contains(concat(@name,"$"),"ue$")][not(preceding-sibling::*)][following-sibling::lambda[starts-with(concat(@token,"-"),"100%-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::upsilon[starts-with(@attr,"solid 1px gr")][@xml:lang="en-US"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>1</nth> + </result> + <tree> + <kappa> + <kappa false="content" xml:id="id1"/> + <iota xml:lang="en"/> + <psi att="attribute value"> + <sigma xml:lang="en" xml:id="id2"/> + <delta xml:lang="nb"> + <xi name="true"/> + <lambda token="100%" xml:lang="en-GB"/> + <beta xml:id="id3"/> + <upsilon attr="solid 1px green" xml:lang="en-US"> + <green>This text must be green</green> + </upsilon> + </delta> + </psi> + </kappa> + </tree> + </test> + <test> + <xpath>//chi[starts-with(concat(@name,"-"),"solid 1px green-")]/xi[@xml:id="id1"][not(following-sibling::*)]//tau[@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(@and,"00%")][@xml:id="id3"]/beta[@xml:id="id4"][following-sibling::gamma[@xml:lang="en"][@xml:id="id5"][following-sibling::epsilon[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[starts-with(concat(@attr,"-"),"true-")][@xml:lang="no"][not(preceding-sibling::nu)][following-sibling::eta[contains(@content,"een")][@xml:lang="no"][preceding-sibling::*[position() = 1]]/iota[@xml:lang="no"][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/theta[@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::sigma[@desciption="true"][@xml:id="id8"]//kappa[contains(@insert,"ri")][not(preceding-sibling::*)][following-sibling::omega[starts-with(concat(@false,"-"),"true-")]//mu[contains(@false,"ru")][@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::omicron[@xml:lang="nb"][@xml:id="id9"][not(child::node())][following-sibling::iota[@xml:lang="nb"][not(following-sibling::*)]//alpha[@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[contains(@src,"nt")][preceding-sibling::*[position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <chi name="solid 1px green"> + <xi xml:id="id1"> + <tau xml:lang="en-US" xml:id="id2"/> + <sigma and="100%" xml:id="id3"> + <beta xml:id="id4"/> + <gamma xml:lang="en" xml:id="id5"/> + <epsilon xml:id="id6"> + <nu attr="true" xml:lang="no"/> + <eta content="solid 1px green" xml:lang="no"> + <iota xml:lang="no"/> + <iota xml:lang="en-US"> + <theta xml:id="id7"/> + <sigma desciption="true" xml:id="id8"> + <kappa insert="attribute"/> + <omega false="true"> + <mu false="true" xml:lang="en"/> + <omicron xml:lang="nb" xml:id="id9"/> + <iota xml:lang="nb"> + <alpha xml:lang="en"/> + <omicron src="content"> + <green>This text must be green</green> + </omicron> + </iota> + </omega> + </sigma> + </iota> + </eta> + </epsilon> + </sigma> + </xi> + </chi> + </tree> + </test> + <test> + <xpath>//beta[@xml:id="id1"]//iota[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/iota[@xml:lang="no-nb"][not(preceding-sibling::*)]//epsilon[@xml:lang="en"][not(preceding-sibling::*)]/lambda[not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)]//delta[@false][@xml:lang="no-nb"]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:id="id1"> + <iota xml:lang="en-US" xml:id="id2"> + <iota xml:lang="no-nb"> + <epsilon xml:lang="en"> + <lambda> + <epsilon xml:lang="en-US" xml:id="id3"> + <delta false="attribute" xml:lang="no-nb"> + <green>This text must be green</green> + </delta> + </epsilon> + </lambda> + </epsilon> + </iota> + </iota> + </beta> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/beta[starts-with(@attrib,"solid 1px gr")][following-sibling::tau[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::psi[@string][@xml:lang="no-nb"][@xml:id="id3"][not(child::node())][following-sibling::alpha[@delete][@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 4]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <beta attrib="solid 1px green"/> + <tau xml:lang="en-US"/> + <zeta xml:id="id2"/> + <psi string="solid 1px green" xml:lang="no-nb" xml:id="id3"/> + <alpha delete="attribute" xml:lang="en" xml:id="id4"> + <green>This text must be green</green> + </alpha> + </nu> + </tree> + </test> + <test> + <xpath>//iota[contains(concat(@token,"$"),"false$")][@xml:lang="en"][@xml:id="id1"]/lambda[@number="true"][@xml:id="id2"]/upsilon[@token][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[@xml:lang="nb"][not(following-sibling::*)]/eta[not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@object,"-"),"solid 1px green-")][@xml:id="id3"][preceding-sibling::*[position() = 1]]/nu[@src][not(following-sibling::*)]/tau[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[not(following-sibling::*)]//tau[starts-with(@false,"th")]//mu[starts-with(@delete,"a")][@xml:lang="nb"][@xml:id="id5"]//lambda[starts-with(concat(@and,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]/nu[contains(concat(@string,"$"),"tent$")][@xml:lang="no"][not(preceding-sibling::*)]//chi[position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <iota token="false" xml:lang="en" xml:id="id1"> + <lambda number="true" xml:id="id2"> + <upsilon token="_blank" xml:lang="no"/> + <rho xml:lang="nb"> + <eta/> + <nu object="solid 1px green" xml:id="id3"> + <nu src="this-is-att-value"> + <tau xml:lang="en" xml:id="id4"/> + <xi> + <tau false="this.nodeValue"> + <mu delete="attribute" xml:lang="nb" xml:id="id5"> + <lambda and="attribute" xml:lang="nb" xml:id="id6"> + <nu string="content" xml:lang="no"> + <chi> + <green>This text must be green</green> + </chi> + </nu> + </lambda> + </mu> + </tau> + </xi> + </nu> + </nu> + </rho> + </lambda> + </iota> + </tree> + </test> + <test> + <xpath>//mu//lambda[starts-with(@attr,"100")][@xml:lang="no-nb"][@xml:id="id1"]/chi[@xml:id="id2"][not(child::node())][following-sibling::beta[@delete="true"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@src="solid 1px green"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::sigma[not(child::node())][following-sibling::rho[starts-with(@attribute,"attribu")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[starts-with(@abort,"this.nodeV")][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[contains(concat(@attrib,"$"),"lue$")]/chi[@abort="false"][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::nu[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::mu[@xml:id="id6"]/beta[following-sibling::kappa[starts-with(concat(@object,"-"),"this-")][@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::rho[@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::sigma[@title][@xml:id="id9"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//xi[@false][not(preceding-sibling::*)][following-sibling::pi[@xml:id="id10"][preceding-sibling::*[position() = 1]]//nu[starts-with(@attribute,"conte")][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::psi[starts-with(concat(@number,"-"),"true-")][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@true="123456789"][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho[@xml:lang="en-US"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]]][position() = 1]]]]]]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <lambda attr="100%" xml:lang="no-nb" xml:id="id1"> + <chi xml:id="id2"/> + <beta delete="true" xml:id="id3"> + <phi src="solid 1px green" xml:id="id4"/> + <sigma/> + <rho attribute="attribute"> + <alpha abort="this.nodeValue"/> + <chi attrib="this-is-att-value"> + <chi abort="false" xml:lang="en" xml:id="id5"/> + <nu xml:lang="en-US"/> + <mu xml:id="id6"> + <beta/> + <kappa object="this-is-att-value" xml:lang="en-US" xml:id="id7"/> + <rho xml:id="id8"/> + <sigma title="this-is-att-value" xml:id="id9"> + <xi false="another attribute value"/> + <pi xml:id="id10"> + <nu attribute="content"/> + <psi number="true" xml:id="id11"/> + <xi true="123456789" xml:lang="no-nb"/> + <rho xml:lang="en-US"> + <green>This text must be green</green> + </rho> + </pi> + </sigma> + </mu> + </chi> + </rho> + </beta> + </lambda> + </mu> + </tree> + </test> + <test> + <xpath>//xi[@attrib]//delta[@xml:lang="no-nb"][not(preceding-sibling::*)]/gamma[not(following-sibling::*)]//beta[contains(concat(@title,"$"),"odeValue$")][@xml:id="id1"]/omega[contains(@true,"ribute value")][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id2"]/chi[@xml:lang="en"][not(following-sibling::*)][not(parent::*/*[position()=2])]/rho[@insert][@xml:lang="no"][following-sibling::iota[following-sibling::upsilon[starts-with(@abort,"this.nodeVal")][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <xi attrib="attribute-value"> + <delta xml:lang="no-nb"> + <gamma> + <beta title="this.nodeValue" xml:id="id1"> + <omega true="another attribute value"> + <upsilon xml:id="id2"> + <chi xml:lang="en"> + <rho insert="another attribute value" xml:lang="no"/> + <iota/> + <upsilon abort="this.nodeValue" xml:id="id3"> + <green>This text must be green</green> + </upsilon> + </chi> + </upsilon> + </omega> + </beta> + </gamma> + </delta> + </xi> + </tree> + </test> + <test> + <xpath>//mu//epsilon[@attrib="123456789"][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 1]]/gamma[@xml:id="id2"][not(child::node())][following-sibling::rho[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:lang="no"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::zeta[contains(@and,"123456")][@xml:lang="en-US"][following-sibling::chi[contains(concat(@or,"$"),"odeValue$")][preceding-sibling::*[position() = 5]]/lambda[starts-with(@object,"1")][@xml:id="id5"][not(following-sibling::*)]/theta[not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <epsilon attrib="123456789" xml:id="id1"/> + <theta> + <gamma xml:id="id2"/> + <rho xml:id="id3"/> + <kappa xml:lang="no"/> + <upsilon xml:id="id4"/> + <zeta and="123456789" xml:lang="en-US"/> + <chi or="this.nodeValue"> + <lambda object="100%" xml:id="id5"> + <theta/> + <epsilon xml:lang="no-nb"> + <green>This text must be green</green> + </epsilon> + </lambda> + </chi> + </theta> + </mu> + </tree> + </test> + <test> + <xpath>//sigma[@xml:id="id1"]/gamma[@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::nu//alpha[@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[not(child::node())][following-sibling::gamma/kappa[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[not(child::node())][following-sibling::xi[@xml:lang="en-US"][@xml:id="id3"]//beta[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[starts-with(@string,"fal")][@xml:lang="en"][following-sibling::*[position()=3]][not(child::node())][following-sibling::epsilon[contains(@name,"eVal")][@xml:lang="en-GB"][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[not(child::node())][following-sibling::iota[@delete][@xml:lang="en-US"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//eta[not(preceding-sibling::*)][following-sibling::eta[@number][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//gamma[contains(@token,"ank")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)]//omega[not(following-sibling::*)]/delta[@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:id="id1"> + <gamma xml:lang="en-US"/> + <nu> + <alpha xml:lang="en" xml:id="id2"/> + <tau xml:lang="nb"/> + <kappa/> + <gamma> + <kappa xml:lang="en-US"/> + <upsilon/> + <xi xml:lang="en-US" xml:id="id3"> + <beta xml:lang="en-GB" xml:id="id4"/> + <alpha string="false" xml:lang="en"/> + <epsilon name="this.nodeValue" xml:lang="en-GB"/> + <mu/> + <iota delete="true" xml:lang="en-US"> + <eta/> + <eta number="_blank"> + <gamma token="_blank" xml:lang="en-GB" xml:id="id5"> + <omega> + <delta xml:lang="no-nb" xml:id="id6"/> + <rho xml:lang="no-nb"/> + <delta xml:lang="no-nb"> + <green>This text must be green</green> + </delta> + </omega> + </gamma> + </eta> + </iota> + </xi> + </gamma> + </nu> + </sigma> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]//epsilon[not(preceding-sibling::*)][following-sibling::pi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omicron[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[not(child::node())][following-sibling::epsilon[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::tau[@xml:lang="nb"][preceding-sibling::*[position() = 2]]//iota[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::iota[@token="100%"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[@xml:id="id5"][preceding-sibling::*[position() = 2]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <epsilon/> + <pi> + <omicron xml:lang="en-GB" xml:id="id2"> + <rho/> + <epsilon xml:lang="no" xml:id="id3"/> + <tau xml:lang="nb"> + <iota/> + <iota token="100%" xml:id="id4"/> + <any xml:id="id5"> + <green>This text must be green</green> + </any> + </tau> + </omicron> + </pi> + </alpha> + </tree> + </test> + <test> + <xpath>//omicron[@number]/tau[@xml:lang="en-GB"][not(preceding-sibling::*)][not(preceding-sibling::tau or following-sibling::tau)][following-sibling::iota[starts-with(concat(@class,"-"),"true-")][preceding-sibling::*[position() = 1]][following-sibling::nu[@xml:id="id1"][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 3]][following-sibling::pi[contains(@desciption,"0")][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/sigma[@token][following-sibling::eta[contains(concat(@object,"$"),"her attribute value$")][@xml:lang="en-US"][@xml:id="id2"]//rho[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)]//*[contains(concat(@att,"$"),"ute value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@desciption]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omicron number="another attribute value"> + <tau xml:lang="en-GB"/> + <iota class="true"/> + <nu xml:id="id1"/> + <chi/> + <pi desciption="100%" xml:lang="no-nb"> + <sigma token="true"/> + <eta object="another attribute value" xml:lang="en-US" xml:id="id2"> + <rho xml:lang="en-GB" xml:id="id3"> + <any att="another attribute value" xml:lang="no-nb"/> + <any desciption="123456789"> + <green>This text must be green</green> + </any> + </rho> + </eta> + </pi> + </omicron> + </tree> + </test> + <test> + <xpath>//delta[contains(concat(@class,"$"),"9$")][@xml:lang="nb"]/mu[@xml:lang="no"][not(preceding-sibling::*)]/phi[starts-with(concat(@string,"-"),"attribute-")][@xml:lang="no"][@xml:id="id1"][not(child::node())][following-sibling::theta[contains(concat(@class,"$"),"tribute value$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::mu[following-sibling::phi[@delete][@xml:id="id4"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::chi[@xml:lang="no"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]//chi[@class="solid 1px green"][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]/zeta[@object="_blank"][@xml:lang="en-GB"]/*[not(preceding-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <delta class="123456789" xml:lang="nb"> + <mu xml:lang="no"> + <phi string="attribute" xml:lang="no" xml:id="id1"/> + <theta class="another attribute value" xml:id="id2"/> + <zeta xml:lang="no" xml:id="id3"/> + <mu/> + <phi delete="attribute value" xml:id="id4"/> + <chi xml:lang="no"> + <chi class="solid 1px green" xml:lang="nb" xml:id="id5"> + <gamma xml:lang="en-US" xml:id="id6"> + <zeta object="_blank" xml:lang="en-GB"> + <any> + <green>This text must be green</green> + </any> + </zeta> + </gamma> + </chi> + </chi> + </mu> + </delta> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="nb"]/kappa[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[contains(@number,"his-is-at")][not(following-sibling::*)]//epsilon[@attrib][@xml:id="id2"][not(following-sibling::*)]//tau[@number][@xml:lang="en"][not(following-sibling::*)]//beta[starts-with(concat(@attr,"-"),"123456789-")][@xml:id="id3"][not(following-sibling::*)]//kappa[@xml:id="id4"][not(child::node())][following-sibling::epsilon[starts-with(@abort,"solid 1px gr")][@xml:id="id5"][not(child::node())][following-sibling::beta[not(following-sibling::*)]//nu/iota[not(preceding-sibling::*)]/eta[starts-with(concat(@data,"-"),"100%-")][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@attr][@xml:lang="no"][not(child::node())][following-sibling::omega[contains(@false,"tent")][preceding-sibling::*[position() = 2]]//upsilon[starts-with(@insert,"false")][@xml:lang="en-US"]//lambda[@attribute][@xml:lang="no-nb"][@xml:id="id6"][not(child::node())][following-sibling::kappa[@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][following-sibling::zeta[starts-with(concat(@true,"-"),"content-")][@xml:id="id8"][following-sibling::*[position()=4]][following-sibling::pi[preceding-sibling::*[position() = 3]][following-sibling::omega[starts-with(@attribute,"so")][not(child::node())][following-sibling::sigma[@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::psi[@xml:lang="en-GB"][preceding-sibling::*[position() = 6]][not(following-sibling::*)]/beta[@xml:lang="en"]/psi[@xml:lang="nb"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>1</nth> + </result> + <tree> + <theta xml:lang="nb"> + <kappa xml:id="id1"> + <nu number="this-is-att-value"> + <epsilon attrib="attribute value" xml:id="id2"> + <tau number="100%" xml:lang="en"> + <beta attr="123456789" xml:id="id3"> + <kappa xml:id="id4"/> + <epsilon abort="solid 1px green" xml:id="id5"/> + <beta> + <nu> + <iota> + <eta data="100%"/> + <chi attr="this.nodeValue" xml:lang="no"/> + <omega false="content"> + <upsilon insert="false" xml:lang="en-US"> + <lambda attribute="attribute value" xml:lang="no-nb" xml:id="id6"/> + <kappa xml:id="id7"/> + <zeta true="content" xml:id="id8"/> + <pi/> + <omega attribute="solid 1px green"/> + <sigma xml:id="id9"/> + <psi xml:lang="en-GB"> + <beta xml:lang="en"> + <psi xml:lang="nb"> + <green>This text must be green</green> + </psi> + </beta> + </psi> + </upsilon> + </omega> + </iota> + </nu> + </beta> + </beta> + </tau> + </epsilon> + </nu> + </kappa> + </theta> + </tree> + </test> + <test> + <xpath>//omega/epsilon[@insert][not(child::node())][following-sibling::zeta[starts-with(concat(@string,"-"),"attribute value-")][@xml:id="id1"][not(child::node())][following-sibling::gamma[starts-with(@false,"this-is-att-")][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/pi[not(preceding-sibling::*)][following-sibling::phi[@content][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[contains(@true," 1px green")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 3]]//zeta[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)]//iota[contains(@token,"se")][@xml:id="id8"][not(child::node())][following-sibling::xi[starts-with(concat(@insert,"-"),"another attribute value-")][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[contains(@object,"te")][@xml:id="id10"][not(child::node())][following-sibling::psi[@xml:lang="nb"][following-sibling::nu[contains(concat(@content,"$"),"ute$")][@xml:lang="no-nb"][following-sibling::nu[starts-with(@string,"solid 1px gre")][@xml:lang="en-GB"][@xml:id="id11"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <epsilon insert="attribute"/> + <zeta string="attribute value" xml:id="id1"/> + <gamma false="this-is-att-value" xml:lang="en" xml:id="id2"> + <pi/> + <phi content="_blank" xml:id="id3"/> + <xi xml:id="id4"/> + <any true="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <zeta xml:id="id6"> + <kappa xml:lang="nb" xml:id="id7"> + <iota token="false" xml:id="id8"/> + <xi insert="another attribute value" xml:id="id9"/> + <rho object="attribute" xml:id="id10"/> + <psi xml:lang="nb"/> + <nu content="attribute" xml:lang="no-nb"/> + <nu string="solid 1px green" xml:lang="en-GB" xml:id="id11"> + <green>This text must be green</green> + </nu> + </kappa> + </zeta> + </any> + </gamma> + </omega> + </tree> + </test> + <test> + <xpath>//*[@string]/chi//mu[@name][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[contains(@desciption,"b")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::tau[contains(concat(@att,"$"),"true$")][following-sibling::upsilon[contains(@attr,"nk")][@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::xi[contains(concat(@class,"$"),"se$")][@xml:lang="en-GB"][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 4]]/lambda[@xml:lang="en"][@xml:id="id5"]//beta[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@delete][following-sibling::psi[@xml:lang="no-nb"][@xml:id="id7"]/psi[@xml:id="id8"][not(preceding-sibling::*)]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <any string="this-is-att-value"> + <chi> + <mu name="attribute-value" xml:lang="no-nb" xml:id="id1"> + <sigma desciption="_blank" xml:lang="nb" xml:id="id2"/> + <tau att="true"/> + <upsilon attr="_blank" xml:lang="nb" xml:id="id3"/> + <xi class="false" xml:lang="en-GB"/> + <any xml:id="id4"> + <lambda xml:lang="en" xml:id="id5"> + <beta xml:id="id6"/> + <zeta delete="attribute"/> + <psi xml:lang="no-nb" xml:id="id7"> + <psi xml:id="id8"> + <green>This text must be green</green> + </psi> + </psi> + </lambda> + </any> + </mu> + </chi> + </any> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en"][@xml:id="id1"]/theta[contains(concat(@data,"$"),"e$")][not(preceding-sibling::*)][following-sibling::rho[@xml:lang="nb"][preceding-sibling::*[position() = 1]]//tau[@token][@xml:lang="no"][following-sibling::iota[@xml:lang="en-US"][@xml:id="id2"][following-sibling::tau[@attr][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//eta[@xml:lang="no"][following-sibling::*[position()=3]][not(child::node())][following-sibling::lambda[starts-with(concat(@abort,"-"),"this-")][@xml:lang="nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::alpha)][following-sibling::delta[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 3]]//omega/*[starts-with(@false,"so")][not(preceding-sibling::*)][following-sibling::iota[@xml:id="id5"][not(child::node())][following-sibling::alpha[@attr="attribute-value"][@xml:id="id6"][following-sibling::pi[starts-with(concat(@attr,"-"),"another attribute value-")][preceding-sibling::*[position() = 3]][following-sibling::omega/zeta[@xml:lang="no-nb"][not(preceding-sibling::*)]//lambda[@and][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en" xml:id="id1"> + <theta data="false"/> + <rho xml:lang="nb"> + <tau token="100%" xml:lang="no"/> + <iota xml:lang="en-US" xml:id="id2"/> + <tau attr="this.nodeValue"> + <eta xml:lang="no"/> + <lambda abort="this-is-att-value" xml:lang="nb"/> + <alpha xml:id="id3"/> + <delta xml:lang="en-US" xml:id="id4"> + <omega> + <any false="solid 1px green"/> + <iota xml:id="id5"/> + <alpha attr="attribute-value" xml:id="id6"/> + <pi attr="another attribute value"/> + <omega> + <zeta xml:lang="no-nb"> + <lambda and="solid 1px green" xml:lang="en-US"> + <mu> + <green>This text must be green</green> + </mu> + </lambda> + </zeta> + </omega> + </omega> + </delta> + </tau> + </rho> + </upsilon> + </tree> + </test> + <test> + <xpath>//epsilon[starts-with(concat(@attr,"-"),"this-")][@xml:lang="no-nb"]//sigma[@delete="solid 1px green"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[contains(concat(@title,"$"),"e$")][@xml:id="id2"][not(following-sibling::*)]//chi[starts-with(concat(@class,"-"),"this-")]//chi[contains(@token,"12")][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[contains(concat(@string,"$"),"te value$")][@xml:lang="no"][not(preceding-sibling::*)]/omega[@and][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::alpha[not(following-sibling::*)]//lambda[@object][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <epsilon attr="this-is-att-value" xml:lang="no-nb"> + <sigma delete="solid 1px green" xml:id="id1"> + <eta title="attribute-value" xml:id="id2"> + <chi class="this-is-att-value"> + <chi token="123456789"> + <lambda string="another attribute value" xml:lang="no"> + <omega and="this.nodeValue" xml:id="id3"/> + <any xml:id="id4"> + <omega xml:lang="en-US" xml:id="id5"/> + <alpha> + <lambda object="this-is-att-value" xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </lambda> + </alpha> + </any> + </lambda> + </chi> + </chi> + </eta> + </sigma> + </epsilon> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="no"]//iota[@xml:lang="en"][@xml:id="id1"]//nu[@xml:lang="nb"]//nu[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::nu[@xml:lang="no-nb"][@xml:id="id2"][following-sibling::epsilon[preceding-sibling::*[position() = 2]]//lambda[not(child::node())][following-sibling::beta[@true="attribute"][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@xml:lang="en-GB"]/sigma[starts-with(concat(@string,"-"),"attribute-")][@xml:lang="en"]/psi[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(concat(@attr,"$"),"ue$")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/epsilon[starts-with(concat(@data,"-"),"solid 1px green-")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>1</nth> + </result> + <tree> + <omega xml:lang="no"> + <iota xml:lang="en" xml:id="id1"> + <nu xml:lang="nb"> + <nu xml:lang="en"/> + <nu xml:lang="no-nb" xml:id="id2"/> + <epsilon> + <lambda/> + <beta true="attribute" xml:lang="en-US" xml:id="id3"> + <phi xml:lang="en-GB"> + <sigma string="attribute-value" xml:lang="en"> + <psi xml:id="id4"/> + <delta attr="true" xml:id="id5"/> + <theta xml:id="id6"> + <epsilon data="solid 1px green"> + <green>This text must be green</green> + </epsilon> + </theta> + </sigma> + </phi> + </beta> + </epsilon> + </nu> + </iota> + </omega> + </tree> + </test> + <test> + <xpath>//xi/beta[@number][@xml:id="id1"][not(child::node())][following-sibling::theta[@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@and][@xml:id="id3"][not(following-sibling::*)][not(preceding-sibling::alpha)]//delta[following-sibling::*[position()=1]][following-sibling::delta[contains(concat(@token,"$"),"t$")][@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)]/alpha[following-sibling::*[position()=1]][following-sibling::pi[@string][preceding-sibling::*[position() = 1]]//mu[@class="123456789"][@xml:lang="en"][@xml:id="id5"]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <xi> + <beta number="attribute-value" xml:id="id1"/> + <theta xml:lang="nb" xml:id="id2"/> + <alpha and="attribute" xml:id="id3"> + <delta/> + <delta token="content" xml:lang="no" xml:id="id4"> + <alpha/> + <pi string="attribute value"> + <mu class="123456789" xml:lang="en" xml:id="id5"> + <green>This text must be green</green> + </mu> + </pi> + </delta> + </alpha> + </xi> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="no"]/psi[not(preceding-sibling::*)][not(child::node())][following-sibling::tau[starts-with(concat(@content,"-"),"100%-")]//gamma[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/chi[@and][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::pi[position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="no"> + <psi/> + <tau content="100%"> + <gamma xml:lang="no-nb" xml:id="id1"/> + <zeta xml:lang="no-nb"> + <chi and="this.nodeValue" xml:lang="en"/> + <pi> + <green>This text must be green</green> + </pi> + </zeta> + </tau> + </phi> + </tree> + </test> + <test> + <xpath>//sigma/zeta[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[@class="100%"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id3"][not(following-sibling::*)]//iota[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::rho[@xml:lang="en"][@xml:id="id5"]//zeta[@abort="attribute"][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[starts-with(concat(@true,"-"),"attribute-")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//alpha[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="en"][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id8"]//omicron[starts-with(@name,"attribute-value")][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[contains(@number,"tent")][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(@att,"ibute valu")][@xml:lang="en-US"][not(child::node())][following-sibling::gamma[contains(concat(@object,"$"),"te value$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <zeta xml:id="id1"/> + <xi class="100%" xml:id="id2"/> + <alpha xml:lang="en-GB" xml:id="id3"> + <iota xml:lang="en-GB" xml:id="id4"/> + <rho xml:lang="en" xml:id="id5"> + <zeta abort="attribute" xml:lang="en-GB"/> + <delta true="attribute" xml:id="id6"> + <alpha xml:lang="en" xml:id="id7"> + <omicron xml:lang="en"/> + <chi xml:lang="no" xml:id="id8"> + <omicron name="attribute-value" xml:id="id9"> + <upsilon number="content" xml:id="id10"/> + <sigma att="attribute value" xml:lang="en-US"/> + <gamma object="another attribute value"> + <green>This text must be green</green> + </gamma> + </omicron> + </chi> + </alpha> + </delta> + </rho> + </alpha> + </sigma> + </tree> + </test> + <test> + <xpath>//mu[@object="100%"][@xml:lang="no-nb"]//psi[@name][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)]//iota[following-sibling::kappa[@src][following-sibling::mu[following-sibling::*[position()=5]][following-sibling::upsilon[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::chi[following-sibling::iota[@xml:lang="nb"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::eta[@xml:lang="en"][preceding-sibling::*[position() = 6]][following-sibling::chi[starts-with(@attrib,"123")][@xml:lang="no"][preceding-sibling::*[position() = 7]]/omega[@or][@xml:lang="en-GB"][following-sibling::*[position()=2]][following-sibling::mu[@delete][following-sibling::*[position()=1]][following-sibling::kappa[contains(concat(@object,"$"),"%$")][@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]//alpha[@xml:lang="en"][@xml:id="id3"]//eta[@desciption][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(concat(@false,"-"),"true-")][preceding-sibling::*[position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <mu object="100%" xml:lang="no-nb"> + <psi name="another attribute value" xml:lang="en-GB" xml:id="id1"> + <iota/> + <kappa src="this-is-att-value"/> + <mu/> + <upsilon/> + <chi/> + <iota xml:lang="nb"/> + <eta xml:lang="en"/> + <chi attrib="123456789" xml:lang="no"> + <omega or="this-is-att-value" xml:lang="en-GB"/> + <mu delete="content"/> + <kappa object="100%" xml:lang="no-nb" xml:id="id2"> + <alpha xml:lang="en" xml:id="id3"> + <eta desciption="content"/> + <delta false="true"> + <green>This text must be green</green> + </delta> + </alpha> + </kappa> + </chi> + </psi> + </mu> + </tree> + </test> + <test> + <xpath>//nu[@and][@xml:lang="en-GB"]//nu[@xml:id="id1"][not(child::node())][following-sibling::eta[@insert][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[starts-with(@abort,"solid 1px ")][@xml:id="id2"][preceding-sibling::*[position() = 2]]/xi[@xml:lang="en-GB"][not(following-sibling::*)]/psi[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::psi)]//mu[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[following-sibling::*[position()=3]][not(child::node())][following-sibling::delta[not(child::node())][following-sibling::xi[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::theta[preceding-sibling::*[position() = 4]][not(following-sibling::*)]//eta[not(following-sibling::*)]/beta[contains(concat(@data,"$"),"alse$")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]/lambda[@attribute="true"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="en-US"][@xml:id="id8"][position() = 1]][position() = 1]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>1</nth> + </result> + <tree> + <nu and="attribute value" xml:lang="en-GB"> + <nu xml:id="id1"/> + <eta insert="content" xml:lang="no-nb"/> + <any abort="solid 1px green" xml:id="id2"> + <xi xml:lang="en-GB"> + <psi xml:lang="en-US" xml:id="id3"> + <mu xml:lang="no" xml:id="id4"/> + <lambda/> + <delta/> + <xi xml:id="id5"/> + <theta> + <eta> + <beta data="false" xml:lang="en"/> + <theta xml:lang="en-US" xml:id="id6"> + <lambda attribute="true" xml:id="id7"/> + <beta xml:lang="en-US" xml:id="id8"> + <green>This text must be green</green> + </beta> + </theta> + </eta> + </theta> + </psi> + </xi> + </any> + </nu> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="nb"][@xml:id="id1"]/epsilon[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]/phi[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::phi)]/upsilon[@and="this.nodeValue"][@xml:lang="no-nb"][not(following-sibling::*)]//mu[starts-with(@object,"attri")][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::psi[@xml:lang="no-nb"][not(following-sibling::*)]//phi[@string][not(following-sibling::*)]/alpha[starts-with(concat(@name,"-"),"content-")][not(following-sibling::*)]/delta[@title][@xml:lang="no"][following-sibling::*[@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@false][preceding-sibling::*[position() = 2]]/psi[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::delta[starts-with(@attribute,"t")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//mu[@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[contains(concat(@abort,"$"),"this.nodeValue$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="nb" xml:id="id1"> + <epsilon xml:lang="en" xml:id="id2"> + <phi xml:lang="en"> + <upsilon and="this.nodeValue" xml:lang="no-nb"> + <mu object="attribute-value" xml:lang="no-nb" xml:id="id3"/> + <psi xml:lang="no-nb"> + <phi string="this.nodeValue"> + <alpha name="content"> + <delta title="true" xml:lang="no"/> + <any xml:lang="en-GB" xml:id="id4"/> + <mu false="true"> + <psi xml:lang="en-US" xml:id="id5"> + <xi xml:lang="no"/> + <delta attribute="this.nodeValue" xml:id="id6"> + <mu xml:id="id7"/> + <beta abort="this.nodeValue" xml:lang="no-nb"> + <green>This text must be green</green> + </beta> + </delta> + </psi> + </mu> + </alpha> + </phi> + </psi> + </upsilon> + </phi> + </epsilon> + </theta> + </tree> + </test> + <test> + <xpath>//lambda[contains(@desciption,"als")]/zeta[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)]//beta[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::rho[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[starts-with(concat(@and,"-"),"another attribute value-")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[starts-with(@object,"attr")][@xml:lang="en-GB"][@xml:id="id3"]/epsilon[@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[contains(concat(@abort,"$"),"e$")][@xml:id="id5"][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <lambda desciption="false"> + <zeta xml:lang="en" xml:id="id1"> + <beta xml:lang="no"/> + <rho> + <beta and="another attribute value" xml:id="id2"> + <theta object="attribute value" xml:lang="en-GB" xml:id="id3"> + <epsilon xml:id="id4"/> + <gamma abort="another attribute value" xml:id="id5"> + <green>This text must be green</green> + </gamma> + </theta> + </beta> + </rho> + </zeta> + </lambda> + </tree> + </test> + <test> + <xpath>//eta[contains(concat(@name,"$"),"en$")][@xml:lang="no-nb"]/lambda[starts-with(@abort,"attrib")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@and="attribute value"][@xml:id="id2"][not(following-sibling::*)]/eta[contains(@class,"ribute-value")][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:id="id3"]//zeta[contains(concat(@or,"$"),"alue$")][not(preceding-sibling::*)]//nu[contains(concat(@delete,"$"),"00%$")][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@attr]/omicron[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::phi[@xml:id="id4"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <eta name="solid 1px green" xml:lang="no-nb"> + <lambda abort="attribute-value" xml:id="id1"/> + <pi and="attribute value" xml:id="id2"> + <eta class="attribute-value"/> + <sigma xml:id="id3"> + <zeta or="attribute value"> + <nu delete="100%"/> + <zeta attr="another attribute value"> + <omicron xml:lang="en-US"/> + <phi xml:id="id4"> + <green>This text must be green</green> + </phi> + </zeta> + </zeta> + </sigma> + </pi> + </eta> + </tree> + </test> + <test> + <xpath>//nu[@object][@xml:lang="en-GB"]/iota[starts-with(@desciption,"sol")][@xml:lang="no"][@xml:id="id1"]//iota[contains(@delete,"lan")][@xml:lang="nb"][not(child::node())][following-sibling::kappa[@true]/phi[not(preceding-sibling::*)]/zeta[starts-with(concat(@true,"-"),"true-")][@xml:lang="no-nb"][not(preceding-sibling::*)]//omega[contains(@insert,"lue")][@xml:id="id2"][not(following-sibling::*)]/lambda[contains(concat(@object,"$"),"ntent$")][@xml:lang="no"][not(preceding-sibling::lambda)]/kappa[@object][@xml:id="id3"]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>1</nth> + </result> + <tree> + <nu object="100%" xml:lang="en-GB"> + <iota desciption="solid 1px green" xml:lang="no" xml:id="id1"> + <iota delete="_blank" xml:lang="nb"/> + <kappa true="123456789"> + <phi> + <zeta true="true" xml:lang="no-nb"> + <omega insert="attribute value" xml:id="id2"> + <lambda object="content" xml:lang="no"> + <kappa object="100%" xml:id="id3"> + <green>This text must be green</green> + </kappa> + </lambda> + </omega> + </zeta> + </phi> + </kappa> + </iota> + </nu> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="en-US"]//tau[starts-with(@content,"content")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:lang="en"][@xml:id="id1"]/*[@token][@xml:lang="en-US"][following-sibling::lambda[@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=7]][not(child::node())][following-sibling::*[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::alpha[contains(concat(@src,"$"),"lse$")][@xml:lang="en"][not(child::node())][following-sibling::gamma[@content][@xml:id="id3"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::beta[@attrib][@xml:lang="no"][not(child::node())][following-sibling::delta[@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 7]][following-sibling::sigma[@token][not(following-sibling::*)]//kappa[@or="this.nodeValue"][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/*[contains(@data,"lse")][@xml:lang="nb"]/chi[@xml:lang="no"][@xml:id="id6"][following-sibling::gamma[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[starts-with(@object,"thi")][not(child::node())][following-sibling::lambda[@xml:lang="nb"][not(following-sibling::*)]/gamma[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="en-US"> + <tau content="content" xml:lang="en-GB"> + <kappa xml:lang="en" xml:id="id1"> + <any token="100%" xml:lang="en-US"/> + <lambda xml:id="id2"/> + <any xml:lang="no-nb"/> + <omicron/> + <alpha src="false" xml:lang="en"/> + <gamma content="_blank" xml:id="id3"/> + <beta attrib="123456789" xml:lang="no"/> + <delta xml:lang="nb" xml:id="id4"/> + <sigma token="solid 1px green"> + <kappa or="this.nodeValue" xml:lang="no" xml:id="id5"> + <any data="false" xml:lang="nb"> + <chi xml:lang="no" xml:id="id6"/> + <gamma xml:lang="no" xml:id="id7"/> + <any object="this-is-att-value"/> + <lambda xml:lang="nb"> + <gamma xml:lang="en" xml:id="id8"> + <green>This text must be green</green> + </gamma> + </lambda> + </any> + </kappa> + </sigma> + </kappa> + </tau> + </epsilon> + </tree> + </test> + <test> + <xpath>//iota[contains(@or,"node")][@xml:lang="en-US"]/epsilon[@false][not(following-sibling::*)]/chi[starts-with(concat(@abort,"-"),"false-")][not(preceding-sibling::*)][not(following-sibling::*)]/phi[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::rho[starts-with(@desciption,"attribute ")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::pi[not(child::node())][following-sibling::phi[@number]/iota[@delete][not(preceding-sibling::*)]/gamma[starts-with(concat(@insert,"-"),"this.nodeValue-")][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:id="id2"]/chi[contains(concat(@name,"$"),"ontent$")][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[contains(concat(@class,"$"),"e value$")][@xml:id="id3"]//beta[@true="attribute"][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/eta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <iota or="this.nodeValue" xml:lang="en-US"> + <epsilon false="another attribute value"> + <chi abort="false"> + <phi/> + <rho desciption="attribute value" xml:lang="en-US"/> + <pi/> + <phi number="another attribute value"> + <iota delete="attribute"> + <gamma insert="this.nodeValue" xml:lang="nb" xml:id="id1"/> + <kappa xml:id="id2"> + <chi name="content" xml:lang="no"/> + <xi class="attribute value" xml:id="id3"> + <beta true="attribute" xml:lang="en" xml:id="id4"> + <eta xml:lang="en-GB"/> + <omicron> + <green>This text must be green</green> + </omicron> + </beta> + </xi> + </kappa> + </iota> + </phi> + </chi> + </epsilon> + </iota> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en-GB"]/kappa[contains(@abort,"alue")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[starts-with(concat(@attribute,"-"),"attribute value-")][not(child::node())][following-sibling::theta[@string="attribute value"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="en-GB"][not(following-sibling::*)]//psi[not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@xml:id="id4"][following-sibling::eta[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//nu[contains(concat(@att,"$"),"e$")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="no"][@xml:id="id6"]/gamma[@xml:id="id7"][not(preceding-sibling::*)]/rho[@or][@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[preceding-sibling::*[position() = 1]]/lambda[not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@content="attribute"][@xml:id="id9"][not(following-sibling::*)]//rho[starts-with(@string,"attribute value")][@xml:lang="no"][not(following-sibling::*)][not(following-sibling::rho)]/psi[@attrib][@xml:lang="no-nb"][@xml:id="id10"][not(child::node())][following-sibling::zeta[@delete="this-is-att-value"][@xml:lang="en-GB"][not(child::node())][following-sibling::omega[starts-with(@src,"attribute va")][@xml:id="id11"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="en-GB"> + <kappa abort="another attribute value" xml:id="id1"> + <sigma attribute="attribute value"/> + <theta string="attribute value" xml:id="id2"> + <omicron xml:lang="no-nb" xml:id="id3"/> + <lambda xml:lang="en-GB"> + <psi> + <alpha xml:id="id4"/> + <eta xml:lang="no-nb" xml:id="id5"> + <nu att="true" xml:lang="no-nb"/> + <omicron xml:lang="no" xml:id="id6"> + <gamma xml:id="id7"> + <rho or="attribute" xml:lang="en" xml:id="id8"/> + <phi> + <lambda> + <sigma content="attribute" xml:id="id9"> + <rho string="attribute value" xml:lang="no"> + <psi attrib="this.nodeValue" xml:lang="no-nb" xml:id="id10"/> + <zeta delete="this-is-att-value" xml:lang="en-GB"/> + <omega src="attribute value" xml:id="id11"> + <green>This text must be green</green> + </omega> + </rho> + </sigma> + </lambda> + </phi> + </gamma> + </omicron> + </eta> + </psi> + </lambda> + </theta> + </kappa> + </iota> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="en"]/*[@xml:lang="en-GB"][not(following-sibling::*)]/*[contains(concat(@string,"$"),"false$")][@xml:lang="en"][not(preceding-sibling::*)]/omega[@att="this.nodeValue"][following-sibling::*[position()=1]][following-sibling::delta[starts-with(@attrib,"tr")][@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[@xml:lang="no"][not(preceding-sibling::*)]//tau[contains(concat(@name,"$"),"ue$")][@xml:id="id2"][not(preceding-sibling::*)]/rho[@or][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[not(preceding-sibling::*)][following-sibling::theta[@attr][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[starts-with(concat(@class,"-"),"solid 1px green-")][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[not(following-sibling::*)]//*[starts-with(@data,"10")][@xml:lang="nb"][not(following-sibling::*)]/kappa[@title="100%"][following-sibling::alpha[starts-with(concat(@delete,"-"),"this.nodeValue-")][@xml:id="id3"][following-sibling::alpha[@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::mu[@insert][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//lambda[@delete="another attribute value"][@xml:lang="en-GB"][following-sibling::zeta[starts-with(@or,"attrib")][@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="en"> + <any xml:lang="en-GB"> + <any string="false" xml:lang="en"> + <omega att="this.nodeValue"/> + <delta attrib="true" xml:lang="en-GB" xml:id="id1"> + <pi xml:lang="no"> + <tau name="this-is-att-value" xml:id="id2"> + <rho or="attribute" xml:lang="en"> + <alpha/> + <theta attr="solid 1px green" xml:lang="en-GB"> + <any class="solid 1px green"/> + <kappa> + <any data="100%" xml:lang="nb"> + <kappa title="100%"/> + <alpha delete="this.nodeValue" xml:id="id3"/> + <alpha xml:lang="en-GB"/> + <mu insert="_blank" xml:lang="en-GB" xml:id="id4"> + <lambda delete="another attribute value" xml:lang="en-GB"/> + <zeta or="attribute value" xml:lang="no-nb" xml:id="id5"/> + <psi> + <green>This text must be green</green> + </psi> + </mu> + </any> + </kappa> + </theta> + </rho> + </tau> + </pi> + </delta> + </any> + </any> + </psi> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//iota[@xml:lang="en"][not(child::node())][following-sibling::gamma[@object][@xml:id="id2"][following-sibling::beta[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//theta[@name="attribute value"][@xml:id="id4"][following-sibling::delta[@name][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu/iota[@insert][@xml:lang="no-nb"][@xml:id="id6"][not(following-sibling::*)]//mu[contains(@data,"t-v")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//theta[not(preceding-sibling::*)][following-sibling::epsilon[contains(concat(@desciption,"$"),"value$")][following-sibling::zeta//psi[not(child::node())][following-sibling::zeta[contains(concat(@desciption,"$"),"ute value$")][@xml:lang="no"]/iota[@xml:lang="en-US"][@xml:id="id7"][not(following-sibling::*)]//lambda[contains(concat(@insert,"$"),"r attribute value$")][not(preceding-sibling::*)]//iota[@title][@xml:lang="no-nb"][@xml:id="id8"][not(preceding-sibling::*)]/gamma[@name][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][following-sibling::alpha[not(following-sibling::*)]//chi[@number="solid 1px green"][@xml:lang="nb"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <iota xml:lang="en"/> + <gamma object="true" xml:id="id2"/> + <beta xml:lang="no" xml:id="id3"> + <theta name="attribute value" xml:id="id4"/> + <delta name="123456789" xml:lang="no-nb" xml:id="id5"> + <nu> + <iota insert="attribute" xml:lang="no-nb" xml:id="id6"> + <mu data="this-is-att-value" xml:lang="en"/> + <gamma/> + <alpha xml:lang="en-US"> + <theta/> + <epsilon desciption="this-is-att-value"/> + <zeta> + <psi/> + <zeta desciption="attribute value" xml:lang="no"> + <iota xml:lang="en-US" xml:id="id7"> + <lambda insert="another attribute value"> + <iota title="_blank" xml:lang="no-nb" xml:id="id8"> + <gamma name="_blank" xml:lang="en-US"/> + <epsilon xml:lang="en-GB"/> + <alpha> + <chi number="solid 1px green" xml:lang="nb"> + <green>This text must be green</green> + </chi> + </alpha> + </iota> + </lambda> + </iota> + </zeta> + </zeta> + </alpha> + </iota> + </nu> + </delta> + </beta> + </chi> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]/eta[contains(@or,"d 1px ")][@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::theta[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::psi[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::xi[starts-with(@data,"tr")][@xml:id="id5"][following-sibling::omega[@attribute][@xml:id="id6"][following-sibling::lambda[@xml:lang="no"][preceding-sibling::*[position() = 5]][not(following-sibling::*)]/eta[@xml:lang="en-US"]//delta[@xml:lang="en-GB"][following-sibling::alpha[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[@attribute][not(preceding-sibling::*)][not(following-sibling::*)]/theta[following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[starts-with(concat(@false,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:id="id8"]/xi[not(preceding-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <eta or="solid 1px green" xml:lang="en-US" xml:id="id2"/> + <theta xml:lang="en-GB" xml:id="id3"/> + <psi xml:lang="no-nb" xml:id="id4"/> + <xi data="true" xml:id="id5"/> + <omega attribute="false" xml:id="id6"/> + <lambda xml:lang="no"> + <eta xml:lang="en-US"> + <delta xml:lang="en-GB"/> + <alpha> + <lambda attribute="attribute-value"> + <theta/> + <eta false="attribute" xml:lang="en-US" xml:id="id7"/> + <omega xml:id="id8"> + <xi> + <green>This text must be green</green> + </xi> + </omega> + </lambda> + </alpha> + </eta> + </lambda> + </chi> + </tree> + </test> + <test> + <xpath>//mu[@object][@xml:lang="en"]/*[@attrib][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::chi[@src="false"][following-sibling::sigma[following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 3]][not(following-sibling::*)]//omega[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 1]][following-sibling::eta[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <mu object="this.nodeValue" xml:lang="en"> + <any attrib="123456789"> + <kappa/> + <chi src="false"/> + <sigma/> + <lambda> + <omega xml:lang="no" xml:id="id1"/> + <psi/> + <eta xml:lang="en" xml:id="id2"> + <green>This text must be green</green> + </eta> + </lambda> + </any> + </mu> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en"]/lambda[contains(@and,"deValue")][following-sibling::psi[@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omega[@xml:lang="nb"][following-sibling::iota[@xml:lang="en"][preceding-sibling::*[position() = 1]]/pi[starts-with(@name,"attribu")][not(child::node())][following-sibling::*[@xml:lang="en-US"][not(child::node())][following-sibling::epsilon[not(preceding-sibling::epsilon or following-sibling::epsilon)][not(child::node())][following-sibling::gamma[@string="solid 1px green"][@xml:id="id2"][not(following-sibling::*)]/phi[starts-with(@true,"this.nod")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//omicron[@or][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@xml:lang="no"][@xml:id="id5"][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en"> + <lambda and="this.nodeValue"/> + <psi xml:id="id1"> + <omega xml:lang="nb"/> + <iota xml:lang="en"> + <pi name="attribute value"/> + <any xml:lang="en-US"/> + <epsilon/> + <gamma string="solid 1px green" xml:id="id2"> + <phi true="this.nodeValue" xml:lang="en" xml:id="id3"> + <omicron or="100%" xml:lang="no" xml:id="id4"> + <mu xml:lang="no" xml:id="id5"> + <green>This text must be green</green> + </mu> + </omicron> + </phi> + </gamma> + </iota> + </psi> + </omega> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no-nb"]//epsilon[contains(concat(@and,"$"),"x green$")][@xml:lang="no-nb"][not(preceding-sibling::*)]//omega[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[starts-with(concat(@class,"-"),"another attribute value-")][not(following-sibling::*)]/tau[contains(concat(@name,"$"),"r attribute value$")][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="nb"][not(following-sibling::*)]//chi[position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no-nb"> + <epsilon and="solid 1px green" xml:lang="no-nb"> + <omega xml:lang="en-GB"/> + <lambda class="another attribute value"> + <tau name="another attribute value"/> + <beta xml:lang="nb"> + <chi> + <green>This text must be green</green> + </chi> + </beta> + </lambda> + </epsilon> + </epsilon> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//psi[@insert="123456789"][not(preceding-sibling::*)][following-sibling::theta[@xml:id="id2"]//delta[starts-with(concat(@token,"-"),"attribute-")][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[starts-with(@attr,"fal")][not(preceding-sibling::*)]/psi/rho[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="no-nb"]/beta[starts-with(concat(@true,"-"),"content-")][@xml:lang="en-US"][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@name][@xml:lang="en"]//theta[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[starts-with(@false,"attr")][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::eta[contains(concat(@and,"$"),"value$")][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::alpha[@data][not(following-sibling::*)]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <psi insert="123456789"/> + <theta xml:id="id2"> + <delta token="attribute"> + <alpha attr="false"> + <psi> + <rho xml:lang="no" xml:id="id3"> + <pi xml:id="id4"/> + <upsilon xml:lang="no-nb"> + <beta true="content" xml:lang="en-US" xml:id="id5"/> + <sigma> + <omicron xml:id="id6"/> + <omicron name="_blank" xml:lang="en"> + <theta and="this.nodeValue" xml:lang="no" xml:id="id7"/> + <chi false="attribute" xml:id="id8"/> + <eta and="attribute-value"/> + <alpha data="100%"> + <green>This text must be green</green> + </alpha> + </omicron> + </sigma> + </upsilon> + </rho> + </psi> + </alpha> + </delta> + </theta> + </chi> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="en"]/alpha[@number][@xml:id="id1"][following-sibling::beta[contains(concat(@att,"$"),"23456789$")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]//*[@xml:id="id3"][not(preceding-sibling::*)][not(preceding-sibling::any)][not(child::node())][following-sibling::*[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[not(preceding-sibling::*)][not(preceding-sibling::nu)][not(child::node())][following-sibling::iota[not(child::node())][following-sibling::rho[@xml:id="id5"][following-sibling::gamma[@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/kappa[@class="attribute-value"][@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)]/gamma[@xml:id="id8"][following-sibling::pi[starts-with(@name,"t")][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@name][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 2]]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="en"> + <alpha number="true" xml:id="id1"/> + <beta att="123456789" xml:lang="nb" xml:id="id2"> + <any xml:id="id3"/> + <any xml:id="id4"> + <nu/> + <iota/> + <rho xml:id="id5"/> + <gamma xml:lang="no-nb" xml:id="id6"> + <kappa class="attribute-value" xml:lang="en-GB" xml:id="id7"> + <gamma xml:id="id8"/> + <pi name="this-is-att-value" xml:id="id9"/> + <rho name="_blank" xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </rho> + </kappa> + </gamma> + </any> + </beta> + </lambda> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no"]//delta[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[@xml:id="id1"][preceding-sibling::*[position() = 1]]//lambda[@number="attribute-value"][following-sibling::*[position()=3]][following-sibling::tau[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[@data][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 3]]/psi[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[starts-with(concat(@class,"-"),"solid 1px green-")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::iota[@attribute][@xml:id="id6"][not(child::node())][following-sibling::pi[@xml:lang="en-GB"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no"> + <delta/> + <omicron xml:id="id1"> + <lambda number="attribute-value"/> + <tau xml:lang="en" xml:id="id2"/> + <any data="content" xml:id="id3"/> + <upsilon xml:lang="en-US" xml:id="id4"> + <psi xml:lang="no"/> + <tau class="solid 1px green" xml:id="id5"> + <mu content="attribute" xml:lang="en-GB"/> + <iota attribute="this.nodeValue" xml:id="id6"/> + <pi xml:lang="en-GB"> + <green>This text must be green</green> + </pi> + </tau> + </upsilon> + </omicron> + </beta> + </tree> + </test> + <test> + <xpath>//pi[contains(concat(@false,"$"),"56789$")][@xml:lang="en-US"][@xml:id="id1"]//epsilon[starts-with(@number,"_blank")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::xi[@xml:id="id2"][following-sibling::alpha[@xml:id="id3"]/phi[@and][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="nb"][not(following-sibling::*)]/rho[@xml:lang="en-US"][@xml:id="id4"]/zeta[@attribute]//theta[@delete][not(preceding-sibling::*)]/theta[@insert][following-sibling::*[position()=3]][following-sibling::omicron[@object="content"][@xml:lang="en"][@xml:id="id5"][following-sibling::lambda[@xml:id="id6"][not(child::node())][following-sibling::iota[@xml:lang="en-GB"]//omicron[@attribute="solid 1px green"][@xml:id="id7"][following-sibling::iota[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]]//*[following-sibling::alpha[starts-with(@att,"_blank")][@xml:id="id9"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@src][@xml:id="id10"][preceding-sibling::*[position() = 2]]/psi[@xml:id="id11"][not(following-sibling::*)]//beta[@object][@xml:id="id12"][not(preceding-sibling::*)]//psi[@attribute][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(concat(@true,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id13"][position() = 1]][position() = 1]]]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi false="123456789" xml:lang="en-US" xml:id="id1"> + <epsilon number="_blank" xml:lang="en-US"/> + <xi xml:id="id2"/> + <alpha xml:id="id3"> + <phi and="this-is-att-value"/> + <gamma xml:lang="nb"> + <rho xml:lang="en-US" xml:id="id4"> + <zeta attribute="attribute value"> + <theta delete="100%"> + <theta insert="100%"/> + <omicron object="content" xml:lang="en" xml:id="id5"/> + <lambda xml:id="id6"/> + <iota xml:lang="en-GB"> + <omicron attribute="solid 1px green" xml:id="id7"/> + <iota xml:lang="en-US" xml:id="id8"> + <any/> + <alpha att="_blank" xml:id="id9"/> + <theta src="solid 1px green" xml:id="id10"> + <psi xml:id="id11"> + <beta object="attribute" xml:id="id12"> + <psi attribute="content"/> + <upsilon true="attribute-value" xml:lang="nb" xml:id="id13"> + <green>This text must be green</green> + </upsilon> + </beta> + </psi> + </theta> + </iota> + </iota> + </theta> + </zeta> + </rho> + </gamma> + </alpha> + </pi> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en"][@xml:id="id1"]//alpha[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="no"][following-sibling::rho[@xml:lang="en-US"][following-sibling::zeta[@xml:lang="no"][preceding-sibling::*[position() = 3]][following-sibling::pi[preceding-sibling::*[position() = 4]][not(following-sibling::*)]//zeta[@att][@xml:lang="no-nb"][not(following-sibling::*)]/rho[@delete][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::lambda[contains(@title,"rue")][@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//sigma[@delete][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@attr="solid 1px green"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[following-sibling::kappa[preceding-sibling::*[position() = 3]][not(following-sibling::*)]//omega[@and][@xml:id="id5"][not(preceding-sibling::*)]/iota[@attribute="attribute-value"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en" xml:id="id1"> + <alpha xml:lang="no-nb"/> + <iota xml:lang="no"/> + <rho xml:lang="en-US"/> + <zeta xml:lang="no"/> + <pi> + <zeta att="solid 1px green" xml:lang="no-nb"> + <rho delete="content" xml:lang="no" xml:id="id2"/> + <lambda title="true" xml:lang="en-GB" xml:id="id3"/> + <kappa xml:lang="en" xml:id="id4"> + <sigma delete="attribute value"/> + <iota attr="solid 1px green"/> + <psi/> + <kappa> + <omega and="true" xml:id="id5"> + <iota attribute="attribute-value" xml:id="id6"> + <green>This text must be green</green> + </iota> + </omega> + </kappa> + </kappa> + </zeta> + </pi> + </kappa> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]//zeta[@xml:id="id2"][not(child::node())][following-sibling::*[@xml:lang="en-US"][not(following-sibling::*)]//upsilon[not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::zeta[starts-with(concat(@true,"-"),"content-")][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]/lambda[contains(concat(@attr,"$"),"ue$")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@attr][@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::*[@number][@xml:lang="nb"][not(following-sibling::*)][not(following-sibling::any)]//omega[@insert="123456789"][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[@true][following-sibling::alpha[@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]/chi[@xml:id="id8"][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <zeta xml:id="id2"/> + <any xml:lang="en-US"> + <upsilon> + <omicron xml:lang="en-US" xml:id="id3"/> + <zeta true="content" xml:lang="nb" xml:id="id4"> + <lambda attr="another attribute value" xml:lang="en-US"/> + <mu attr="100%" xml:lang="nb" xml:id="id5"/> + <any number="_blank" xml:lang="nb"> + <omega insert="123456789" xml:lang="no" xml:id="id6"/> + <xi xml:lang="en-US"> + <beta true="attribute"/> + <alpha xml:lang="en" xml:id="id7"> + <chi xml:id="id8"> + <green>This text must be green</green> + </chi> + </alpha> + </xi> + </any> + </zeta> + </upsilon> + </any> + </xi> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no"]/zeta[@xml:lang="nb"][not(preceding-sibling::*)]//pi[starts-with(@title,"fals")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[not(preceding-sibling::psi)][not(child::node())][following-sibling::zeta[contains(@class,"bla")][@xml:id="id1"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//sigma[@attr="attribute-value"][@xml:id="id2"][following-sibling::lambda[@attrib][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[starts-with(concat(@title,"-"),"123456789-")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::eta[starts-with(concat(@data,"-"),"100%-")][@xml:id="id4"][not(child::node())][following-sibling::*[@and][@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::epsilon[@title][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::theta[@attribute="attribute value"][@xml:lang="nb"][@xml:id="id6"]//kappa[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::tau[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 2]]/delta[@src][@xml:lang="nb"][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::*[contains(concat(@number,"$"),"ute$")][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en"]/alpha[@delete][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::alpha)]][position() = 1]]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no"> + <zeta xml:lang="nb"> + <pi title="false" xml:lang="en-GB"/> + <psi/> + <zeta class="_blank" xml:id="id1"> + <sigma attr="attribute-value" xml:id="id2"/> + <lambda attrib="solid 1px green"> + <epsilon title="123456789" xml:lang="en" xml:id="id3"/> + <eta data="100%" xml:id="id4"/> + <any and="this.nodeValue" xml:lang="no-nb" xml:id="id5"/> + <epsilon title="this.nodeValue"/> + <theta attribute="attribute value" xml:lang="nb" xml:id="id6"> + <kappa xml:lang="en-GB" xml:id="id7"/> + <lambda xml:lang="en-US" xml:id="id8"/> + <tau xml:lang="nb" xml:id="id9"> + <delta src="attribute" xml:lang="nb"/> + <iota/> + <any number="attribute" xml:lang="en-US" xml:id="id10"/> + <lambda xml:lang="en"> + <alpha delete="solid 1px green"> + <green>This text must be green</green> + </alpha> + </lambda> + </tau> + </theta> + </lambda> + </zeta> + </zeta> + </psi> + </tree> + </test> + <test> + <xpath>//psi//*[not(preceding-sibling::*)][not(preceding-sibling::any)][following-sibling::omega[@xml:lang="nb"][@xml:id="id1"]//omega[starts-with(concat(@and,"-"),"content-")][@xml:lang="nb"][@xml:id="id2"][following-sibling::tau[@xml:lang="en"][@xml:id="id3"][following-sibling::delta[contains(@true,"ue")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//gamma[@object="attribute value"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::eta[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::kappa[preceding-sibling::*[position() = 5]][not(following-sibling::*)]/zeta[@xml:lang="en-GB"][@xml:id="id6"][following-sibling::psi[contains(concat(@att,"$"),"se$")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="en-US"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::pi[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 3]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <psi> + <any/> + <omega xml:lang="nb" xml:id="id1"> + <omega and="content" xml:lang="nb" xml:id="id2"/> + <tau xml:lang="en" xml:id="id3"/> + <delta true="this-is-att-value" xml:lang="nb"> + <gamma object="attribute value"/> + <mu xml:id="id4"/> + <eta/> + <omega xml:lang="en-GB" xml:id="id5"/> + <gamma/> + <kappa> + <zeta xml:lang="en-GB" xml:id="id6"/> + <psi att="false" xml:lang="no"/> + <delta xml:lang="en-US" xml:id="id7"/> + <pi xml:lang="en-US" xml:id="id8"> + <green>This text must be green</green> + </pi> + </kappa> + </delta> + </omega> + </psi> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="nb"]//upsilon[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[starts-with(concat(@title,"-"),"this-")][@xml:lang="en"][@xml:id="id1"][not(following-sibling::*)]//upsilon[starts-with(@name,"this-is-att-val")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[starts-with(concat(@number,"-"),"false-")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//alpha[@xml:lang="en"][not(child::node())][following-sibling::tau[starts-with(concat(@token,"-"),"solid 1px green-")][@xml:lang="nb"]//omicron[following-sibling::psi[@number][@xml:lang="en-GB"]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>1</nth> + </result> + <tree> + <any xml:lang="nb"> + <upsilon xml:lang="en-GB"> + <mu title="this-is-att-value" xml:lang="en" xml:id="id1"> + <upsilon name="this-is-att-value" xml:id="id2"/> + <nu number="false" xml:lang="en" xml:id="id3"> + <alpha xml:lang="en"/> + <tau token="solid 1px green" xml:lang="nb"> + <omicron/> + <psi number="content" xml:lang="en-GB"> + <green>This text must be green</green> + </psi> + </tau> + </nu> + </mu> + </upsilon> + </any> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="en-GB"]/sigma[@delete="this.nodeValue"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@src][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[contains(@title,"true")]/omega[@xml:lang="en"][not(following-sibling::*)]//zeta[@content="100%"][@xml:id="id2"][not(preceding-sibling::*)]/iota[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="no-nb"][not(following-sibling::*)]/upsilon[contains(concat(@false,"$"),"ent$")][not(following-sibling::*)][not(preceding-sibling::upsilon)]/*[@true][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="en-GB"> + <sigma delete="this.nodeValue"> + <rho src="true" xml:lang="en-US" xml:id="id1"/> + <any title="true"> + <omega xml:lang="en"> + <zeta content="100%" xml:id="id2"> + <iota xml:lang="no-nb" xml:id="id3"> + <zeta xml:lang="no-nb"> + <upsilon false="content"> + <any true="123456789" xml:id="id4"/> + <epsilon xml:id="id5"> + <green>This text must be green</green> + </epsilon> + </upsilon> + </zeta> + </iota> + </zeta> + </omega> + </any> + </sigma> + </zeta> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="no-nb"][@xml:id="id1"]/*[starts-with(concat(@abort,"-"),"content-")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omega[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::omega)]//iota[@xml:id="id4"][following-sibling::*[position()=4]][following-sibling::upsilon[@string][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::delta[following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[starts-with(concat(@src,"-"),"solid 1px green-")][following-sibling::mu[@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/nu[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[starts-with(concat(@attribute,"-"),"another attribute value-")][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::xi[@abort][@xml:lang="en"][preceding-sibling::*[position() = 1]]/sigma[@true][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::zeta[@title][@xml:lang="nb"][@xml:id="id8"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@xml:lang="nb"][@xml:id="id9"][not(following-sibling::*)]//alpha[contains(@attrib,"olid")][@xml:id="id10"][not(preceding-sibling::*)][not(preceding-sibling::alpha)][not(child::node())][following-sibling::tau[not(following-sibling::*)]/omicron[@content][@xml:lang="en-GB"]//phi[starts-with(@class,"_blan")][@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@string][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="no-nb" xml:id="id1"> + <any abort="content" xml:lang="en" xml:id="id2"/> + <omega xml:id="id3"> + <iota xml:id="id4"/> + <upsilon string="another attribute value" xml:lang="en-GB" xml:id="id5"/> + <delta/> + <omega src="solid 1px green"/> + <mu xml:lang="no-nb" xml:id="id6"> + <nu xml:id="id7"> + <delta/> + <theta xml:lang="en-US"> + <theta attribute="another attribute value" xml:lang="en"/> + <xi abort="attribute" xml:lang="en"> + <sigma true="123456789" xml:lang="nb"/> + <zeta title="_blank" xml:lang="nb" xml:id="id8"/> + <beta xml:lang="nb" xml:id="id9"> + <alpha attrib="solid 1px green" xml:id="id10"/> + <tau> + <omicron content="attribute value" xml:lang="en-GB"> + <phi class="_blank" xml:lang="no" xml:id="id11"> + <upsilon string="this-is-att-value"> + <green>This text must be green</green> + </upsilon> + </phi> + </omicron> + </tau> + </beta> + </xi> + </theta> + </nu> + </mu> + </omega> + </eta> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(@string,"tr")][@xml:lang="en-US"][@xml:id="id1"]/eta[not(following-sibling::*)]/alpha[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::beta[@xml:id="id2"][not(following-sibling::*)]//lambda[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[contains(@true,"l")][@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <lambda string="true" xml:lang="en-US" xml:id="id1"> + <eta> + <alpha xml:lang="no-nb"/> + <beta xml:id="id2"> + <lambda xml:lang="en-US"> + <rho true="_blank" xml:lang="nb" xml:id="id3"> + <green>This text must be green</green> + </rho> + </lambda> + </beta> + </eta> + </lambda> + </tree> + </test> + <test> + <xpath>//delta[@delete][@xml:lang="no-nb"]//alpha[@xml:id="id1"]//psi[@xml:id="id2"][not(following-sibling::*)]//delta[starts-with(@desciption,"this-is-att-valu")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::tau[contains(concat(@number,"$"),"ttribute$")][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::rho[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::phi[@class][preceding-sibling::*[position() = 3]][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>1</nth> + </result> + <tree> + <delta delete="this.nodeValue" xml:lang="no-nb"> + <alpha xml:id="id1"> + <psi xml:id="id2"> + <delta desciption="this-is-att-value" xml:lang="en-GB"/> + <tau number="attribute" xml:id="id3"/> + <rho xml:lang="no" xml:id="id4"/> + <phi class="content"> + <green>This text must be green</green> + </phi> + </psi> + </alpha> + </delta> + </tree> + </test> + <test> + <xpath>//chi[contains(concat(@string,"$"),"23456789$")]//phi[@xml:lang="en-US"][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//omicron[starts-with(concat(@false,"-"),"_blank-")][@xml:id="id3"][following-sibling::pi[@token="123456789"][@xml:lang="en"][not(child::node())][following-sibling::lambda[@attribute][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::omega[contains(concat(@or,"$"),"false$")][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::chi[@xml:id="id6"]//epsilon[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(@and,"true")][@xml:lang="en"][preceding-sibling::*[position() = 1]]//kappa[@xml:id="id8"][not(preceding-sibling::*)]/mu[@attrib][not(preceding-sibling::*)]/mu[@class][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[starts-with(concat(@number,"-"),"100%-")][not(following-sibling::*)][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <chi string="123456789"> + <phi xml:lang="en-US" xml:id="id1"/> + <lambda xml:lang="en-US" xml:id="id2"> + <omicron false="_blank" xml:id="id3"/> + <pi token="123456789" xml:lang="en"/> + <lambda attribute="attribute-value" xml:id="id4"/> + <omega or="false" xml:id="id5"/> + <chi xml:id="id6"> + <epsilon xml:lang="no" xml:id="id7"/> + <delta and="true" xml:lang="en"> + <kappa xml:id="id8"> + <mu attrib="100%"> + <mu class="attribute-value" xml:id="id9"> + <nu number="100%"> + <green>This text must be green</green> + </nu> + </mu> + </mu> + </kappa> + </delta> + </chi> + </lambda> + </chi> + </tree> + </test> + <test> + <xpath>//alpha//rho[@xml:id="id1"][not(preceding-sibling::*)]//xi[@xml:id="id2"]//zeta[@xml:lang="en-US"][@xml:id="id3"][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omega[not(preceding-sibling::*)]/pi[@xml:id="id6"]//omicron[@xml:lang="no-nb"]//psi[@abort="this-is-att-value"][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::gamma[contains(concat(@class,"$"),"%$")][@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[contains(concat(@title,"$"),"123456789$")][@xml:id="id9"]/gamma[@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <alpha> + <rho xml:id="id1"> + <xi xml:id="id2"> + <zeta xml:lang="en-US" xml:id="id3"/> + <alpha xml:lang="en-GB" xml:id="id4"/> + <pi xml:id="id5"> + <omega> + <pi xml:id="id6"> + <omicron xml:lang="no-nb"> + <psi abort="this-is-att-value" xml:lang="nb" xml:id="id7"/> + <gamma class="100%" xml:lang="en-GB" xml:id="id8"/> + <iota title="123456789" xml:id="id9"> + <gamma xml:lang="en" xml:id="id10"/> + <gamma xml:lang="en-US"> + <green>This text must be green</green> + </gamma> + </iota> + </omicron> + </pi> + </omega> + </pi> + </xi> + </rho> + </alpha> + </tree> + </test> + <test> + <xpath>//rho//tau[starts-with(@content,"s")]//*[@xml:id="id1"][not(preceding-sibling::*)]//epsilon[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[contains(concat(@true,"$"),"k$")][@xml:lang="no"][@xml:id="id2"]//eta[@xml:lang="en-GB"][not(preceding-sibling::*)]/xi[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/zeta[@content][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::omicron[contains(concat(@true,"$"),"ue$")][@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 2]][following-sibling::gamma[contains(concat(@attribute,"$"),"alue$")][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[@att="solid 1px green"][@xml:id="id5"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::nu[@xml:id="id6"][not(following-sibling::*)]/beta[starts-with(concat(@delete,"-"),"this.nodeValue-")][@xml:lang="en-US"][@xml:id="id7"]/delta[@delete][@xml:id="id8"][not(preceding-sibling::delta)][following-sibling::nu[not(child::node())][following-sibling::sigma[@xml:lang="en-US"][following-sibling::theta[contains(concat(@string,"$"),"e$")][@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::beta[not(following-sibling::*)]/zeta[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <tau content="solid 1px green"> + <any xml:id="id1"> + <epsilon/> + <gamma true="_blank" xml:lang="no" xml:id="id2"> + <eta xml:lang="en-GB"> + <xi xml:lang="en-US" xml:id="id3"> + <zeta content="this.nodeValue" xml:lang="no-nb"/> + <omicron true="true" xml:lang="nb" xml:id="id4"/> + <tau/> + <gamma attribute="attribute-value"/> + <theta att="solid 1px green" xml:id="id5"/> + <nu xml:id="id6"> + <beta delete="this.nodeValue" xml:lang="en-US" xml:id="id7"> + <delta delete="_blank" xml:id="id8"/> + <nu/> + <sigma xml:lang="en-US"/> + <theta string="true" xml:lang="nb"/> + <beta> + <zeta xml:lang="nb"> + <zeta xml:id="id9"/> + <beta xml:lang="en"> + <green>This text must be green</green> + </beta> + </zeta> + </beta> + </beta> + </nu> + </xi> + </eta> + </gamma> + </any> + </tau> + </rho> + </tree> + </test> + <test> + <xpath>//eta[@xml:id="id1"]//sigma[@insert="this-is-att-value"][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:lang="no"][following-sibling::gamma[@xml:lang="no"][@xml:id="id2"][following-sibling::mu//iota/beta[@true="_blank"][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::sigma[@or][preceding-sibling::*[position() = 1]][following-sibling::xi[not(following-sibling::*)]//nu[@false][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@string="content"][@xml:lang="en-GB"]/zeta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id5"][preceding-sibling::*[position() = 1]]/nu[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[contains(@class,"co")][not(preceding-sibling::*)][not(preceding-sibling::nu)][not(child::node())][following-sibling::beta[@xml:id="id7"][following-sibling::iota[contains(@and,"ribute")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]/omicron[@attrib="solid 1px green"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@title][@xml:lang="nb"][preceding-sibling::*[position() = 1]]//zeta[following-sibling::pi[@token="100%"][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[contains(concat(@and,"$"),"tent$")][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@desciption][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[contains(concat(@delete,"$"),"ue$")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:id="id1"> + <sigma insert="this-is-att-value" xml:lang="nb"> + <upsilon xml:lang="no"/> + <gamma xml:lang="no" xml:id="id2"/> + <mu> + <iota> + <beta true="_blank" xml:lang="no" xml:id="id3"/> + <sigma or="false"/> + <xi> + <nu false="another attribute value" xml:lang="nb" xml:id="id4"> + <psi string="content" xml:lang="en-GB"> + <zeta xml:lang="en-GB"/> + <delta xml:id="id5"> + <nu xml:id="id6"> + <nu class="content"/> + <beta xml:id="id7"/> + <iota and="attribute" xml:lang="nb"> + <omicron attrib="solid 1px green"/> + <phi title="false" xml:lang="nb"> + <zeta/> + <pi token="100%" xml:lang="en"> + <iota and="content"/> + <any desciption="solid 1px green" xml:lang="en"/> + <delta delete="true" xml:lang="nb"> + <green>This text must be green</green> + </delta> + </pi> + </phi> + </iota> + </nu> + </delta> + </psi> + </nu> + </xi> + </iota> + </mu> + </sigma> + </eta> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//xi[starts-with(concat(@object,"-"),"true-")][@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::tau[contains(@content,"k")][preceding-sibling::*[position() = 1]][following-sibling::chi[not(following-sibling::*)]//upsilon[@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::epsilon[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[starts-with(@string,"this-is-a")][@xml:id="id4"][not(child::node())][following-sibling::psi[contains(@object,"value")][@xml:lang="nb"][not(following-sibling::*)]/zeta[not(child::node())][following-sibling::omicron[contains(concat(@insert,"$"),"tent$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <xi object="true" xml:lang="en-US" xml:id="id2"/> + <tau content="_blank"/> + <chi> + <upsilon xml:lang="en" xml:id="id3"/> + <epsilon xml:lang="no"> + <sigma string="this-is-att-value" xml:id="id4"/> + <psi object="attribute value" xml:lang="nb"> + <zeta/> + <omicron insert="content" xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </psi> + </epsilon> + </chi> + </psi> + </tree> + </test> + <test> + <xpath>//omega/tau[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]]/nu[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[contains(concat(@src,"$"),"9$")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::eta[@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]//rho[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@attribute="this.nodeValue"][@xml:lang="nb"][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <tau xml:lang="no"/> + <beta xml:lang="nb" xml:id="id1"> + <nu xml:lang="no-nb"> + <eta src="123456789" xml:lang="no" xml:id="id2"> + <phi xml:lang="en"/> + <eta xml:lang="nb" xml:id="id3"> + <rho xml:id="id4"> + <psi attribute="this.nodeValue" xml:lang="nb"> + <green>This text must be green</green> + </psi> + </rho> + </eta> + </eta> + </nu> + </beta> + </omega> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//alpha[@xml:lang="en-GB"]//gamma[@xml:lang="no-nb"][not(following-sibling::*)]/sigma[starts-with(@object,"solid 1px gr")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[contains(concat(@attrib,"$"),"Value$")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(concat(@attribute,"$"),"false$")][@xml:id="id3"]//*[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]//beta[not(preceding-sibling::*)][following-sibling::phi[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@xml:lang="nb"][preceding-sibling::*[position() = 2]][following-sibling::xi[@class="100%"][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(preceding-sibling::xi)]//*[@xml:lang="en"][not(following-sibling::*)][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <alpha xml:lang="en-GB"> + <gamma xml:lang="no-nb"> + <sigma object="solid 1px green" xml:lang="en"/> + <epsilon> + <lambda attrib="this.nodeValue" xml:id="id2"/> + <delta attribute="false" xml:id="id3"> + <any xml:lang="no" xml:id="id4"> + <beta/> + <phi xml:lang="en" xml:id="id5"/> + <kappa xml:lang="nb"/> + <xi class="100%" xml:lang="en-US" xml:id="id6"> + <any xml:lang="en"> + <green>This text must be green</green> + </any> + </xi> + </any> + </delta> + </epsilon> + </gamma> + </alpha> + </psi> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/kappa[@xml:id="id2"]/phi[starts-with(concat(@token,"-"),"123456789-")][@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)]//omega[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@abort][not(following-sibling::*)]//*[@name][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(concat(@attr,"-"),"attribute value-")][not(following-sibling::*)]//rho[contains(@title,"0%")][@xml:lang="no"][following-sibling::phi[starts-with(@attr,"100%")][@xml:lang="nb"][following-sibling::beta/omicron[@xml:id="id5"][not(preceding-sibling::*)]/omega[contains(concat(@class,"$"),"true$")][@xml:id="id6"]//lambda[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::pi[starts-with(concat(@delete,"-"),"solid 1px green-")][@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::gamma[@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[@xml:lang="en"][following-sibling::kappa[contains(@desciption,"bl")]/alpha[starts-with(concat(@title,"-"),"attribute-")][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[@true="_blank"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(following-sibling::phi)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <kappa xml:id="id2"> + <phi token="123456789" xml:lang="en-GB" xml:id="id3"> + <omega xml:id="id4"/> + <epsilon abort="true"> + <any name="100%" xml:lang="en-US"/> + <kappa attr="attribute value"> + <rho title="100%" xml:lang="no"/> + <phi attr="100%" xml:lang="nb"/> + <beta> + <omicron xml:id="id5"> + <omega class="true" xml:id="id6"> + <lambda xml:lang="en-US" xml:id="id7"/> + <pi delete="solid 1px green" xml:lang="en-US" xml:id="id8"/> + <gamma xml:lang="en-GB" xml:id="id9"/> + <kappa xml:lang="en"/> + <kappa desciption="_blank"> + <alpha title="attribute" xml:id="id10"/> + <phi true="_blank"> + <green>This text must be green</green> + </phi> + </kappa> + </omega> + </omicron> + </beta> + </kappa> + </epsilon> + </phi> + </kappa> + </nu> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]//zeta[following-sibling::omega[not(following-sibling::*)]/eta[starts-with(concat(@data,"-"),"true-")][not(child::node())][following-sibling::theta[@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::gamma[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::delta[not(child::node())][following-sibling::psi[starts-with(concat(@or,"-"),"attribute value-")][@xml:lang="en-US"][preceding-sibling::*[position() = 4]]//sigma[@xml:id="id4"][not(child::node())][following-sibling::kappa[@insert][@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::mu[@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="no-nb"]//chi[not(preceding-sibling::*)]//sigma[starts-with(concat(@insert,"-"),"solid 1px green-")][@xml:lang="no"][following-sibling::eta[@or][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[contains(@false,"rue")][@xml:id="id8"][following-sibling::tau[starts-with(@or,"solid 1px ")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][not(following-sibling::*)]/iota[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="no"][@xml:id="id9"][not(following-sibling::*)][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:id="id1"> + <zeta/> + <omega> + <eta data="true"/> + <theta xml:lang="no" xml:id="id2"/> + <gamma xml:id="id3"/> + <delta/> + <psi or="attribute value" xml:lang="en-US"> + <sigma xml:id="id4"/> + <kappa insert="content" xml:lang="en" xml:id="id5"/> + <mu xml:id="id6"/> + <iota xml:lang="no-nb"> + <chi> + <sigma insert="solid 1px green" xml:lang="no"/> + <eta or="_blank" xml:id="id7"> + <xi false="true" xml:id="id8"/> + <tau or="solid 1px green" xml:lang="en"/> + <kappa xml:lang="no-nb"> + <iota xml:lang="no-nb"/> + <psi xml:lang="no" xml:id="id9"> + <green>This text must be green</green> + </psi> + </kappa> + </eta> + </chi> + </iota> + </psi> + </omega> + </kappa> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@src,"$"),"e$")]/iota[@att][@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::theta[starts-with(@insert,"conte")][@xml:lang="nb"][@xml:id="id2"][following-sibling::delta[starts-with(@name,"this.nodeVa")][@xml:lang="en-US"][following-sibling::psi[starts-with(concat(@attrib,"-"),"content-")][@xml:lang="no"][following-sibling::*[position()=3]][following-sibling::epsilon[contains(concat(@insert,"$"),"ue$")][@xml:lang="no-nb"][@xml:id="id3"][not(child::node())][following-sibling::epsilon[@xml:id="id4"][not(child::node())][following-sibling::*[contains(@number,"en")][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <alpha src="true"> + <iota att="_blank" xml:lang="en" xml:id="id1"/> + <theta insert="content" xml:lang="nb" xml:id="id2"/> + <delta name="this.nodeValue" xml:lang="en-US"/> + <psi attrib="content" xml:lang="no"/> + <epsilon insert="true" xml:lang="no-nb" xml:id="id3"/> + <epsilon xml:id="id4"/> + <any number="solid 1px green"> + <green>This text must be green</green> + </any> + </alpha> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="nb"]//pi[starts-with(@data,"attribut")][@xml:id="id1"][following-sibling::omega[contains(@attribute,"ue")][@xml:lang="no-nb"][following-sibling::chi[@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 2]]/gamma[starts-with(concat(@or,"-"),"attribute value-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::phi[contains(@content,"fal")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//sigma[@xml:lang="en"]//kappa[@xml:id="id4"][following-sibling::omega[preceding-sibling::*[position() = 1]]//theta[@xml:lang="no-nb"][@xml:id="id5"][following-sibling::*[position()=3]][not(following-sibling::theta)][not(child::node())][following-sibling::epsilon[@delete][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::gamma[@abort][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::mu[@name][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//beta[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="nb"> + <pi data="attribute value" xml:id="id1"/> + <omega attribute="this-is-att-value" xml:lang="no-nb"/> + <chi xml:lang="en" xml:id="id2"> + <gamma or="attribute value"/> + <phi content="false" xml:lang="en" xml:id="id3"> + <sigma xml:lang="en"> + <kappa xml:id="id4"/> + <omega> + <theta xml:lang="no-nb" xml:id="id5"/> + <epsilon delete="false"/> + <gamma abort="attribute" xml:lang="en-US"/> + <mu name="_blank" xml:lang="en-GB" xml:id="id6"> + <beta xml:lang="en-US"> + <green>This text must be green</green> + </beta> + </mu> + </omega> + </sigma> + </phi> + </chi> + </any> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en-US"]//iota[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@delete][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@xml:lang="nb"][following-sibling::*[position()=1]][not(preceding-sibling::zeta)][not(child::node())][following-sibling::eta[@data][preceding-sibling::*[position() = 3]][not(preceding-sibling::eta)]//iota[contains(concat(@string,"$"),"content$")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::upsilon[following-sibling::*[position()=1]][following-sibling::upsilon[not(following-sibling::*)]//delta[@class="_blank"][following-sibling::*[position()=1]][following-sibling::zeta[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[contains(@token,"se")][@xml:id="id4"][not(preceding-sibling::*)]/nu[@number="another attribute value"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:id="id6"][not(following-sibling::*)]/mu[starts-with(@number,"another attribute valu")][not(following-sibling::*)]/delta[starts-with(@abort,"fal")][@xml:lang="en"][not(child::node())][following-sibling::gamma[@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>1</nth> + </result> + <tree> + <iota xml:lang="en-US"> + <iota xml:id="id1"/> + <beta delete="attribute" xml:id="id2"/> + <zeta xml:lang="nb"/> + <eta data="another attribute value"> + <iota string="content" xml:lang="en-GB"/> + <upsilon/> + <upsilon> + <delta class="_blank"/> + <zeta xml:id="id3"> + <epsilon token="false" xml:id="id4"> + <nu number="another attribute value" xml:id="id5"> + <upsilon xml:id="id6"> + <mu number="another attribute value"> + <delta abort="false" xml:lang="en"/> + <gamma xml:id="id7"> + <green>This text must be green</green> + </gamma> + </mu> + </upsilon> + </nu> + </epsilon> + </zeta> + </upsilon> + </eta> + </iota> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no-nb"][@xml:id="id1"]/sigma[@xml:lang="en-US"][not(following-sibling::*)]/xi[not(following-sibling::*)]//kappa[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/psi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@src="_blank"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::upsilon[@or][@xml:id="id4"][following-sibling::sigma[@class][@xml:id="id5"][preceding-sibling::*[position() = 2]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no-nb" xml:id="id1"> + <sigma xml:lang="en-US"> + <xi> + <kappa xml:lang="en" xml:id="id2"/> + <omicron xml:lang="en-GB" xml:id="id3"> + <psi xml:lang="no-nb"> + <iota src="_blank" xml:lang="no-nb"> + <omega xml:lang="en"/> + <upsilon or="content" xml:id="id4"/> + <sigma class="this-is-att-value" xml:id="id5"> + <green>This text must be green</green> + </sigma> + </iota> + </psi> + </omicron> + </xi> + </sigma> + </epsilon> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:id="id1"]//phi[@xml:lang="en-US"][@xml:id="id2"][following-sibling::beta[preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::zeta[starts-with(@string,"solid 1px gr")][@xml:lang="no-nb"][following-sibling::omega[contains(concat(@object,"$"),"rue$")][@xml:id="id3"][not(child::node())][following-sibling::lambda[@name][@xml:lang="no"][not(following-sibling::*)]/gamma[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@title][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//chi[@xml:lang="no-nb"][not(child::node())][following-sibling::zeta[starts-with(@or,"t")][not(child::node())][following-sibling::iota[starts-with(concat(@string,"-"),"100%-")][@xml:lang="no"][@xml:id="id7"][not(child::node())][following-sibling::mu[@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//gamma[@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]//rho[@xml:lang="no-nb"][following-sibling::lambda[@xml:lang="nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::lambda[@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 2]]/upsilon[contains(concat(@content,"$"),"solid 1px green$")][@xml:lang="nb"][not(following-sibling::*)][not(preceding-sibling::upsilon)]//psi[contains(concat(@data,"$"),"id 1px green$")][not(preceding-sibling::*)][not(following-sibling::*)]/psi[contains(@attribute,"ttribute val")][not(preceding-sibling::*)]/upsilon[@class][@xml:lang="nb"][@xml:id="id12"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::gamma[@src][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:lang="en-GB"]//*[contains(@attrib,"ank")][@xml:lang="en-GB"][not(preceding-sibling::*)]][position() = 1]]]]][position() = 1]]]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:id="id1"> + <phi xml:lang="en-US" xml:id="id2"/> + <beta/> + <zeta string="solid 1px green" xml:lang="no-nb"/> + <omega object="true" xml:id="id3"/> + <lambda name="another attribute value" xml:lang="no"> + <gamma xml:lang="en-US" xml:id="id4"/> + <sigma xml:lang="no" xml:id="id5"/> + <sigma title="attribute-value" xml:id="id6"> + <chi xml:lang="no-nb"/> + <zeta or="this-is-att-value"/> + <iota string="100%" xml:lang="no" xml:id="id7"/> + <mu xml:id="id8"> + <gamma xml:lang="en-US" xml:id="id9"> + <rho xml:lang="no-nb"/> + <lambda xml:lang="nb" xml:id="id10"/> + <lambda xml:lang="no" xml:id="id11"> + <upsilon content="solid 1px green" xml:lang="nb"> + <psi data="solid 1px green"> + <psi attribute="another attribute value"> + <upsilon class="this-is-att-value" xml:lang="nb" xml:id="id12"/> + <gamma src="attribute value"/> + <theta xml:lang="en-GB"> + <any attrib="_blank" xml:lang="en-GB"> + <green>This text must be green</green> + </any> + </theta> + </psi> + </psi> + </upsilon> + </lambda> + </gamma> + </mu> + </sigma> + </lambda> + </epsilon> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-US"]//tau[starts-with(concat(@attr,"-"),"this-")][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[contains(@class,"ute-value")][@xml:lang="en"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::psi[@xml:lang="en"][not(following-sibling::*)]//iota[@true][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@class="this.nodeValue"][@xml:lang="en"][not(following-sibling::*)]//theta[contains(concat(@attr,"$"),"100%$")][@xml:id="id3"]//rho[@xml:lang="en-US"][following-sibling::*[position()=4]][not(child::node())][following-sibling::omicron[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@false][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::phi[starts-with(@data,"attribute-value")][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[starts-with(@attr,"attribut")][@xml:lang="no"][preceding-sibling::*[position() = 4]]//nu[contains(concat(@class,"$"),"tribute-value$")][@xml:id="id6"][following-sibling::*[position()=3]][not(child::node())][following-sibling::theta[following-sibling::*[position()=2]][following-sibling::alpha[contains(@desciption,"value")][@xml:lang="en-GB"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::sigma[contains(concat(@data,"$"),"this-is-att-value$")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en-US"> + <tau attr="this-is-att-value"/> + <beta class="attribute-value" xml:lang="en" xml:id="id1"/> + <psi xml:lang="en"> + <iota true="123456789" xml:id="id2"/> + <psi class="this.nodeValue" xml:lang="en"> + <theta attr="100%" xml:id="id3"> + <rho xml:lang="en-US"/> + <omicron xml:id="id4"/> + <iota false="100%" xml:id="id5"/> + <phi data="attribute-value"/> + <psi attr="attribute" xml:lang="no"> + <nu class="attribute-value" xml:id="id6"/> + <theta/> + <alpha desciption="this-is-att-value" xml:lang="en-GB"/> + <sigma data="this-is-att-value" xml:lang="en-US" xml:id="id7"> + <green>This text must be green</green> + </sigma> + </psi> + </theta> + </psi> + </psi> + </chi> + </tree> + </test> + <test> + <xpath>//omega[@and][@xml:lang="en-GB"][@xml:id="id1"]/omega[contains(concat(@desciption,"$"),"ibute$")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[contains(concat(@object,"$"),"nother attribute value$")][@xml:id="id3"][not(preceding-sibling::*)]//epsilon[@and="123456789"][@xml:lang="en-US"][not(following-sibling::*)]//pi[contains(concat(@content,"$"),"reen$")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]//zeta[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::zeta[following-sibling::alpha[@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::nu[@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//tau[not(child::node())][following-sibling::tau[not(following-sibling::*)]/chi[starts-with(concat(@true,"-"),"123456789-")][@xml:lang="no"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <omega and="_blank" xml:lang="en-GB" xml:id="id1"> + <omega desciption="attribute" xml:lang="no-nb" xml:id="id2"> + <theta object="another attribute value" xml:id="id3"> + <epsilon and="123456789" xml:lang="en-US"> + <pi content="solid 1px green" xml:lang="en" xml:id="id4"> + <zeta xml:id="id5"/> + <zeta/> + <alpha xml:lang="no-nb"/> + <nu xml:id="id6"> + <tau/> + <tau> + <chi true="123456789" xml:lang="no"> + <green>This text must be green</green> + </chi> + </tau> + </nu> + </pi> + </epsilon> + </theta> + </omega> + </omega> + </tree> + </test> + <test> + <xpath>//iota[starts-with(@att,"content")][@xml:id="id1"]//phi[@xml:id="id2"][not(following-sibling::*)]/theta[starts-with(@class,"_")][@xml:lang="en-US"][following-sibling::iota[contains(@abort,"234")][not(child::node())][following-sibling::psi[starts-with(concat(@abort,"-"),"content-")][@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::pi[@string][@xml:lang="en-US"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(@attrib," 1px g")][preceding-sibling::*[position() = 4]]//tau[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::zeta[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omicron[not(following-sibling::*)][not(preceding-sibling::omicron)]//*[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)]//sigma[@content][not(following-sibling::*)]//phi[starts-with(@true,"123456789")][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@attr][@xml:lang="en-GB"][following-sibling::zeta[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id8"][following-sibling::zeta[contains(@attr,"e")][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 4]][position() = 1]]]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <iota att="content" xml:id="id1"> + <phi xml:id="id2"> + <theta class="_blank" xml:lang="en-US"/> + <iota abort="123456789"/> + <psi abort="content" xml:lang="en-GB" xml:id="id3"/> + <pi string="solid 1px green" xml:lang="en-US" xml:id="id4"/> + <sigma attrib="solid 1px green"> + <tau xml:id="id5"/> + <zeta xml:lang="nb"> + <omicron> + <any xml:lang="en-GB" xml:id="id6"> + <sigma content="attribute"> + <phi true="123456789" xml:lang="nb" xml:id="id7"/> + <beta attr="content" xml:lang="en-GB"/> + <zeta token="another attribute value" xml:id="id8"/> + <zeta attr="false"/> + <upsilon xml:lang="nb" xml:id="id9"> + <green>This text must be green</green> + </upsilon> + </sigma> + </any> + </omicron> + </zeta> + </sigma> + </phi> + </iota> + </tree> + </test> + <test> + <xpath>//pi[contains(@attr,"ibute va")][@xml:id="id1"]//chi[@xml:id="id2"]//phi[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)]/lambda[@xml:lang="en-GB"]/kappa[not(preceding-sibling::*)]//*[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="en-GB"][not(following-sibling::*)]//tau[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:id="id7"][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <pi attr="attribute value" xml:id="id1"> + <chi xml:id="id2"> + <phi xml:lang="nb" xml:id="id3"> + <lambda xml:lang="en-GB"> + <kappa> + <any xml:id="id4"/> + <gamma xml:id="id5"/> + <lambda xml:lang="en-GB"> + <tau xml:lang="nb" xml:id="id6"/> + <pi xml:id="id7"> + <green>This text must be green</green> + </pi> + </lambda> + </kappa> + </lambda> + </phi> + </chi> + </pi> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="en-US"][@xml:id="id1"]//beta[starts-with(concat(@insert,"-"),"content-")][@xml:lang="en-US"][following-sibling::beta[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::delta[starts-with(@src,"cont")][@xml:id="id2"]/omega[not(preceding-sibling::*)][following-sibling::eta[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::rho[not(child::node())][following-sibling::nu[starts-with(@string,"10")][preceding-sibling::*[position() = 3]][following-sibling::pi[contains(@title,"x green")][not(following-sibling::*)]/chi[starts-with(@and,"attribut")][@xml:id="id4"][not(preceding-sibling::*)]/tau[not(child::node())][following-sibling::epsilon[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::beta[starts-with(concat(@abort,"-"),"123456789-")][@xml:id="id6"]/rho[@xml:lang="en"][not(preceding-sibling::*)][position() = 1]]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="en-US" xml:id="id1"> + <beta insert="content" xml:lang="en-US"/> + <beta/> + <delta src="content" xml:id="id2"> + <omega/> + <eta xml:lang="en-US" xml:id="id3"/> + <rho/> + <nu string="100%"/> + <pi title="solid 1px green"> + <chi and="attribute-value" xml:id="id4"> + <tau/> + <epsilon xml:id="id5"/> + <beta abort="123456789" xml:id="id6"> + <rho xml:lang="en"> + <green>This text must be green</green> + </rho> + </beta> + </chi> + </pi> + </delta> + </eta> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@abort,"$"),"te$")][@xml:lang="en-GB"][@xml:id="id1"]//lambda[contains(@src,"cont")][@xml:id="id2"]//omicron[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[starts-with(@attrib,"attr")][not(preceding-sibling::*)]/theta[following-sibling::nu[@string][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[@object][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[starts-with(concat(@content,"-"),"another attribute value-")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::tau)]//pi[@and="attribute-value"][not(child::node())][following-sibling::zeta[following-sibling::*[position()=3]][following-sibling::rho[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::rho[@delete][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::gamma[contains(@data,"bute value")][@xml:lang="no"]/tau[contains(concat(@src,"$"),"lue$")][not(preceding-sibling::*)][following-sibling::alpha[@xml:id="id6"][following-sibling::upsilon[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <alpha abort="attribute" xml:lang="en-GB" xml:id="id1"> + <lambda src="content" xml:id="id2"> + <omicron xml:lang="nb"> + <tau attrib="attribute-value"> + <theta/> + <nu string="content" xml:lang="nb"> + <nu object="_blank" xml:id="id3"> + <tau content="another attribute value" xml:lang="en-US"> + <pi and="attribute-value"/> + <zeta/> + <rho xml:id="id4"/> + <rho delete="_blank" xml:lang="no-nb" xml:id="id5"/> + <gamma data="another attribute value" xml:lang="no"> + <tau src="another attribute value"/> + <alpha xml:id="id6"/> + <upsilon xml:lang="no-nb"> + <green>This text must be green</green> + </upsilon> + </gamma> + </tau> + </nu> + </nu> + </tau> + </omicron> + </lambda> + </alpha> + </tree> + </test> + <test> + <xpath>//psi[starts-with(concat(@att,"-"),"100%-")]//chi[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::alpha[preceding-sibling::*[position() = 2]]//phi[@title][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::phi[@insert][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <psi att="100%"> + <chi xml:lang="en-US"/> + <iota xml:id="id1"/> + <alpha> + <phi title="_blank" xml:id="id2"/> + <xi xml:lang="en-US"/> + <phi insert="solid 1px green"/> + <sigma xml:lang="en-GB"> + <green>This text must be green</green> + </sigma> + </alpha> + </psi> + </tree> + </test> + <test> + <xpath>//*[@insert="_blank"]/epsilon[starts-with(@data,"this.")][@xml:id="id1"]/gamma[not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::phi[contains(concat(@desciption,"$"),"0%$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::zeta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//*[@title][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@abort="another attribute value"][@xml:lang="nb"][@xml:id="id3"][not(child::node())][following-sibling::omicron[@token="attribute-value"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::rho[contains(concat(@title,"$"),"alse$")][@xml:id="id4"][preceding-sibling::*[position() = 3]]//omicron[@xml:id="id5"][not(child::node())][following-sibling::zeta[not(following-sibling::*)]//iota[@xml:lang="en-US"][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/xi[@xml:lang="en-GB"][@xml:id="id7"]//alpha[not(preceding-sibling::*)]//omicron[contains(@name,"e")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[not(following-sibling::*)]//omicron[@xml:id="id8"][not(following-sibling::*)]/alpha[not(child::node())][following-sibling::eta[starts-with(@string,"another at")][@xml:lang="en"][position() = 1]]]][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <any insert="_blank"> + <epsilon data="this.nodeValue" xml:id="id1"> + <gamma/> + <phi desciption="100%" xml:id="id2"/> + <zeta> + <any title="this-is-att-value"/> + <alpha abort="another attribute value" xml:lang="nb" xml:id="id3"/> + <omicron token="attribute-value"/> + <rho title="false" xml:id="id4"> + <omicron xml:id="id5"/> + <zeta> + <iota xml:lang="en-US"/> + <pi/> + <omega xml:lang="no" xml:id="id6"> + <xi xml:lang="en-GB" xml:id="id7"> + <alpha> + <omicron name="true"/> + <omicron> + <omicron xml:id="id8"> + <alpha/> + <eta string="another attribute value" xml:lang="en"> + <green>This text must be green</green> + </eta> + </omicron> + </omicron> + </alpha> + </xi> + </omega> + </zeta> + </rho> + </zeta> + </epsilon> + </any> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]/theta[starts-with(@desciption,"attribut")][@xml:lang="no-nb"][not(following-sibling::*)]/alpha[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::rho[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::*[starts-with(@token,"attribute-val")][@xml:lang="no-nb"][@xml:id="id4"]/lambda[starts-with(@name,"another attr")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:id="id5"]//epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[starts-with(@src,"att")][@xml:lang="no"][@xml:id="id6"][following-sibling::xi[not(following-sibling::*)]/lambda[starts-with(concat(@true,"-"),"this-")][@xml:id="id7"][not(child::node())][following-sibling::*[@xml:id="id8"][not(child::node())][following-sibling::kappa[not(child::node())][following-sibling::theta[starts-with(@abort,"at")][@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 3]]/epsilon[@false][@xml:lang="en-GB"][@xml:id="id10"][not(preceding-sibling::*)]/chi[@xml:lang="nb"][@xml:id="id11"][not(following-sibling::*)][not(preceding-sibling::chi or following-sibling::chi)]//chi[@xml:id="id12"][not(following-sibling::*)]]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>1</nth> + </result> + <tree> + <alpha xml:id="id1"> + <theta desciption="attribute" xml:lang="no-nb"> + <alpha xml:id="id2"/> + <upsilon xml:lang="en"/> + <rho xml:id="id3"/> + <any token="attribute-value" xml:lang="no-nb" xml:id="id4"> + <lambda name="another attribute value" xml:lang="en-US"/> + <phi xml:id="id5"> + <epsilon xml:lang="no-nb"> + <rho/> + <lambda src="attribute value" xml:lang="no" xml:id="id6"/> + <xi> + <lambda true="this-is-att-value" xml:id="id7"/> + <any xml:id="id8"/> + <kappa/> + <theta abort="attribute" xml:lang="nb" xml:id="id9"> + <epsilon false="attribute-value" xml:lang="en-GB" xml:id="id10"> + <chi xml:lang="nb" xml:id="id11"> + <chi xml:id="id12"> + <green>This text must be green</green> + </chi> + </chi> + </epsilon> + </theta> + </xi> + </epsilon> + </phi> + </any> + </theta> + </alpha> + </tree> + </test> + <test> + <xpath>//psi//epsilon[contains(@att,"alue")][@xml:lang="no"][not(following-sibling::*)]/zeta[contains(@object,"s-att-value")][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[following-sibling::pi[contains(concat(@number,"$"),"content$")][@xml:lang="nb"][@xml:id="id1"][not(child::node())][following-sibling::eta[starts-with(@delete,"this-is-att-valu")][@xml:lang="no"]//beta[not(following-sibling::*)]/lambda[@object][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::tau[@xml:id="id3"][not(child::node())][following-sibling::gamma[@insert="100%"][@xml:lang="nb"][not(child::node())][following-sibling::nu[@insert][@xml:id="id4"][preceding-sibling::*[position() = 4]][following-sibling::phi[starts-with(@token,"1234")][not(following-sibling::*)]][position() = 1]]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <psi> + <epsilon att="this-is-att-value" xml:lang="no"> + <zeta object="this-is-att-value"/> + <delta/> + <pi number="content" xml:lang="nb" xml:id="id1"/> + <eta delete="this-is-att-value" xml:lang="no"> + <beta> + <lambda object="attribute value" xml:lang="no"/> + <iota xml:lang="en-GB" xml:id="id2"/> + <tau xml:id="id3"/> + <gamma insert="100%" xml:lang="nb"/> + <nu insert="solid 1px green" xml:id="id4"/> + <phi token="123456789"> + <green>This text must be green</green> + </phi> + </beta> + </eta> + </epsilon> + </psi> + </tree> + </test> + <test> + <xpath>//alpha[@delete]//alpha[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)]//omega[@string][@xml:id="id2"][not(following-sibling::*)]/rho[starts-with(concat(@delete,"-"),"true-")][@xml:id="id3"]//chi[contains(@token,"tribu")][@xml:lang="nb"][@xml:id="id4"]//iota[@insert="true"][@xml:id="id5"][not(preceding-sibling::*)]//chi[@attrib="solid 1px green"][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@and][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@xml:lang="no-nb"][not(preceding-sibling::*)]//zeta[not(following-sibling::*)]/kappa[@content][not(preceding-sibling::*)]//rho[starts-with(concat(@object,"-"),"_blank-")][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:lang="no"][@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[starts-with(@desciption,"this.nodeV")][@xml:id="id7"][not(following-sibling::*)]/theta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:id="id8"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <alpha delete="attribute-value"> + <alpha xml:lang="no-nb" xml:id="id1"> + <omega string="_blank" xml:id="id2"> + <rho delete="true" xml:id="id3"> + <chi token="attribute-value" xml:lang="nb" xml:id="id4"> + <iota insert="true" xml:id="id5"> + <chi attrib="solid 1px green" xml:lang="en-US"> + <xi and="content"> + <kappa xml:lang="no-nb"> + <zeta> + <kappa content="attribute"> + <rho object="_blank"> + <eta xml:lang="no" xml:id="id6"/> + <omicron desciption="this.nodeValue" xml:id="id7"> + <theta xml:lang="no"/> + <omicron xml:lang="nb"/> + <phi xml:id="id8"> + <green>This text must be green</green> + </phi> + </omicron> + </rho> + </kappa> + </zeta> + </kappa> + </xi> + </chi> + </iota> + </chi> + </rho> + </omega> + </alpha> + </alpha> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]/upsilon[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[@xml:lang="no-nb"][not(following-sibling::*)]/delta[contains(concat(@attrib,"$"),"%$")][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id4"]//sigma[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <upsilon xml:id="id2"> + <gamma xml:lang="no-nb"> + <delta attrib="100%" xml:id="id3"/> + <iota xml:id="id4"> + <sigma xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </sigma> + </iota> + </gamma> + </upsilon> + </gamma> + </tree> + </test> + <test> + <xpath>//delta[starts-with(concat(@and,"-"),"another attribute value-")]/*[@attr][@xml:lang="en-US"][following-sibling::*[position()=2]][following-sibling::xi[contains(concat(@false,"$"),"k$")][@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/gamma[@xml:id="id3"]//zeta[starts-with(@title,"solid 1px gree")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/rho[starts-with(@name,"1")][@xml:id="id5"][not(child::node())][following-sibling::rho[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[starts-with(@string,"a")][not(following-sibling::*)]//chi[starts-with(@class,"f")][following-sibling::kappa[@object][@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[@xml:lang="en-GB"][not(following-sibling::*)][not(preceding-sibling::epsilon)]//mu[@abort]//theta[starts-with(@class,"solid ")][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@and][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[starts-with(@attribute,"this")][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::delta[starts-with(concat(@class,"-"),"_blank-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//omicron[@xml:id="id11"][following-sibling::mu[starts-with(concat(@and,"-"),"100%-")][@xml:lang="en-US"]//theta[@string][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <delta and="another attribute value"> + <any attr="attribute" xml:lang="en-US"/> + <xi false="_blank" xml:lang="en-US" xml:id="id1"/> + <delta xml:id="id2"> + <gamma xml:id="id3"> + <zeta title="solid 1px green" xml:lang="en" xml:id="id4"> + <rho name="100%" xml:id="id5"/> + <rho xml:id="id6"> + <phi string="attribute-value"> + <chi class="false"/> + <kappa object="attribute-value" xml:lang="nb" xml:id="id7"> + <epsilon xml:lang="en-GB"> + <mu abort="solid 1px green"> + <theta class="solid 1px green" xml:lang="no" xml:id="id8"> + <delta xml:lang="en-US"> + <psi and="attribute-value" xml:id="id9"> + <chi attribute="this.nodeValue" xml:id="id10"/> + <delta class="_blank" xml:lang="en-GB"> + <omicron xml:id="id11"/> + <mu and="100%" xml:lang="en-US"> + <theta string="100%"> + <green>This text must be green</green> + </theta> + </mu> + </delta> + </psi> + </delta> + </theta> + </mu> + </epsilon> + </kappa> + </phi> + </rho> + </zeta> + </gamma> + </delta> + </delta> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="nb"]/beta[contains(concat(@delete,"$")," value$")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[contains(@attrib,"e")][@xml:lang="nb"][@xml:id="id2"][following-sibling::*[starts-with(concat(@true,"-"),"123456789-")][@xml:lang="no-nb"][@xml:id="id3"]/sigma[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::theta[contains(@abort,"56789")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[@xml:lang="en"][@xml:id="id6"][not(child::node())][following-sibling::psi//eta[contains(concat(@abort,"$"),"e value$")][@xml:lang="no"][not(following-sibling::*)]//sigma[not(preceding-sibling::*)]/omega[@xml:lang="no"]/epsilon[@attrib][@xml:id="id7"][following-sibling::zeta[@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@or="another attribute value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[starts-with(@true,"co")][@xml:lang="no-nb"][@xml:id="id8"][not(following-sibling::*)]/omega[contains(@object,"n")][@xml:lang="en"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="nb"> + <beta delete="attribute value" xml:id="id1"/> + <omega attrib="attribute value" xml:lang="nb" xml:id="id2"/> + <any true="123456789" xml:lang="no-nb" xml:id="id3"> + <sigma xml:lang="en-US" xml:id="id4"/> + <theta abort="123456789" xml:lang="en-GB" xml:id="id5"/> + <psi xml:lang="en" xml:id="id6"/> + <psi> + <eta abort="another attribute value" xml:lang="no"> + <sigma> + <omega xml:lang="no"> + <epsilon attrib="attribute-value" xml:id="id7"/> + <zeta xml:lang="nb"/> + <alpha or="another attribute value"> + <phi true="content" xml:lang="no-nb" xml:id="id8"> + <omega object="content" xml:lang="en"> + <green>This text must be green</green> + </omega> + </phi> + </alpha> + </omega> + </sigma> + </eta> + </psi> + </any> + </upsilon> + </tree> + </test> + <test> + <xpath>//psi[contains(@attr,"lue")][@xml:lang="no-nb"][@xml:id="id1"]//epsilon[@att="content"][@xml:lang="en"][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@delete][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::kappa[following-sibling::omega[@xml:lang="en-GB"]]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <psi attr="this-is-att-value" xml:lang="no-nb" xml:id="id1"> + <epsilon att="content" xml:lang="en"/> + <beta xml:lang="en"> + <kappa delete="100%" xml:id="id2"/> + <kappa/> + <omega xml:lang="en-GB"> + <green>This text must be green</green> + </omega> + </beta> + </psi> + </tree> + </test> + <test> + <xpath>//chi[starts-with(@abort,"_")][@xml:lang="no-nb"]//omega/theta[@xml:id="id1"][following-sibling::pi[@xml:lang="nb"][following-sibling::*[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::iota[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/xi[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@name="false"][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)]//psi[starts-with(@true,"attribut")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::xi[@xml:id="id7"][preceding-sibling::*[position() = 1]]/kappa[@token="another attribute value"][@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]/gamma[@number][not(following-sibling::*)][not(following-sibling::gamma)]//theta[@xml:lang="en-GB"][@xml:id="id9"][not(child::node())][following-sibling::theta[@desciption][@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[contains(concat(@att,"$"),"ue$")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <chi abort="_blank" xml:lang="no-nb"> + <omega> + <theta xml:id="id1"/> + <pi xml:lang="nb"/> + <any xml:lang="en-US" xml:id="id2"/> + <iota xml:lang="en" xml:id="id3"> + <xi xml:lang="en-US" xml:id="id4"> + <lambda name="false" xml:lang="no" xml:id="id5"> + <psi true="attribute" xml:lang="nb" xml:id="id6"/> + <xi xml:id="id7"> + <kappa token="another attribute value" xml:lang="en-GB" xml:id="id8"> + <gamma number="another attribute value"> + <theta xml:lang="en-GB" xml:id="id9"/> + <theta desciption="this-is-att-value" xml:lang="en" xml:id="id10"/> + <tau att="this.nodeValue" xml:lang="en-US"> + <green>This text must be green</green> + </tau> + </gamma> + </kappa> + </xi> + </lambda> + </xi> + </iota> + </omega> + </chi> + </tree> + </test> + <test> + <xpath>//psi[@xml:id="id1"]//zeta[@xml:lang="en-GB"][following-sibling::lambda[@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::kappa[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//gamma[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]//zeta[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[starts-with(@or,"thi")][following-sibling::*[position()=3]][not(child::node())][following-sibling::lambda[contains(concat(@attrib,"$"),"attribute value$")][@xml:lang="en-US"][not(child::node())][following-sibling::omicron[starts-with(concat(@attrib,"-"),"true-")][@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[starts-with(@attrib,"this-is-at")][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 3]]/pi[contains(concat(@attribute,"$"),"attribute value$")][@xml:id="id7"]/omicron[@false][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]//rho[@xml:id="id9"][not(preceding-sibling::*)]/iota[@true="solid 1px green"][@xml:id="id10"][not(following-sibling::*)]//gamma[@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@number][not(following-sibling::*)]/kappa[following-sibling::*[position()=3]][following-sibling::xi[preceding-sibling::*[position() = 1]][following-sibling::xi[contains(@class,"ank")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][preceding-sibling::xi[1]][following-sibling::pi[contains(@content,"solid")][@xml:id="id12"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:id="id1"> + <zeta xml:lang="en-GB"/> + <lambda xml:lang="no" xml:id="id2"/> + <kappa xml:id="id3"> + <gamma xml:lang="no-nb" xml:id="id4"> + <zeta xml:lang="nb" xml:id="id5"> + <gamma xml:lang="en"> + <theta or="this.nodeValue"/> + <lambda attrib="attribute value" xml:lang="en-US"/> + <omicron attrib="true" xml:lang="en-GB"/> + <eta attrib="this-is-att-value" xml:lang="no" xml:id="id6"> + <pi attribute="another attribute value" xml:id="id7"> + <omicron false="solid 1px green" xml:lang="nb"/> + <any xml:lang="en-US" xml:id="id8"> + <rho xml:id="id9"> + <iota true="solid 1px green" xml:id="id10"> + <gamma xml:id="id11"> + <lambda number="another attribute value"> + <kappa/> + <xi/> + <xi class="_blank" xml:lang="no-nb"/> + <pi content="solid 1px green" xml:id="id12"> + <green>This text must be green</green> + </pi> + </lambda> + </gamma> + </iota> + </rho> + </any> + </pi> + </eta> + </gamma> + </zeta> + </gamma> + </kappa> + </psi> + </tree> + </test> + <test> + <xpath>//theta[@xml:id="id1"]//nu[@xml:lang="no"][not(following-sibling::*)]/psi[starts-with(concat(@class,"-"),"solid 1px green-")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[@attribute="attribute"][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//gamma[@xml:lang="en-GB"]//alpha/zeta[@class][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[contains(@attrib,"ont")][not(preceding-sibling::*)]//psi[@attrib][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/pi[contains(@attribute,"id 1px g")][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]]//epsilon[starts-with(@number,"attri")][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:lang="en-US"][@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::epsilon[contains(concat(@attrib,"$"),"te value$")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)]/eta[@xml:id="id10"][not(preceding-sibling::*)][following-sibling::upsilon[contains(concat(@true,"$"),"true$")][@xml:id="id11"][not(child::node())][following-sibling::pi[@xml:id="id12"][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[not(following-sibling::*)]//omicron[@xml:id="id13"][following-sibling::gamma[@xml:lang="en-GB"][following-sibling::theta[@xml:id="id14"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:id="id1"> + <nu xml:lang="no"> + <psi class="solid 1px green" xml:lang="no" xml:id="id2"/> + <delta attribute="attribute" xml:lang="no" xml:id="id3"> + <gamma xml:lang="en-GB"> + <alpha> + <zeta class="content" xml:lang="en-GB" xml:id="id4"> + <theta attrib="content"> + <psi attrib="false" xml:lang="no-nb"/> + <chi xml:id="id5"> + <pi attribute="solid 1px green"/> + <kappa xml:lang="en-GB" xml:id="id6"> + <epsilon number="attribute-value" xml:id="id7"> + <pi xml:lang="en-US" xml:id="id8"/> + <epsilon attrib="another attribute value" xml:lang="nb"/> + <pi xml:lang="no-nb" xml:id="id9"> + <eta xml:id="id10"/> + <upsilon true="true" xml:id="id11"/> + <pi xml:id="id12"/> + <delta> + <omicron xml:id="id13"/> + <gamma xml:lang="en-GB"/> + <theta xml:id="id14"> + <green>This text must be green</green> + </theta> + </delta> + </pi> + </epsilon> + </kappa> + </chi> + </theta> + </zeta> + </alpha> + </gamma> + </delta> + </nu> + </theta> + </tree> + </test> + <test> + <xpath>//phi/*[@xml:lang="nb"][@xml:id="id1"][following-sibling::lambda[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::psi[@xml:lang="nb"][@xml:id="id3"]/phi[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::beta[@object="true"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[following-sibling::*[position()=1]][not(preceding-sibling::xi)][following-sibling::lambda[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@title][@xml:id="id7"][not(preceding-sibling::*)]//sigma[@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]//theta[@xml:id="id9"][following-sibling::mu[@xml:lang="no-nb"][@xml:id="id10"]//alpha[@xml:id="id11"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id12"][following-sibling::phi[starts-with(concat(@class,"-"),"another attribute value-")][position() = 1]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <any xml:lang="nb" xml:id="id1"/> + <lambda xml:lang="no-nb" xml:id="id2"/> + <psi xml:lang="nb" xml:id="id3"> + <phi xml:id="id4"/> + <beta object="true" xml:id="id5"> + <xi/> + <lambda xml:id="id6"> + <xi title="false" xml:id="id7"> + <sigma xml:lang="no" xml:id="id8"> + <theta xml:id="id9"/> + <mu xml:lang="no-nb" xml:id="id10"> + <alpha xml:id="id11"/> + <epsilon xml:id="id12"/> + <phi class="another attribute value"> + <green>This text must be green</green> + </phi> + </mu> + </sigma> + </xi> + </lambda> + </beta> + </psi> + </phi> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(concat(@name,"-"),"attribute value-")][@xml:id="id1"]//rho[contains(concat(@attrib,"$"),"se$")][@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//upsilon[@xml:id="id3"][not(child::node())][following-sibling::sigma[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id4"]/beta[not(preceding-sibling::*)]/tau[@xml:lang="en-GB"][not(preceding-sibling::*)]/upsilon[@xml:id="id5"][following-sibling::*[position()=2]][following-sibling::kappa[starts-with(concat(@attr,"-"),"this-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[contains(concat(@class,"$"),"e$")][@xml:id="id6"][not(preceding-sibling::*)]//upsilon[@or][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(concat(@title,"-"),"100%-")][@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)]/eta[@xml:lang="no"][following-sibling::psi[starts-with(concat(@data,"-"),"false-")][@xml:id="id8"][not(child::node())][following-sibling::*[starts-with(@content,"12345")][@xml:id="id9"][not(following-sibling::*)]/xi[contains(@src,"e")][@xml:lang="nb"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::sigma[@src][@xml:lang="en-US"][@xml:id="id11"][not(following-sibling::*)]//alpha[starts-with(@name,"att")][@xml:lang="nb"][@xml:id="id12"][following-sibling::mu[@xml:id="id13"]/eta[@xml:lang="no-nb"][@xml:id="id14"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <lambda name="attribute value" xml:id="id1"> + <rho attrib="false" xml:lang="en-US" xml:id="id2"> + <upsilon xml:id="id3"/> + <sigma xml:lang="no"/> + <phi xml:lang="no-nb" xml:id="id4"> + <beta> + <tau xml:lang="en-GB"> + <upsilon xml:id="id5"/> + <kappa attr="this-is-att-value" xml:lang="en"/> + <nu xml:lang="nb"> + <lambda class="false" xml:id="id6"> + <upsilon or="attribute"> + <beta title="100%" xml:lang="en-US" xml:id="id7"> + <eta xml:lang="no"/> + <psi data="false" xml:id="id8"/> + <any content="123456789" xml:id="id9"> + <xi src="false" xml:lang="nb" xml:id="id10"/> + <sigma src="attribute-value" xml:lang="en-US" xml:id="id11"> + <alpha name="attribute value" xml:lang="nb" xml:id="id12"/> + <mu xml:id="id13"> + <eta xml:lang="no-nb" xml:id="id14"> + <green>This text must be green</green> + </eta> + </mu> + </sigma> + </any> + </beta> + </upsilon> + </lambda> + </nu> + </tau> + </beta> + </phi> + </rho> + </lambda> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(@name,"attribu")][@xml:lang="nb"]//delta[starts-with(@src,"another attribu")][not(preceding-sibling::*)][not(following-sibling::*)]/xi[following-sibling::chi[starts-with(concat(@insert,"-"),"attribute-")][@xml:id="id1"][not(child::node())][following-sibling::nu[@attribute="attribute-value"][@xml:lang="no"][not(following-sibling::*)]/zeta[@insert][@xml:lang="no-nb"][not(following-sibling::*)]/eta[not(child::node())][following-sibling::phi[@or="content"][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::lambda[contains(@number,"bute value")][preceding-sibling::*[position() = 2]]/epsilon[starts-with(@and,"solid 1px g")][not(preceding-sibling::*)][following-sibling::iota[contains(concat(@string,"$"),"%$")][@xml:lang="no-nb"]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <gamma name="attribute" xml:lang="nb"> + <delta src="another attribute value"> + <xi/> + <chi insert="attribute" xml:id="id1"/> + <nu attribute="attribute-value" xml:lang="no"> + <zeta insert="content" xml:lang="no-nb"> + <eta/> + <phi or="content" xml:lang="en-GB" xml:id="id2"/> + <lambda number="attribute value"> + <epsilon and="solid 1px green"/> + <iota string="100%" xml:lang="no-nb"> + <green>This text must be green</green> + </iota> + </lambda> + </zeta> + </nu> + </delta> + </gamma> + </tree> + </test> + <test> + <xpath>//iota/kappa[@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::lambda[@xml:id="id2"][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::*[@xml:id="id3"][preceding-sibling::*[position() = 3]]/kappa[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)]//phi[contains(concat(@class,"$"),"another attribute value$")][@xml:lang="en"][not(preceding-sibling::*)]//sigma[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <iota> + <kappa xml:lang="en-GB" xml:id="id1"/> + <lambda xml:id="id2"/> + <delta xml:lang="en-GB"/> + <any xml:id="id3"> + <kappa xml:lang="nb" xml:id="id4"> + <phi class="another attribute value" xml:lang="en"> + <sigma xml:lang="en-GB"> + <green>This text must be green</green> + </sigma> + </phi> + </kappa> + </any> + </iota> + </tree> + </test> + <test> + <xpath>//rho[starts-with(@src,"fals")][@xml:id="id1"]//nu[starts-with(concat(@att,"-"),"_blank-")][@xml:lang="no"][not(following-sibling::*)]/gamma[@token][not(preceding-sibling::*)][following-sibling::zeta[contains(concat(@attr,"$"),"value$")][preceding-sibling::*[position() = 1]][not(following-sibling::zeta)]/nu[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//alpha[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[not(child::node())][following-sibling::kappa[contains(@true,"Value")][@xml:lang="no"][@xml:id="id4"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <rho src="false" xml:id="id1"> + <nu att="_blank" xml:lang="no"> + <gamma token="123456789"/> + <zeta attr="attribute value"> + <nu xml:lang="en-GB" xml:id="id2"/> + <psi> + <alpha xml:lang="no"/> + <tau xml:lang="nb" xml:id="id3"> + <iota/> + <kappa true="this.nodeValue" xml:lang="no" xml:id="id4"> + <green>This text must be green</green> + </kappa> + </tau> + </psi> + </zeta> + </nu> + </rho> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@false,"$"),"this.nodeValue$")]//epsilon[contains(concat(@string,"$"),"123456789$")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[starts-with(concat(@true,"-"),"true-")][not(child::node())][following-sibling::mu[not(following-sibling::*)]//pi[@true="_blank"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::omicron//iota[@abort="content"][@xml:lang="no-nb"]/chi[@xml:lang="no-nb"][not(child::node())][following-sibling::theta[@and][@xml:lang="no"][not(preceding-sibling::theta)]/chi[@xml:lang="en"][not(following-sibling::*)]//chi[@xml:lang="en-GB"][@xml:id="id4"][following-sibling::sigma[@xml:id="id5"]/eta[@xml:lang="en"][not(following-sibling::*)]/chi[@attr][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::epsilon[@class][@xml:id="id7"][following-sibling::phi[contains(concat(@number,"$"),"se$")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/eta[@xml:lang="en-US"][@xml:id="id8"][not(preceding-sibling::*)]//zeta[contains(concat(@src,"$"),"ribute$")][@xml:lang="en-US"][not(preceding-sibling::*)]//iota[@name][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[starts-with(@attrib,"1234")][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@false][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(preceding-sibling::mu)]/iota[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <beta false="this.nodeValue"> + <epsilon string="123456789" xml:id="id1"/> + <theta true="true"/> + <mu> + <pi true="_blank" xml:id="id2"/> + <mu xml:id="id3"/> + <omicron> + <iota abort="content" xml:lang="no-nb"> + <chi xml:lang="no-nb"/> + <theta and="this.nodeValue" xml:lang="no"> + <chi xml:lang="en"> + <chi xml:lang="en-GB" xml:id="id4"/> + <sigma xml:id="id5"> + <eta xml:lang="en"> + <chi attr="this.nodeValue" xml:lang="en-GB" xml:id="id6"/> + <epsilon class="solid 1px green" xml:id="id7"/> + <phi number="false"> + <eta xml:lang="en-US" xml:id="id8"> + <zeta src="attribute" xml:lang="en-US"> + <iota name="attribute value"/> + <chi attrib="123456789" xml:lang="no"/> + <mu false="this.nodeValue" xml:id="id9"> + <iota xml:lang="nb"> + <green>This text must be green</green> + </iota> + </mu> + </zeta> + </eta> + </phi> + </eta> + </sigma> + </chi> + </theta> + </iota> + </omicron> + </mu> + </beta> + </tree> + </test> + <test> + <xpath>//gamma[@abort="123456789"][@xml:lang="nb"][@xml:id="id1"]/kappa[starts-with(@name,"so")][@xml:id="id2"]/mu[@name][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:lang="en-US"][following-sibling::psi[contains(concat(@number,"$"),"ue$")][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::lambda[@string="_blank"][@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::alpha[preceding-sibling::*[position() = 4]][not(following-sibling::*)]//delta[contains(concat(@abort,"$"),"t$")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[@false][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=7]][not(child::node())][following-sibling::upsilon[contains(@content,"nt")][@xml:lang="no-nb"][not(child::node())][following-sibling::pi[contains(@src,"e")][@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=5]][following-sibling::sigma[contains(concat(@number,"$"),"value$")][@xml:lang="en-GB"][following-sibling::kappa[@token][following-sibling::kappa[contains(concat(@true,"$"),"content$")][@xml:lang="en-US"][following-sibling::kappa[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][preceding-sibling::*[position() = 7]][following-sibling::*[position()=1]][following-sibling::kappa[starts-with(@src,"attribute value")][@xml:id="id6"][preceding-sibling::*[position() = 8]][not(following-sibling::*)]/pi[@token][@xml:id="id7"][not(preceding-sibling::*)]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <gamma abort="123456789" xml:lang="nb" xml:id="id1"> + <kappa name="solid 1px green" xml:id="id2"> + <mu name="_blank" xml:lang="no-nb"/> + <kappa xml:lang="en-US"/> + <psi number="this.nodeValue" xml:id="id3"/> + <lambda string="_blank" xml:lang="nb"/> + <alpha> + <delta abort="content" xml:lang="no" xml:id="id4"/> + <any false="_blank" xml:lang="no-nb"/> + <upsilon content="content" xml:lang="no-nb"/> + <pi src="another attribute value" xml:lang="no" xml:id="id5"/> + <sigma number="attribute value" xml:lang="en-GB"/> + <kappa token="123456789"/> + <kappa true="content" xml:lang="en-US"/> + <tau xml:lang="no-nb"/> + <kappa src="attribute value" xml:id="id6"> + <pi token="_blank" xml:id="id7"> + <green>This text must be green</green> + </pi> + </kappa> + </alpha> + </kappa> + </gamma> + </tree> + </test> + <test> + <xpath>//tau[@xml:id="id1"]//gamma[not(preceding-sibling::*)]/alpha[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[contains(@title,"nk")][@xml:lang="no"]//psi[@xml:lang="no-nb"][@xml:id="id2"]//zeta[contains(@att,"ank")][@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@attr="123456789"][@xml:id="id4"][following-sibling::xi[contains(concat(@false,"$"),"_blank$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:id="id1"> + <gamma> + <alpha/> + <phi title="_blank" xml:lang="no"> + <psi xml:lang="no-nb" xml:id="id2"> + <zeta att="_blank" xml:lang="nb" xml:id="id3"> + <kappa attr="123456789" xml:id="id4"/> + <xi false="_blank"> + <green>This text must be green</green> + </xi> + </zeta> + </psi> + </phi> + </gamma> + </tau> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="en-US"]/gamma[@attribute][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@attribute="content"][@xml:id="id2"]/upsilon[starts-with(concat(@desciption,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id3"][following-sibling::theta[@desciption="true"][@xml:lang="en-GB"][@xml:id="id4"][following-sibling::*[position()=3]][following-sibling::omicron[@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::xi[@attribute][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::psi[preceding-sibling::*[position() = 4]]/pi//psi[@name][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:id="id7"]//mu[@attr][@xml:lang="en-US"][@xml:id="id8"][following-sibling::mu[@xml:lang="nb"][@xml:id="id9"][not(child::node())][following-sibling::kappa[@xml:lang="no"][@xml:id="id10"]]]]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:lang="en-US"> + <gamma attribute="100%"/> + <omicron xml:lang="en-GB" xml:id="id1"/> + <theta attribute="content" xml:id="id2"> + <upsilon desciption="attribute" xml:lang="en-US" xml:id="id3"/> + <theta desciption="true" xml:lang="en-GB" xml:id="id4"/> + <omicron xml:lang="no" xml:id="id5"/> + <xi attribute="attribute" xml:id="id6"/> + <psi> + <pi> + <psi name="true"/> + <zeta xml:lang="en-US"> + <beta xml:id="id7"> + <mu attr="attribute" xml:lang="en-US" xml:id="id8"/> + <mu xml:lang="nb" xml:id="id9"/> + <kappa xml:lang="no" xml:id="id10"> + <green>This text must be green</green> + </kappa> + </beta> + </zeta> + </pi> + </psi> + </theta> + </chi> + </tree> + </test> + <test> + <xpath>//zeta[@token][@xml:id="id1"]/omega[@xml:lang="no-nb"][@xml:id="id2"]/nu[contains(@insert,"gre")][@xml:lang="no"][@xml:id="id3"]/upsilon[not(preceding-sibling::*)]/iota[@desciption][@xml:id="id4"]/alpha[@content][@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[@attrib][@xml:id="id6"][not(child::node())][following-sibling::xi[starts-with(@attr,"content")][@xml:lang="en"][@xml:id="id7"][following-sibling::iota[preceding-sibling::*[position() = 3]][not(following-sibling::*)]//pi[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::zeta[@true][@xml:lang="en-GB"][@xml:id="id9"][following-sibling::*[position()=2]][following-sibling::psi[@content][@xml:lang="no-nb"][not(child::node())][following-sibling::*[@xml:id="id10"][not(following-sibling::*)][not(following-sibling::any)]/alpha[@xml:lang="en-US"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:id="id12"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <zeta token="attribute-value" xml:id="id1"> + <omega xml:lang="no-nb" xml:id="id2"> + <nu insert="solid 1px green" xml:lang="no" xml:id="id3"> + <upsilon> + <iota desciption="solid 1px green" xml:id="id4"> + <alpha content="false" xml:lang="en-US" xml:id="id5"/> + <any attrib="another attribute value" xml:id="id6"/> + <xi attr="content" xml:lang="en" xml:id="id7"/> + <iota> + <pi xml:lang="en" xml:id="id8"/> + <zeta true="attribute" xml:lang="en-GB" xml:id="id9"/> + <psi content="false" xml:lang="no-nb"/> + <any xml:id="id10"> + <alpha xml:lang="en-US" xml:id="id11"> + <epsilon content="this.nodeValue" xml:id="id12"> + <green>This text must be green</green> + </epsilon> + </alpha> + </any> + </iota> + </iota> + </upsilon> + </nu> + </omega> + </zeta> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]/pi[@xml:lang="no"][@xml:id="id2"]//nu[@xml:lang="en"][not(child::node())][following-sibling::tau[contains(@name,"e value")][@xml:lang="en"][@xml:id="id3"][following-sibling::zeta[@desciption="this-is-att-value"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::tau[@xml:id="id5"][not(following-sibling::*)]//*[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@and][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[contains(concat(@true,"$"),"ibute$")][@xml:lang="en"][@xml:id="id8"][not(following-sibling::*)]/chi[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::upsilon[starts-with(concat(@attrib,"-"),"_blank-")][@xml:lang="no-nb"][@xml:id="id10"][not(child::node())][following-sibling::tau[@object][preceding-sibling::*[position() = 2]]//mu[@token="this-is-att-value"][@xml:id="id11"][not(child::node())][following-sibling::*[@name="false"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:lang="en"][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][following-sibling::phi[starts-with(@token,"this-is-att-valu")][@xml:lang="no"][@xml:id="id12"][not(following-sibling::*)]//tau[@data="attribute value"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::delta[starts-with(concat(@delete,"-"),"another attribute value-")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@xml:lang="nb"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <pi xml:lang="no" xml:id="id2"> + <nu xml:lang="en"/> + <tau name="attribute value" xml:lang="en" xml:id="id3"/> + <zeta desciption="this-is-att-value" xml:id="id4"/> + <tau xml:id="id5"> + <any xml:id="id6"> + <eta xml:lang="en-GB"> + <chi and="this-is-att-value" xml:id="id7"/> + <any true="attribute" xml:lang="en" xml:id="id8"> + <chi xml:id="id9"/> + <upsilon attrib="_blank" xml:lang="no-nb" xml:id="id10"/> + <tau object="solid 1px green"> + <mu token="this-is-att-value" xml:id="id11"/> + <any name="false"/> + <alpha xml:lang="en"/> + <iota/> + <sigma xml:lang="no-nb"/> + <phi token="this-is-att-value" xml:lang="no" xml:id="id12"> + <tau data="attribute value" xml:lang="no-nb"/> + <delta delete="another attribute value"/> + <epsilon xml:lang="nb"> + <green>This text must be green</green> + </epsilon> + </phi> + </tau> + </any> + </eta> + </any> + </tau> + </pi> + </xi> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@content,"-"),"123456789-")][@xml:id="id1"]/tau[@desciption="attribute"][@xml:lang="en"][@xml:id="id2"]/zeta[contains(@abort,"89")][@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::xi[starts-with(@src,"12345")][@xml:lang="no-nb"][following-sibling::rho[starts-with(@class,"true")][@xml:id="id4"][preceding-sibling::*[position() = 2]]//epsilon[@abort][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::sigma[contains(@object,"0%")][@xml:id="id5"]/tau[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta[not(preceding-sibling::*)][not(following-sibling::*)]//iota[not(following-sibling::*)]/iota[@xml:lang="nb"][not(child::node())][following-sibling::pi[not(child::node())][following-sibling::alpha[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::pi[@string="true"][@xml:lang="nb"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]/pi[contains(concat(@abort,"$"),"9$")][following-sibling::*[position()=2]][following-sibling::zeta[@xml:lang="nb"][following-sibling::iota//upsilon[@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]//nu[contains(concat(@src,"$"),"solid 1px green$")][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(@string,"00%")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <mu content="123456789" xml:id="id1"> + <tau desciption="attribute" xml:lang="en" xml:id="id2"> + <zeta abort="123456789" xml:lang="en-GB" xml:id="id3"/> + <xi src="123456789" xml:lang="no-nb"/> + <rho class="true" xml:id="id4"> + <epsilon abort="attribute" xml:lang="en"/> + <sigma object="100%" xml:id="id5"> + <tau/> + <lambda xml:lang="en-GB" xml:id="id6"> + <zeta> + <iota> + <iota xml:lang="nb"/> + <pi/> + <alpha xml:lang="en"/> + <pi string="true" xml:lang="nb" xml:id="id7"/> + <tau xml:lang="en-GB" xml:id="id8"> + <pi abort="123456789"/> + <zeta xml:lang="nb"/> + <iota> + <upsilon xml:id="id9"/> + <any xml:lang="no-nb"> + <nu src="solid 1px green"/> + <mu string="100%" xml:lang="en"> + <green>This text must be green</green> + </mu> + </any> + </iota> + </tau> + </iota> + </zeta> + </lambda> + </sigma> + </rho> + </tau> + </mu> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en"][@xml:id="id1"]/rho[contains(concat(@true,"$"),"_blank$")][@xml:lang="nb"][not(preceding-sibling::*)]/omicron[contains(concat(@false,"$"),"tribute value$")][@xml:id="id2"][not(child::node())][following-sibling::chi[@number="solid 1px green"][not(following-sibling::*)]/omicron[not(preceding-sibling::*)][not(following-sibling::*)]//beta[@att="_blank"][@xml:lang="nb"][@xml:id="id3"]//omega[@xml:lang="no-nb"][following-sibling::chi[not(following-sibling::*)]//epsilon[@xml:lang="en-GB"][not(child::node())][following-sibling::nu[@desciption="this.nodeValue"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:lang="en-US"][preceding-sibling::*[position() = 2]]/mu[starts-with(concat(@object,"-"),"solid 1px green-")][@xml:lang="en-US"][not(following-sibling::*)][not(preceding-sibling::mu)]/chi[@abort="true"][@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::iota[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/gamma[@attribute="100%"]/omicron[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[@number="100%"][@xml:lang="en-US"][@xml:id="id8"][following-sibling::beta[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::tau[preceding-sibling::*[position() = 2]]//delta[@xml:id="id10"][not(child::node())][following-sibling::omicron[contains(concat(@object,"$"),"ttribute$")][@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[contains(@title,"s")][@xml:id="id12"][not(following-sibling::*)]//xi[starts-with(concat(@desciption,"-"),"this-")][not(following-sibling::*)]//nu[@xml:lang="en"]][position() = 1]][position() = 1]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en" xml:id="id1"> + <rho true="_blank" xml:lang="nb"> + <omicron false="attribute value" xml:id="id2"/> + <chi number="solid 1px green"> + <omicron> + <beta att="_blank" xml:lang="nb" xml:id="id3"> + <omega xml:lang="no-nb"/> + <chi> + <epsilon xml:lang="en-GB"/> + <nu desciption="this.nodeValue" xml:id="id4"/> + <tau xml:lang="en-US"> + <mu object="solid 1px green" xml:lang="en-US"> + <chi abort="true" xml:lang="en" xml:id="id5"/> + <iota xml:id="id6"> + <gamma attribute="100%"> + <omicron xml:lang="en-US" xml:id="id7"> + <omicron number="100%" xml:lang="en-US" xml:id="id8"/> + <beta xml:id="id9"/> + <tau> + <delta xml:id="id10"/> + <omicron object="attribute" xml:lang="no" xml:id="id11"> + <iota title="false" xml:id="id12"> + <xi desciption="this-is-att-value"> + <nu xml:lang="en"> + <green>This text must be green</green> + </nu> + </xi> + </iota> + </omicron> + </tau> + </omicron> + </gamma> + </iota> + </mu> + </tau> + </chi> + </beta> + </omicron> + </chi> + </rho> + </phi> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//psi[@attrib][not(following-sibling::*)]//mu[@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(concat(@name,"$"),"ntent$")][@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]//pi[@or]//iota[@true][@xml:lang="en"][not(child::node())][following-sibling::xi[@abort][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[contains(@false,"ibute-va")][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:id="id4"]//alpha[not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="no-nb"]//pi[@false="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)]/sigma[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::eta[@attr="attribute value"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[not(child::node())][following-sibling::rho[@xml:id="id6"][not(following-sibling::*)]/omega[starts-with(concat(@false,"-"),"attribute value-")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(@true,"this.no")]/rho[starts-with(@att,"_")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[contains(@object,"blan")][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[contains(@false,"reen")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[contains(concat(@title,"$"),"1px green$")][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <psi attrib="true"> + <mu xml:id="id2"/> + <mu name="content" xml:lang="nb" xml:id="id3"> + <pi or="content"> + <iota true="another attribute value" xml:lang="en"/> + <xi abort="100%" xml:lang="en"> + <xi false="attribute-value"> + <iota xml:id="id4"> + <alpha/> + <upsilon xml:lang="no-nb"> + <pi false="this.nodeValue" xml:lang="en-GB" xml:id="id5"> + <sigma xml:lang="nb"/> + <eta attr="attribute value"/> + <rho/> + <rho xml:id="id6"> + <omega false="attribute value" xml:lang="en-US"/> + <pi true="this.nodeValue"> + <rho att="_blank" xml:lang="no"/> + <nu xml:id="id7"> + <nu object="_blank"/> + <rho false="solid 1px green"> + <xi title="solid 1px green"> + <green>This text must be green</green> + </xi> + </rho> + </nu> + </pi> + </rho> + </pi> + </upsilon> + </iota> + </xi> + </xi> + </pi> + </mu> + </psi> + </chi> + </tree> + </test> + <test> + <xpath>//lambda[contains(concat(@desciption,"$"),"00%$")][@xml:id="id1"]/epsilon[@xml:lang="en-US"]//alpha[@xml:id="id2"][not(preceding-sibling::alpha)]//omicron[@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::omicron[contains(@object,"56")][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::gamma[@attribute][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//gamma[not(preceding-sibling::*)]//xi[@insert="_blank"][@xml:id="id5"][not(preceding-sibling::xi)][following-sibling::gamma[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::*[@xml:lang="en-GB"][following-sibling::rho[contains(@and,"t")][not(following-sibling::*)]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <lambda desciption="100%" xml:id="id1"> + <epsilon xml:lang="en-US"> + <alpha xml:id="id2"> + <omicron xml:lang="en" xml:id="id3"/> + <omicron object="123456789"/> + <tau/> + <gamma attribute="attribute" xml:id="id4"> + <gamma> + <xi insert="_blank" xml:id="id5"/> + <gamma xml:id="id6"/> + <any xml:lang="en-GB"/> + <rho and="content"> + <green>This text must be green</green> + </rho> + </gamma> + </gamma> + </alpha> + </epsilon> + </lambda> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="en-US"]//beta[@xml:lang="nb"]/lambda[@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]/nu[following-sibling::omega[@xml:lang="no-nb"][not(following-sibling::*)]/rho[@string][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="en-US"> + <beta xml:lang="nb"> + <lambda xml:lang="en-GB" xml:id="id1"> + <nu/> + <omega xml:lang="no-nb"> + <rho string="_blank" xml:id="id2"> + <green>This text must be green</green> + </rho> + </omega> + </lambda> + </beta> + </lambda> + </tree> + </test> + <test> + <xpath>//omega[starts-with(@token,"this-is-att-valu")][@xml:lang="no"]//mu[starts-with(@attrib,"solid 1px gr")][@xml:lang="en"][@xml:id="id1"][not(following-sibling::*)]//gamma[not(preceding-sibling::*)]/sigma[not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:lang="en"][@xml:id="id2"]//omega[starts-with(concat(@and,"-"),"attribute-")][not(preceding-sibling::*)]/epsilon[@xml:id="id3"][not(preceding-sibling::*)]//omicron[contains(@insert,"lue")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(preceding-sibling::delta)][following-sibling::lambda[preceding-sibling::*[position() = 1]]/theta[starts-with(@att,"attribu")][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[contains(@or,"789")][following-sibling::*[position()=1]][following-sibling::tau[@insert][@xml:lang="en"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//*[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <omega token="this-is-att-value" xml:lang="no"> + <mu attrib="solid 1px green" xml:lang="en" xml:id="id1"> + <gamma> + <sigma/> + <phi xml:lang="en" xml:id="id2"> + <omega and="attribute"> + <epsilon xml:id="id3"> + <omicron insert="this.nodeValue" xml:lang="en-GB" xml:id="id4"> + <delta xml:lang="en" xml:id="id5"/> + <lambda> + <theta att="attribute" xml:id="id6"/> + <psi xml:lang="no"/> + <lambda or="123456789"/> + <tau insert="false" xml:lang="en"> + <any xml:lang="en-GB"> + <green>This text must be green</green> + </any> + </tau> + </lambda> + </omicron> + </epsilon> + </omega> + </phi> + </gamma> + </mu> + </omega> + </tree> + </test> + <test> + <xpath>//omega[contains(@title,"ru")][@xml:id="id1"]//psi[@title][@xml:lang="en-GB"][not(following-sibling::*)]//alpha[not(child::node())][following-sibling::tau[@string][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[@title="content"][@xml:lang="nb"][@xml:id="id3"]/omicron[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/phi[@attr][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::zeta[@false][@xml:lang="nb"]//eta[@xml:id="id5"][not(preceding-sibling::*)]//mu[@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:id="id7"][preceding-sibling::*[position() = 1]]/delta[@xml:lang="no"][not(following-sibling::*)]//nu[contains(concat(@title,"$"),"this.nodeValue$")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda//nu[@att][@xml:id="id9"][not(preceding-sibling::*)][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <omega title="true" xml:id="id1"> + <psi title="100%" xml:lang="en-GB"> + <alpha/> + <tau string="this-is-att-value" xml:lang="en" xml:id="id2"> + <iota title="content" xml:lang="nb" xml:id="id3"> + <omicron xml:lang="nb"> + <phi attr="attribute-value" xml:id="id4"/> + <zeta false="another attribute value" xml:lang="nb"> + <eta xml:id="id5"> + <mu xml:lang="no-nb" xml:id="id6"/> + <alpha xml:id="id7"> + <delta xml:lang="no"> + <nu title="this.nodeValue" xml:id="id8"> + <lambda> + <nu att="solid 1px green" xml:id="id9"> + <green>This text must be green</green> + </nu> + </lambda> + </nu> + </delta> + </alpha> + </eta> + </zeta> + </omicron> + </iota> + </tau> + </psi> + </omega> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:id="id1"]//sigma[not(preceding-sibling::*)]//*[contains(concat(@attribute,"$"),"e$")][@xml:lang="nb"][@xml:id="id2"][not(following-sibling::*)]/zeta[not(preceding-sibling::*)]//iota[@xml:lang="en-GB"][following-sibling::xi[@xml:lang="nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][not(following-sibling::rho)]//rho[starts-with(@src,"attribu")][not(preceding-sibling::*)][following-sibling::*[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//upsilon[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::iota[@xml:id="id5"]/psi[@xml:id="id6"][following-sibling::mu[not(following-sibling::*)]//kappa[@src="attribute value"][@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::omicron[starts-with(concat(@false,"-"),"true-")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[not(child::node())][following-sibling::gamma[starts-with(@insert,"a")][@xml:id="id8"][not(following-sibling::*)]//zeta[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[starts-with(@attribute,"fal")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[@xml:lang="no"][not(following-sibling::*)]/sigma[starts-with(@src,"another")][following-sibling::*[position()=1]][following-sibling::delta//phi[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:id="id1"> + <sigma> + <any attribute="this-is-att-value" xml:lang="nb" xml:id="id2"> + <zeta> + <iota xml:lang="en-GB"/> + <xi xml:lang="nb" xml:id="id3"/> + <rho xml:lang="en-GB"> + <rho src="attribute value"/> + <any xml:lang="en"> + <upsilon xml:lang="no-nb" xml:id="id4"/> + <iota xml:id="id5"> + <psi xml:id="id6"/> + <mu> + <kappa src="attribute value" xml:lang="nb"/> + <omicron false="true" xml:id="id7"> + <tau/> + <gamma insert="another attribute value" xml:id="id8"> + <zeta xml:lang="nb"> + <zeta xml:lang="nb"/> + <any attribute="false"/> + <omicron xml:lang="no"> + <sigma src="another attribute value"/> + <delta> + <phi xml:lang="no"> + <green>This text must be green</green> + </phi> + </delta> + </omicron> + </zeta> + </gamma> + </omicron> + </mu> + </iota> + </any> + </rho> + </zeta> + </any> + </sigma> + </epsilon> + </tree> + </test> + <test> + <xpath>//delta[starts-with(@content,"_bl")]//eta[@xml:lang="nb"][following-sibling::*[position()=3]][following-sibling::lambda[@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::kappa[starts-with(concat(@string,"-"),"false-")][@xml:id="id2"][following-sibling::xi[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/zeta[following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[contains(concat(@attr,"$"),"se$")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[starts-with(concat(@object,"-"),"content-")][@xml:lang="nb"][not(following-sibling::*)]/theta[not(preceding-sibling::*)][following-sibling::chi[@src][@xml:id="id5"]/kappa[@data][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@number][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::xi[@true][preceding-sibling::*[position() = 2]][not(preceding-sibling::xi)][following-sibling::upsilon[@xml:id="id7"][following-sibling::omicron[@xml:lang="nb"]/lambda[@xml:lang="en-GB"][@xml:id="id8"]/zeta[@xml:id="id9"]/epsilon[@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[contains(concat(@title,"$"),"k$")][@xml:lang="en-US"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <delta content="_blank"> + <eta xml:lang="nb"/> + <lambda xml:id="id1"/> + <kappa string="false" xml:id="id2"/> + <xi xml:lang="no-nb" xml:id="id3"> + <zeta/> + <epsilon attr="false" xml:lang="no" xml:id="id4"> + <chi object="content" xml:lang="nb"> + <theta/> + <chi src="true" xml:id="id5"> + <kappa data="123456789" xml:lang="en" xml:id="id6"/> + <beta number="solid 1px green"/> + <xi true="123456789"/> + <upsilon xml:id="id7"/> + <omicron xml:lang="nb"> + <lambda xml:lang="en-GB" xml:id="id8"> + <zeta xml:id="id9"> + <epsilon xml:lang="no-nb" xml:id="id10"> + <xi title="_blank" xml:lang="en-US"> + <green>This text must be green</green> + </xi> + </epsilon> + </zeta> + </lambda> + </omicron> + </chi> + </chi> + </epsilon> + </xi> + </delta> + </tree> + </test> + <test> + <xpath>//chi[@string][@xml:lang="en"]/mu[starts-with(@and,"th")][@xml:lang="en-US"]/alpha[starts-with(@src,"1234567")][@xml:id="id1"][not(preceding-sibling::*)]/nu[@xml:lang="en"][@xml:id="id2"][following-sibling::upsilon[@content][@xml:id="id3"][following-sibling::tau[following-sibling::*[position()=1]][following-sibling::delta[@string][@xml:lang="en-US"][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <chi string="this-is-att-value" xml:lang="en"> + <mu and="this.nodeValue" xml:lang="en-US"> + <alpha src="123456789" xml:id="id1"> + <nu xml:lang="en" xml:id="id2"/> + <upsilon content="attribute" xml:id="id3"/> + <tau/> + <delta string="solid 1px green" xml:lang="en-US"> + <green>This text must be green</green> + </delta> + </alpha> + </mu> + </chi> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-US"][@xml:id="id1"]/kappa[@attribute="this.nodeValue"][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::epsilon[starts-with(concat(@att,"-"),"solid 1px green-")][@xml:id="id2"]/alpha[@xml:lang="no"][@xml:id="id3"][following-sibling::omicron[not(following-sibling::*)]//psi[@xml:id="id4"][not(preceding-sibling::*)]//theta[contains(@false,"nod")][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(@desciption,"00%")][@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omega[starts-with(@att,"another")][@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[starts-with(@number,"1")][@xml:id="id7"][not(following-sibling::*)]//upsilon[contains(@token,"co")][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::lambda[@false="content"][preceding-sibling::*[position() = 1]]/beta[@att][@xml:lang="en-US"][not(child::node())][following-sibling::beta[@xml:lang="no"][not(following-sibling::*)]//rho[contains(concat(@attribute,"$"),"ntent$")][@xml:lang="nb"]/*[@xml:lang="nb"][following-sibling::iota[@token="this.nodeValue"][preceding-sibling::*[position() = 1]]//omicron[@false="123456789"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[following-sibling::mu[contains(@true,"nt")][@xml:id="id9"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(preceding-sibling::mu)]/upsilon[@object][not(preceding-sibling::*)]/beta[contains(@and,"true")][@xml:lang="nb"][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-US" xml:id="id1"> + <kappa attribute="this.nodeValue" xml:lang="en-US"/> + <epsilon att="solid 1px green" xml:id="id2"> + <alpha xml:lang="no" xml:id="id3"/> + <omicron> + <psi xml:id="id4"> + <theta false="this.nodeValue" xml:id="id5"/> + <theta/> + <delta desciption="100%" xml:lang="nb"> + <omega att="another attribute value" xml:lang="en" xml:id="id6"> + <pi number="100%" xml:id="id7"> + <upsilon token="content" xml:id="id8"/> + <lambda false="content"> + <beta att="content" xml:lang="en-US"/> + <beta xml:lang="no"> + <rho attribute="content" xml:lang="nb"> + <any xml:lang="nb"/> + <iota token="this.nodeValue"> + <omicron false="123456789"/> + <epsilon/> + <mu true="content" xml:id="id9"> + <upsilon object="123456789"> + <beta and="true" xml:lang="nb"> + <green>This text must be green</green> + </beta> + </upsilon> + </mu> + </iota> + </rho> + </beta> + </lambda> + </pi> + </omega> + </delta> + </psi> + </omicron> + </epsilon> + </phi> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]/lambda[@xml:id="id2"]//omega[contains(concat(@attribute,"$"),"23456789$")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::gamma[contains(concat(@attribute,"$"),"lank$")][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]]/chi[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[@attr][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <lambda xml:id="id2"> + <omega attribute="123456789" xml:lang="no-nb"/> + <gamma attribute="_blank" xml:lang="en-US" xml:id="id3"> + <chi xml:lang="en-US" xml:id="id4"/> + <epsilon attr="100%" xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </epsilon> + </gamma> + </lambda> + </mu> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="no"][@xml:id="id1"]//upsilon[@xml:lang="no"][not(preceding-sibling::*)]/beta[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id3"][following-sibling::delta[@content][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]]//mu[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::mu[@token="true"][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@attrib][@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)]/omega[contains(concat(@title,"$"),"se$")][@xml:lang="en-US"][@xml:id="id6"]/xi[@xml:id="id7"]/theta[contains(concat(@attr,"$"),"lue$")][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)]//sigma[@xml:lang="no-nb"][not(child::node())][following-sibling::lambda[@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::xi[@and][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/*[starts-with(@src,"true")][@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="en-GB"][@xml:id="id11"][not(preceding-sibling::phi or following-sibling::phi)]/zeta[not(preceding-sibling::*)]//xi[@xml:lang="en-US"][not(child::node())][following-sibling::gamma[@true="content"][@xml:lang="no-nb"][@xml:id="id12"][preceding-sibling::*[position() = 1]]//beta[@xml:lang="en-GB"][@xml:id="id13"]//chi[@xml:lang="en-US"][not(following-sibling::*)]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>1</nth> + </result> + <tree> + <omega xml:lang="no" xml:id="id1"> + <upsilon xml:lang="no"> + <beta xml:id="id2"> + <upsilon xml:id="id3"/> + <delta content="_blank" xml:lang="nb" xml:id="id4"> + <mu xml:lang="en"/> + <mu token="true" xml:lang="en-US"/> + <nu attrib="100%" xml:lang="no-nb" xml:id="id5"> + <omega title="false" xml:lang="en-US" xml:id="id6"> + <xi xml:id="id7"> + <theta attr="this-is-att-value" xml:lang="no" xml:id="id8"> + <sigma xml:lang="no-nb"/> + <lambda xml:id="id9"/> + <xi and="100%" xml:lang="no-nb"> + <any src="true" xml:lang="en" xml:id="id10"/> + <phi xml:lang="en-GB" xml:id="id11"> + <zeta> + <xi xml:lang="en-US"/> + <gamma true="content" xml:lang="no-nb" xml:id="id12"> + <beta xml:lang="en-GB" xml:id="id13"> + <chi xml:lang="en-US"> + <green>This text must be green</green> + </chi> + </beta> + </gamma> + </zeta> + </phi> + </xi> + </theta> + </xi> + </omega> + </nu> + </delta> + </beta> + </upsilon> + </omega> + </tree> + </test> + <test> + <xpath>//theta[contains(concat(@insert,"$"),"attribute$")][@xml:lang="nb"][@xml:id="id1"]//kappa[not(following-sibling::*)]//theta[@xml:lang="en-US"]//chi[@xml:id="id2"]/*[@name][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]//mu[not(child::node())][following-sibling::iota[@insert][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::kappa[contains(@insert,"al")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/pi[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@true][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::alpha[@xml:id="id7"]/chi[@xml:lang="no-nb"]//xi[@true][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <theta insert="attribute" xml:lang="nb" xml:id="id1"> + <kappa> + <theta xml:lang="en-US"> + <chi xml:id="id2"> + <any name="this-is-att-value" xml:lang="en-US"> + <pi xml:lang="en-GB" xml:id="id3"/> + <theta xml:lang="en-US" xml:id="id4"> + <mu/> + <iota insert="true" xml:id="id5"/> + <kappa insert="false"> + <pi xml:lang="en-US"/> + <iota true="attribute value" xml:id="id6"/> + <alpha xml:id="id7"> + <chi xml:lang="no-nb"> + <xi true="attribute-value" xml:lang="no-nb"> + <green>This text must be green</green> + </xi> + </chi> + </alpha> + </kappa> + </theta> + </any> + </chi> + </theta> + </kappa> + </theta> + </tree> + </test> + <test> + <xpath>//psi[@xml:lang="no-nb"]//mu[starts-with(concat(@content,"-"),"attribute value-")][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[@class="attribute-value"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@xml:lang="en"][following-sibling::*[position()=3]][following-sibling::upsilon[following-sibling::*[position()=2]][not(child::node())][following-sibling::*[@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta//xi[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="no-nb"][not(following-sibling::*)]/zeta[not(preceding-sibling::*)]/kappa[not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <psi xml:lang="no-nb"> + <mu content="attribute value"/> + <chi xml:lang="en-GB" xml:id="id1"> + <rho class="attribute-value" xml:id="id2"> + <alpha xml:lang="en"/> + <upsilon/> + <any xml:id="id3"/> + <theta> + <xi xml:lang="en-GB" xml:id="id4"> + <zeta xml:lang="no-nb"/> + <delta xml:lang="no-nb"> + <zeta> + <kappa> + <green>This text must be green</green> + </kappa> + </zeta> + </delta> + </xi> + </theta> + </rho> + </chi> + </psi> + </tree> + </test> + <test> + <xpath>//lambda[@insert="content"]//omicron[@desciption][@xml:lang="en-GB"][@xml:id="id1"]/zeta[starts-with(concat(@delete,"-"),"true-")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(preceding-sibling::zeta)]//iota[@content][@xml:lang="nb"]/xi[contains(@token,"e")][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@number="_blank"][not(preceding-sibling::*)][not(parent::*/*[position()=2])]/gamma[starts-with(concat(@name,"-"),"true-")][@xml:lang="en"][not(preceding-sibling::*)]/zeta[@att="content"][@xml:lang="no-nb"][@xml:id="id3"]//omega[not(following-sibling::*)]/upsilon[contains(concat(@object,"$")," green$")][@xml:lang="en"][@xml:id="id4"]//*[starts-with(@src,"tr")][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(@and,"anot")][not(following-sibling::*)]//*[contains(@content,"tru")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[contains(concat(@token,"$"),"100%$")][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@data="attribute value"][@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[contains(concat(@insert,"$"),"lank$")][@xml:lang="no"][@xml:id="id9"]//delta[@xml:id="id10"][not(preceding-sibling::*)]/mu[contains(concat(@abort,"$"),"r attribute value$")][not(following-sibling::*)]/omicron[@delete="attribute-value"][@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::pi[contains(@true,"nodeValue")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>1</nth> + </result> + <tree> + <lambda insert="content"> + <omicron desciption="false" xml:lang="en-GB" xml:id="id1"> + <zeta delete="true" xml:lang="en-GB" xml:id="id2"> + <iota content="false" xml:lang="nb"> + <xi token="true"> + <iota number="_blank"> + <gamma name="true" xml:lang="en"> + <zeta att="content" xml:lang="no-nb" xml:id="id3"> + <omega> + <upsilon object="solid 1px green" xml:lang="en" xml:id="id4"> + <any src="true"> + <beta and="another attribute value"> + <any content="true" xml:id="id5"/> + <any xml:lang="no" xml:id="id6"> + <delta token="100%"> + <lambda data="attribute value" xml:lang="no" xml:id="id7"/> + <gamma xml:lang="en" xml:id="id8"> + <xi insert="_blank" xml:lang="no" xml:id="id9"> + <delta xml:id="id10"> + <mu abort="another attribute value"> + <omicron delete="attribute-value" xml:lang="en"/> + <pi true="this.nodeValue" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </mu> + </delta> + </xi> + </gamma> + </delta> + </any> + </beta> + </any> + </upsilon> + </omega> + </zeta> + </gamma> + </iota> + </xi> + </iota> + </zeta> + </omicron> + </lambda> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no"]/delta[not(preceding-sibling::*)][following-sibling::eta[contains(@abort," 1px gr")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[starts-with(@object,"1")][@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[contains(concat(@title,"$"),"te value$")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@and][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]/rho[contains(@attribute,"onten")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta/omicron[@delete="this-is-att-value"][following-sibling::*[position()=3]][following-sibling::omicron[@object="123456789"][@xml:lang="en"][@xml:id="id3"][following-sibling::epsilon[following-sibling::nu[starts-with(concat(@attrib,"-"),"false-")][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][not(preceding-sibling::nu)]//omicron[@xml:lang="en-GB"][@xml:id="id5"][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no"> + <delta/> + <eta abort="solid 1px green" xml:lang="en"/> + <any> + <alpha object="123456789" xml:lang="nb" xml:id="id1"/> + <eta xml:lang="no"> + <eta title="another attribute value" xml:lang="no"> + <xi and="100%" xml:lang="en-GB" xml:id="id2"> + <rho attribute="content" xml:lang="en"/> + <delta> + <omicron delete="this-is-att-value"/> + <omicron object="123456789" xml:lang="en" xml:id="id3"/> + <epsilon/> + <nu attrib="false" xml:id="id4"> + <omicron xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </omicron> + </nu> + </delta> + </xi> + </eta> + </eta> + </any> + </tau> + </tree> + </test> + <test> + <xpath>//omicron[@xml:id="id1"]/beta[not(preceding-sibling::*)][following-sibling::kappa[starts-with(@content,"this-is-att-v")][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/alpha//alpha[not(following-sibling::*)]/eta[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@content][following-sibling::epsilon[@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[@xml:id="id5"][preceding-sibling::*[position() = 2]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omicron xml:id="id1"> + <beta/> + <kappa content="this-is-att-value" xml:lang="nb" xml:id="id2"> + <alpha> + <alpha> + <eta xml:lang="no-nb" xml:id="id3"> + <kappa content="solid 1px green"/> + <epsilon xml:lang="nb" xml:id="id4"/> + <omega xml:id="id5"> + <green>This text must be green</green> + </omega> + </eta> + </alpha> + </alpha> + </kappa> + </omicron> + </tree> + </test> + <test> + <xpath>//phi//theta[starts-with(concat(@true,"-"),"content-")][not(child::node())][following-sibling::epsilon[@xml:id="id1"][not(child::node())][following-sibling::psi[not(child::node())][following-sibling::chi[starts-with(concat(@data,"-"),"another attribute value-")][@xml:lang="en-US"][@xml:id="id2"]//rho[@token][@xml:lang="en"]//omicron[@attribute="attribute"][not(following-sibling::*)]//chi[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::theta[contains(concat(@and,"$"),"ttribute value$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@and][@xml:lang="no-nb"]/eta[@number="content"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::omega[contains(@abort,"nt")][preceding-sibling::*[position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <phi> + <theta true="content"/> + <epsilon xml:id="id1"/> + <psi/> + <chi data="another attribute value" xml:lang="en-US" xml:id="id2"> + <rho token="this-is-att-value" xml:lang="en"> + <omicron attribute="attribute"> + <chi xml:lang="no-nb" xml:id="id3"/> + <theta and="attribute value"> + <nu and="true" xml:lang="no-nb"> + <eta number="content" xml:id="id4"/> + <omega abort="content"> + <green>This text must be green</green> + </omega> + </nu> + </theta> + </omicron> + </rho> + </chi> + </phi> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-GB"][@xml:id="id1"]//xi[starts-with(@content,"tru")][following-sibling::chi[@src][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[starts-with(@attribute,"solid 1")][@xml:lang="nb"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::eta[starts-with(@or,"1234")][preceding-sibling::*[position() = 4]]//rho[@xml:lang="no-nb"][not(following-sibling::*)]//omega[starts-with(@or,"1234")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id5"]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-GB" xml:id="id1"> + <xi content="true"/> + <chi src="true" xml:lang="en"/> + <rho attribute="solid 1px green" xml:lang="nb" xml:id="id2"/> + <iota xml:lang="en-US" xml:id="id3"/> + <eta or="123456789"> + <rho xml:lang="no-nb"> + <omega or="123456789" xml:lang="en-GB" xml:id="id4"/> + <upsilon xml:id="id5"> + <green>This text must be green</green> + </upsilon> + </rho> + </eta> + </any> + </tree> + </test> + <test> + <xpath>//gamma[@or="this-is-att-value"]//chi[@xml:lang="no"][following-sibling::lambda[@xml:lang="no-nb"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::gamma[@and="attribute"][@xml:lang="en"][@xml:id="id2"]/epsilon[following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[starts-with(@false,"f")][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[starts-with(concat(@abort,"-"),"false-")][not(child::node())][following-sibling::theta[contains(@name,"k")][@xml:id="id4"][not(following-sibling::*)]/chi[@xml:lang="no"][@xml:id="id5"][not(following-sibling::*)]//phi[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[@xml:id="id6"][not(child::node())][following-sibling::delta[@xml:id="id7"]/alpha[contains(@object,"r attribute ")][@xml:lang="no"][not(preceding-sibling::*)]/upsilon[@xml:lang="nb"][not(child::node())][following-sibling::alpha[@xml:id="id8"][preceding-sibling::*[position() = 1]]/pi[starts-with(@object,"thi")][not(following-sibling::*)]/delta[@xml:id="id9"][not(following-sibling::*)]/omega[@xml:id="id10"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <gamma or="this-is-att-value"> + <chi xml:lang="no"/> + <lambda xml:lang="no-nb" xml:id="id1"/> + <gamma and="attribute" xml:lang="en" xml:id="id2"> + <epsilon/> + <gamma false="false" xml:lang="en" xml:id="id3"> + <rho abort="false"/> + <theta name="_blank" xml:id="id4"> + <chi xml:lang="no" xml:id="id5"> + <phi xml:lang="no"/> + <any xml:id="id6"/> + <delta xml:id="id7"> + <alpha object="another attribute value" xml:lang="no"> + <upsilon xml:lang="nb"/> + <alpha xml:id="id8"> + <pi object="this-is-att-value"> + <delta xml:id="id9"> + <omega xml:id="id10"> + <green>This text must be green</green> + </omega> + </delta> + </pi> + </alpha> + </alpha> + </delta> + </chi> + </theta> + </gamma> + </gamma> + </gamma> + </tree> + </test> + <test> + <xpath>//zeta[@xml:id="id1"]//phi[contains(concat(@attribute,"$"),"reen$")][@xml:lang="en-US"][not(child::node())][following-sibling::iota[@object][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::lambda[preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[starts-with(@token,"attribute-value")][@xml:id="id3"][not(following-sibling::*)]/rho[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]//xi[not(child::node())][following-sibling::eta[@name][@xml:id="id6"][not(following-sibling::*)]/omicron[@class="attribute-value"][@xml:id="id7"][following-sibling::sigma[starts-with(@attrib,"attribute v")][@xml:lang="en-GB"][not(following-sibling::*)]//omicron[@xml:lang="en"]//upsilon[@abort][not(preceding-sibling::*)][following-sibling::omega[@number][@xml:lang="no"][@xml:id="id8"][following-sibling::nu[contains(concat(@src,"$"),"ibute value$")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//omega[@xml:lang="en-US"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(preceding-sibling::omega)][following-sibling::phi[@xml:lang="no-nb"][@xml:id="id10"][not(following-sibling::*)]//theta[starts-with(concat(@abort,"-"),"attribute-")][@xml:id="id11"]/delta[contains(@desciption,"lue")][not(following-sibling::*)]//omicron[@token][@xml:id="id12"][not(preceding-sibling::*)]/lambda[contains(@number,"reen")][@xml:lang="en-GB"][@xml:id="id13"][following-sibling::lambda[@att][@xml:id="id14"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::epsilon[@delete="solid 1px green"][@xml:lang="en-US"][@xml:id="id15"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/phi[contains(concat(@name,"$")," attribute value$")][@xml:lang="en-GB"][@xml:id="id16"][not(preceding-sibling::*)]]]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:id="id1"> + <phi attribute="solid 1px green" xml:lang="en-US"/> + <iota object="123456789" xml:id="id2"/> + <lambda/> + <epsilon token="attribute-value" xml:id="id3"> + <rho xml:id="id4"> + <phi xml:lang="en-US" xml:id="id5"> + <xi/> + <eta name="this-is-att-value" xml:id="id6"> + <omicron class="attribute-value" xml:id="id7"/> + <sigma attrib="attribute value" xml:lang="en-GB"> + <omicron xml:lang="en"> + <upsilon abort="this-is-att-value"/> + <omega number="attribute" xml:lang="no" xml:id="id8"/> + <nu src="attribute value" xml:lang="en-US"> + <omega xml:lang="en-US" xml:id="id9"/> + <phi xml:lang="no-nb" xml:id="id10"> + <theta abort="attribute-value" xml:id="id11"> + <delta desciption="attribute-value"> + <omicron token="attribute-value" xml:id="id12"> + <lambda number="solid 1px green" xml:lang="en-GB" xml:id="id13"/> + <lambda att="false" xml:id="id14"/> + <epsilon delete="solid 1px green" xml:lang="en-US" xml:id="id15"> + <phi name="another attribute value" xml:lang="en-GB" xml:id="id16"> + <green>This text must be green</green> + </phi> + </epsilon> + </omicron> + </delta> + </theta> + </phi> + </nu> + </omicron> + </sigma> + </eta> + </phi> + </rho> + </epsilon> + </zeta> + </tree> + </test> + <test> + <xpath>//lambda[@src]/nu[not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@attr,"$"),"00%$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/phi[contains(concat(@string,"$"),"s.nodeValue$")][@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@false="_blank"][@xml:id="id2"][not(following-sibling::*)]//iota[@delete][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::xi[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:lang="nb"][not(following-sibling::*)]/delta[starts-with(concat(@object,"-"),"attribute-")][@xml:lang="nb"]/alpha[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::gamma[preceding-sibling::*[position() = 1]]//xi[not(child::node())][following-sibling::iota[starts-with(@number,"this.n")][@xml:lang="no"][@xml:id="id7"][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <lambda src="100%"> + <nu/> + <alpha attr="100%" xml:lang="en-US"> + <phi string="this.nodeValue" xml:lang="no" xml:id="id1"/> + <epsilon false="_blank" xml:id="id2"> + <iota delete="attribute value" xml:lang="no-nb" xml:id="id3"/> + <xi xml:id="id4"> + <nu xml:lang="en" xml:id="id5"/> + <theta xml:lang="nb"> + <delta object="attribute" xml:lang="nb"> + <alpha xml:lang="nb" xml:id="id6"/> + <gamma> + <xi/> + <iota number="this.nodeValue" xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </iota> + </gamma> + </delta> + </theta> + </xi> + </epsilon> + </alpha> + </lambda> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="en"][@xml:id="id1"]//psi[@false][@xml:id="id2"][not(preceding-sibling::*)]//sigma[@xml:id="id3"][not(child::node())][following-sibling::sigma[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[contains(concat(@true,"$"),"r attribute value$")][not(child::node())][following-sibling::psi[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omicron[@and][@xml:lang="en-US"][@xml:id="id6"][not(following-sibling::*)]//chi[@xml:lang="en-US"][not(following-sibling::*)]//epsilon[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@attribute][@xml:id="id8"][not(following-sibling::*)]//iota[contains(@title,"34")][@xml:lang="nb"][@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::phi[starts-with(concat(@attr,"-"),"123456789-")][@xml:lang="en"][@xml:id="id10"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="en" xml:id="id1"> + <psi false="100%" xml:id="id2"> + <sigma xml:id="id3"/> + <sigma xml:lang="no" xml:id="id4"/> + <omicron true="another attribute value"/> + <psi att="attribute-value" xml:lang="no-nb" xml:id="id5"/> + <omicron and="attribute" xml:lang="en-US" xml:id="id6"> + <chi xml:lang="en-US"> + <epsilon xml:lang="en-US" xml:id="id7"> + <any attribute="attribute-value" xml:id="id8"> + <iota title="123456789" xml:lang="nb" xml:id="id9"/> + <phi attr="123456789" xml:lang="en" xml:id="id10"> + <green>This text must be green</green> + </phi> + </any> + </epsilon> + </chi> + </omicron> + </psi> + </iota> + </tree> + </test> + <test> + <xpath>//omega/upsilon[@xml:lang="en"]//zeta[@false][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::nu[starts-with(concat(@content,"-"),"_blank-")][@xml:lang="en-GB"][@xml:id="id2"][following-sibling::mu[following-sibling::*[position()=5]][following-sibling::tau[contains(concat(@false,"$"),"lse$")][@xml:id="id3"][not(child::node())][following-sibling::epsilon[@number][following-sibling::*[position()=3]][not(child::node())][following-sibling::eta[starts-with(@abort,"this.node")][@xml:lang="nb"][@xml:id="id4"][following-sibling::*[position()=2]][following-sibling::iota[@xml:lang="no-nb"][preceding-sibling::*[position() = 6]][following-sibling::beta[@false="attribute value"][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 7]][not(following-sibling::*)]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <upsilon xml:lang="en"> + <zeta false="solid 1px green" xml:id="id1"/> + <nu content="_blank" xml:lang="en-GB" xml:id="id2"/> + <mu/> + <tau false="false" xml:id="id3"/> + <epsilon number="another attribute value"/> + <eta abort="this.nodeValue" xml:lang="nb" xml:id="id4"/> + <iota xml:lang="no-nb"/> + <beta false="attribute value" xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </beta> + </upsilon> + </omega> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="no-nb"][@xml:id="id1"]/chi[contains(@title,"b")][@xml:lang="en-US"][@xml:id="id2"][following-sibling::alpha[starts-with(concat(@token,"-"),"123456789-")][@xml:id="id3"]//eta[starts-with(concat(@abort,"-"),"solid 1px green-")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:lang="nb"][@xml:id="id5"]//*[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@object][@xml:lang="no-nb"][@xml:id="id6"]//nu[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(concat(@false,"$"),"e value$")][preceding-sibling::*[position() = 1]][following-sibling::mu[@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)]//psi[starts-with(@desciption,"1")][following-sibling::pi[@data][@xml:lang="en-US"][@xml:id="id8"][following-sibling::beta[@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 2]]//lambda[@content][@xml:lang="en-GB"][not(preceding-sibling::*)]/lambda[@xml:lang="no-nb"][not(preceding-sibling::*)]]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="no-nb" xml:id="id1"> + <chi title="attribute" xml:lang="en-US" xml:id="id2"/> + <alpha token="123456789" xml:id="id3"> + <eta abort="solid 1px green" xml:lang="en-GB" xml:id="id4"/> + <any xml:lang="nb" xml:id="id5"> + <any xml:lang="nb"> + <iota object="content" xml:lang="no-nb" xml:id="id6"> + <nu xml:lang="en"/> + <kappa false="another attribute value"/> + <mu xml:lang="nb" xml:id="id7"> + <psi desciption="100%"/> + <pi data="100%" xml:lang="en-US" xml:id="id8"/> + <beta xml:lang="en" xml:id="id9"> + <lambda content="_blank" xml:lang="en-GB"> + <lambda xml:lang="no-nb"> + <green>This text must be green</green> + </lambda> + </lambda> + </beta> + </mu> + </iota> + </any> + </any> + </alpha> + </omega> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-US"]//kappa[@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::gamma[contains(concat(@src,"$"),"rue$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::phi//epsilon[@insert][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[contains(@src,"other")][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::beta[@desciption="this-is-att-value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[not(preceding-sibling::*)][not(following-sibling::*)][not(parent::*/*[position()=2])]//pi[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::nu[starts-with(@number,"10")][preceding-sibling::*[position() = 1]]/lambda[contains(@content," value")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-US"> + <kappa xml:id="id1"/> + <gamma src="true" xml:id="id2"/> + <phi> + <epsilon insert="123456789" xml:lang="en" xml:id="id3"/> + <xi src="another attribute value" xml:id="id4"/> + <beta desciption="this-is-att-value"> + <tau> + <pi xml:lang="en-US" xml:id="id5"/> + <nu number="100%"> + <lambda content="another attribute value" xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </lambda> + </nu> + </tau> + </beta> + </phi> + </phi> + </tree> + </test> + <test> + <xpath>//beta[@attrib][@xml:lang="en-US"]//chi[@desciption][@xml:lang="no"][following-sibling::rho[starts-with(@attrib,"this")][@xml:id="id1"][preceding-sibling::*[position() = 1]]//sigma[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@true][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[@delete="attribute value"][@xml:lang="en-GB"][not(preceding-sibling::*)]//omicron[@object="another attribute value"][@xml:lang="en-GB"]/lambda[contains(concat(@token,"$"),"value$")][@xml:lang="en-US"][not(preceding-sibling::*)]//iota[starts-with(concat(@true,"-"),"attribute-")][@xml:id="id3"][following-sibling::lambda[@xml:lang="en-GB"][following-sibling::delta[@data][@xml:id="id4"][preceding-sibling::*[position() = 2]]//chi[@delete="attribute value"][@xml:lang="en-GB"][@xml:id="id5"]/pi[starts-with(concat(@abort,"-"),"true-")][not(following-sibling::*)]//kappa[@xml:lang="nb"][not(following-sibling::*)]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <beta attrib="100%" xml:lang="en-US"> + <chi desciption="true" xml:lang="no"/> + <rho attrib="this-is-att-value" xml:id="id1"> + <sigma xml:id="id2"> + <rho true="_blank" xml:lang="nb"> + <chi delete="attribute value" xml:lang="en-GB"> + <omicron object="another attribute value" xml:lang="en-GB"> + <lambda token="attribute-value" xml:lang="en-US"> + <iota true="attribute" xml:id="id3"/> + <lambda xml:lang="en-GB"/> + <delta data="content" xml:id="id4"> + <chi delete="attribute value" xml:lang="en-GB" xml:id="id5"> + <pi abort="true"> + <kappa xml:lang="nb"> + <green>This text must be green</green> + </kappa> + </pi> + </chi> + </delta> + </lambda> + </omicron> + </chi> + </rho> + </sigma> + </rho> + </beta> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]//iota[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::lambda[contains(concat(@number,"$"),"e$")][@xml:lang="en-GB"][@xml:id="id2"]//sigma[contains(concat(@class,"$"),"ue$")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][following-sibling::pi[preceding-sibling::*[position() = 2]][following-sibling::*[position()=4]][not(child::node())][following-sibling::zeta[starts-with(@data,"th")][@xml:id="id4"][not(child::node())][following-sibling::lambda[starts-with(@title,"this.nodeValu")][@xml:id="id5"][not(child::node())][following-sibling::beta[@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 5]][following-sibling::xi[@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <iota xml:lang="en-GB"/> + <lambda number="this.nodeValue" xml:lang="en-GB" xml:id="id2"> + <sigma class="this.nodeValue" xml:lang="en"/> + <sigma xml:lang="no-nb" xml:id="id3"/> + <pi/> + <zeta data="this.nodeValue" xml:id="id4"/> + <lambda title="this.nodeValue" xml:id="id5"/> + <beta xml:lang="no" xml:id="id6"/> + <xi xml:id="id7"> + <green>This text must be green</green> + </xi> + </lambda> + </alpha> + </tree> + </test> + <test> + <xpath>//delta[@false][@xml:id="id1"]/chi[@true][@xml:lang="en-GB"]//rho[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[not(preceding-sibling::*)][not(following-sibling::tau)]/sigma[contains(@token,"ribut")][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[contains(concat(@name,"$"),"ue$")][@xml:id="id3"]//phi[@xml:id="id4"][not(child::node())][following-sibling::omicron[@xml:id="id5"][not(following-sibling::*)]/delta[@token][@xml:lang="no"]/sigma[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:id="id7"][not(child::node())][following-sibling::sigma[starts-with(concat(@delete,"-"),"true-")][@xml:id="id8"][not(following-sibling::*)]//lambda[@name][@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::iota[contains(@and,"t")][preceding-sibling::*[position() = 1]]/chi[@xml:lang="en-US"][@xml:id="id10"][following-sibling::epsilon[@xml:lang="en"][@xml:id="id11"][not(following-sibling::*)]//omega[@object][not(preceding-sibling::*)][following-sibling::omicron[@xml:id="id12"][preceding-sibling::*[position() = 1]]/phi[@attrib][@xml:lang="en-US"][@xml:id="id13"]//*[contains(@and,"ue")][not(preceding-sibling::*)][not(following-sibling::*)]/*[not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <delta false="content" xml:id="id1"> + <chi true="true" xml:lang="en-GB"> + <rho xml:id="id2"> + <tau> + <sigma token="attribute"> + <epsilon name="true" xml:id="id3"> + <phi xml:id="id4"/> + <omicron xml:id="id5"> + <delta token="this.nodeValue" xml:lang="no"> + <sigma xml:id="id6"> + <sigma xml:id="id7"/> + <sigma delete="true" xml:id="id8"> + <lambda name="this.nodeValue" xml:id="id9"/> + <iota and="content"> + <chi xml:lang="en-US" xml:id="id10"/> + <epsilon xml:lang="en" xml:id="id11"> + <omega object="true"/> + <omicron xml:id="id12"> + <phi attrib="attribute-value" xml:lang="en-US" xml:id="id13"> + <any and="another attribute value"> + <any> + <green>This text must be green</green> + </any> + </any> + </phi> + </omicron> + </epsilon> + </iota> + </sigma> + </sigma> + </delta> + </omicron> + </epsilon> + </sigma> + </tau> + </rho> + </chi> + </delta> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en"]/zeta[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::omicron[starts-with(@false,"this")][following-sibling::gamma[not(following-sibling::*)]//epsilon[@xml:lang="no"]/nu[@xml:lang="nb"][@xml:id="id2"][not(child::node())][following-sibling::*[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)]/lambda[contains(concat(@object,"$"),"e value$")][not(preceding-sibling::*)]//*[starts-with(concat(@attr,"-"),"_blank-")][@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::chi[starts-with(@or,"solid 1px")][@xml:lang="no"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en"> + <zeta xml:lang="en-US" xml:id="id1"/> + <omicron false="this.nodeValue"/> + <gamma> + <epsilon xml:lang="no"> + <nu xml:lang="nb" xml:id="id2"/> + <any xml:id="id3"> + <beta xml:lang="no" xml:id="id4"> + <lambda object="attribute value"> + <any attr="_blank" xml:lang="no" xml:id="id5"/> + <chi or="solid 1px green" xml:lang="no"> + <green>This text must be green</green> + </chi> + </lambda> + </beta> + </any> + </epsilon> + </gamma> + </kappa> + </tree> + </test> + <test> + <xpath>//omega[contains(concat(@src,"$"),"9$")][@xml:id="id1"]/zeta[@xml:id="id2"][not(child::node())][following-sibling::rho[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:lang="no-nb"][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id4"]//tau[@xml:lang="nb"][@xml:id="id5"]//iota[starts-with(@content,"this")][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[contains(@delete,"00%")][@xml:id="id7"][not(child::node())][following-sibling::zeta[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/nu[@xml:lang="en"][@xml:id="id8"][not(following-sibling::*)]/kappa[@attribute][@xml:id="id9"][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][not(following-sibling::*)]/nu[@xml:lang="en-GB"][@xml:id="id10"]//psi[starts-with(@abort,"so")][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::psi[contains(concat(@true,"$"),"00%$")][@xml:id="id12"][following-sibling::*[position()=2]][not(child::node())][following-sibling::eta[@xml:id="id13"][not(child::node())][following-sibling::nu[@or="attribute value"][@xml:lang="en"]][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <omega src="123456789" xml:id="id1"> + <zeta xml:id="id2"/> + <rho xml:id="id3"/> + <phi xml:lang="no-nb"/> + <chi xml:lang="no" xml:id="id4"> + <tau xml:lang="nb" xml:id="id5"> + <iota content="this.nodeValue" xml:id="id6"/> + <beta delete="100%" xml:id="id7"/> + <zeta xml:lang="en"> + <nu xml:lang="en" xml:id="id8"> + <kappa attribute="attribute" xml:id="id9"/> + <zeta xml:lang="en-US"> + <nu xml:lang="en-GB" xml:id="id10"> + <psi abort="solid 1px green" xml:id="id11"/> + <psi true="100%" xml:id="id12"/> + <eta xml:id="id13"/> + <nu or="attribute value" xml:lang="en"> + <green>This text must be green</green> + </nu> + </nu> + </zeta> + </nu> + </zeta> + </tau> + </chi> + </omega> + </tree> + </test> + <test> + <xpath>//beta[contains(concat(@attr,"$"),"00%$")][@xml:lang="no-nb"]/tau[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::tau)]//tau[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:lang="no"][not(child::node())][following-sibling::tau[@title][@xml:lang="nb"]//delta[starts-with(concat(@name,"-"),"this.nodeValue-")][@xml:lang="no"][not(child::node())][following-sibling::theta[not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <beta attr="100%" xml:lang="no-nb"> + <tau xml:lang="no" xml:id="id1"> + <tau xml:lang="en-GB" xml:id="id2"> + <iota xml:lang="en-GB"> + <theta xml:lang="no"/> + <tau title="true" xml:lang="nb"> + <delta name="this.nodeValue" xml:lang="no"/> + <theta> + <green>This text must be green</green> + </theta> + </tau> + </iota> + </tau> + </tau> + </beta> + </tree> + </test> + <test> + <xpath>//xi[@token="content"][@xml:id="id1"]//chi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:lang="en"][@xml:id="id3"]/delta[contains(@attr,"9")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::upsilon[contains(@number,"s")][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::gamma[starts-with(concat(@attr,"-"),"attribute value-")][not(child::node())][following-sibling::tau[starts-with(concat(@title,"-"),"100%-")][preceding-sibling::*[position() = 3]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <xi token="content" xml:id="id1"> + <chi xml:id="id2"> + <beta xml:lang="en" xml:id="id3"> + <delta attr="123456789" xml:lang="en-US" xml:id="id4"/> + <upsilon number="false" xml:id="id5"/> + <gamma attr="attribute value"/> + <tau title="100%"> + <green>This text must be green</green> + </tau> + </beta> + </chi> + </xi> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no-nb"][@xml:id="id1"]/theta[starts-with(@false,"attribute")][@xml:lang="no-nb"][not(following-sibling::*)]/beta[not(child::node())][following-sibling::pi[not(child::node())][following-sibling::alpha[starts-with(@att,"at")][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/tau[@xml:lang="no-nb"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[starts-with(@content,"_blan")][@xml:lang="en"][not(following-sibling::*)]//iota[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/rho[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[contains(@data,"ttribute value")][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@xml:lang="en"][@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::alpha[starts-with(concat(@data,"-"),"123456789-")][@xml:lang="nb"][@xml:id="id6"][following-sibling::omicron[@attribute][@xml:lang="no"][@xml:id="id7"][not(child::node())][following-sibling::zeta[starts-with(@true,"co")][@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="no-nb" xml:id="id1"> + <theta false="attribute" xml:lang="no-nb"> + <beta/> + <pi/> + <alpha att="attribute" xml:id="id2"> + <tau xml:lang="no-nb" xml:id="id3"/> + <theta content="_blank" xml:lang="en"> + <iota xml:lang="en" xml:id="id4"> + <rho xml:lang="no-nb"> + <nu data="another attribute value"/> + <mu xml:lang="en" xml:id="id5"/> + <alpha data="123456789" xml:lang="nb" xml:id="id6"/> + <omicron attribute="false" xml:lang="no" xml:id="id7"/> + <zeta true="content" xml:lang="no-nb" xml:id="id8"> + <green>This text must be green</green> + </zeta> + </rho> + </iota> + </theta> + </alpha> + </theta> + </kappa> + </tree> + </test> + <test> + <xpath>//sigma[@content][@xml:lang="no-nb"]/iota[starts-with(@true,"this-is-att-va")][@xml:id="id1"][following-sibling::phi[contains(concat(@true,"$"),"alue$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::pi[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::omicron[@src][@xml:id="id3"][following-sibling::mu[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 5]]/delta[@data="another attribute value"][following-sibling::*[position()=1]][following-sibling::mu[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <sigma content="attribute" xml:lang="no-nb"> + <iota true="this-is-att-value" xml:id="id1"/> + <phi true="this-is-att-value" xml:lang="en"> + <lambda xml:lang="en-GB"/> + <pi xml:lang="no" xml:id="id2"/> + <omicron src="attribute value" xml:id="id3"/> + <mu xml:lang="en-US" xml:id="id4"/> + <psi xml:lang="no-nb" xml:id="id5"/> + <omicron> + <delta data="another attribute value"/> + <mu xml:lang="no-nb"> + <green>This text must be green</green> + </mu> + </omicron> + </phi> + </sigma> + </tree> + </test> + <test> + <xpath>//mu//beta//zeta[starts-with(@number,"12345678")][not(preceding-sibling::*)]//omega[@xml:lang="no"][not(following-sibling::*)]/pi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::upsilon[contains(concat(@attrib,"$"),"lue$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[contains(concat(@attrib,"$"),"blank$")][preceding-sibling::*[position() = 2]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <beta> + <zeta number="123456789"> + <omega xml:lang="no"> + <pi xml:lang="no-nb"/> + <upsilon attrib="attribute-value" xml:lang="en"/> + <gamma attrib="_blank"> + <green>This text must be green</green> + </gamma> + </omega> + </zeta> + </beta> + </mu> + </tree> + </test> + <test> + <xpath>//theta[@false="solid 1px green"][@xml:lang="nb"]/lambda[starts-with(concat(@desciption,"-"),"123456789-")][@xml:id="id1"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::theta)]//kappa[starts-with(concat(@attrib,"-"),"content-")]//tau[contains(@class,"alse")][@xml:lang="no-nb"][@xml:id="id3"][following-sibling::omega[@xml:id="id4"][not(child::node())][following-sibling::*[@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[@class][not(child::node())][following-sibling::omicron[contains(@attrib,"te")][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 4]]/phi[@string][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::mu[contains(concat(@string,"$"),"this-is-att-value$")][preceding-sibling::*[position() = 1]]][position() = 1]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <theta false="solid 1px green" xml:lang="nb"> + <lambda desciption="123456789" xml:id="id1"/> + <theta xml:lang="en-GB" xml:id="id2"> + <kappa attrib="content"> + <tau class="false" xml:lang="no-nb" xml:id="id3"/> + <omega xml:id="id4"/> + <any xml:lang="en" xml:id="id5"/> + <omicron class="another attribute value"/> + <omicron attrib="another attribute value" xml:lang="no" xml:id="id6"> + <phi string="this.nodeValue" xml:lang="en" xml:id="id7"/> + <epsilon xml:lang="no-nb" xml:id="id8"> + <nu xml:id="id9"/> + <mu string="this-is-att-value"> + <green>This text must be green</green> + </mu> + </epsilon> + </omicron> + </kappa> + </theta> + </theta> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="nb"]//upsilon[@xml:lang="en-GB"][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][not(child::node())][following-sibling::rho[starts-with(concat(@content,"-"),"solid 1px green-")][@xml:lang="en-GB"][not(following-sibling::*)]/delta[starts-with(concat(@attrib,"-"),"_blank-")][@xml:lang="no-nb"]/chi[contains(@insert,"s-att-val")][@xml:lang="en"][@xml:id="id1"][not(child::node())][following-sibling::delta[@attrib="123456789"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omega[contains(concat(@false,"$"),"nt$")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]]//psi[@xml:id="id4"][following-sibling::kappa[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]]/iota[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::zeta[contains(@attribute,"7")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::upsilon[@xml:lang="nb"][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[following-sibling::*[not(following-sibling::*)]/epsilon[@xml:lang="en-US"][following-sibling::eta[not(child::node())][following-sibling::phi[@attrib][following-sibling::delta[@attribute][@xml:lang="nb"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="nb"> + <upsilon xml:lang="en-GB"/> + <sigma xml:lang="no-nb"/> + <rho content="solid 1px green" xml:lang="en-GB"> + <delta attrib="_blank" xml:lang="no-nb"> + <chi insert="this-is-att-value" xml:lang="en" xml:id="id1"/> + <delta attrib="123456789" xml:id="id2"/> + <omega false="content" xml:lang="no" xml:id="id3"> + <psi xml:id="id4"/> + <kappa xml:lang="no-nb"> + <iota xml:id="id5"/> + <zeta attribute="123456789"/> + <upsilon xml:lang="nb"/> + <rho/> + <any> + <epsilon xml:lang="en-US"/> + <eta/> + <phi attrib="this.nodeValue"/> + <delta attribute="content" xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </delta> + </any> + </kappa> + </omega> + </delta> + </rho> + </omega> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="en-GB"]//psi[@attr][@xml:id="id1"][not(preceding-sibling::*)]//omicron[@number][not(following-sibling::*)][not(following-sibling::omicron)]/kappa[@token][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/delta[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/phi[@class="this.nodeValue"][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::upsilon)]//eta[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::epsilon[starts-with(concat(@token,"-"),"attribute-")][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/iota][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="en-GB"> + <psi attr="another attribute value" xml:id="id1"> + <omicron number="false"> + <kappa token="attribute value" xml:lang="no"> + <delta xml:lang="en-US" xml:id="id2"> + <phi class="this.nodeValue" xml:lang="nb"/> + <upsilon xml:lang="no-nb" xml:id="id3"> + <eta xml:id="id4"/> + <epsilon token="attribute" xml:id="id5"/> + <omicron xml:lang="en-US" xml:id="id6"> + <iota> + <green>This text must be green</green> + </iota> + </omicron> + </upsilon> + </delta> + </kappa> + </omicron> + </psi> + </theta> + </tree> + </test> + <test> + <xpath>//mu[contains(@content,"ibute")]//upsilon[@xml:id="id1"]//omega[starts-with(@string,"c")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::kappa[@xml:id="id3"][not(preceding-sibling::kappa)]//iota[@xml:id="id4"][not(preceding-sibling::*)]/xi[not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <mu content="attribute"> + <upsilon xml:id="id1"> + <omega string="content" xml:id="id2"/> + <kappa xml:id="id3"> + <iota xml:id="id4"> + <xi> + <green>This text must be green</green> + </xi> + </iota> + </kappa> + </upsilon> + </mu> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="no-nb"]//alpha[starts-with(concat(@name,"-"),"attribute value-")][@xml:id="id1"][not(child::node())][following-sibling::pi[@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::zeta[@attr][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//lambda[contains(concat(@src,"$"),"ttribute value$")][@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::*[@xml:lang="en"]//phi[@delete][@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::phi[@xml:id="id4"]/beta[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::beta[starts-with(concat(@and,"-"),"this.nodeValue-")][following-sibling::*[position()=2]][following-sibling::chi[contains(concat(@data,"$"),"ttribute value$")][not(child::node())][following-sibling::epsilon[@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//*[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[@xml:lang="en-US"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="no-nb"> + <alpha name="attribute value" xml:id="id1"/> + <pi xml:id="id2"/> + <zeta attr="true" xml:lang="no-nb"> + <lambda src="another attribute value" xml:lang="en-GB"/> + <any xml:lang="en"> + <phi delete="100%" xml:lang="no" xml:id="id3"/> + <phi xml:id="id4"> + <beta xml:id="id5"/> + <beta and="this.nodeValue"/> + <chi data="attribute value"/> + <epsilon xml:id="id6"> + <any xml:id="id7"/> + <any xml:lang="en-US" xml:id="id8"> + <green>This text must be green</green> + </any> + </epsilon> + </phi> + </any> + </zeta> + </sigma> + </tree> + </test> + <test> + <xpath>//mu//mu[@insert][@xml:lang="nb"][@xml:id="id1"]//phi[@xml:id="id2"][not(child::node())][following-sibling::mu[@content][@xml:id="id3"][following-sibling::tau[preceding-sibling::*[position() = 2]]//epsilon[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::*[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::rho[@name][@xml:id="id4"][not(following-sibling::*)][not(preceding-sibling::rho)]/tau[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::gamma[@content][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <mu> + <mu insert="false" xml:lang="nb" xml:id="id1"> + <phi xml:id="id2"/> + <mu content="attribute" xml:id="id3"/> + <tau> + <epsilon xml:lang="en"/> + <any xml:lang="en"/> + <rho name="content" xml:id="id4"> + <tau xml:lang="no-nb"/> + <gamma content="another attribute value" xml:lang="nb"> + <green>This text must be green</green> + </gamma> + </rho> + </tau> + </mu> + </mu> + </tree> + </test> + <test> + <xpath>//beta/alpha[starts-with(concat(@false,"-"),"123456789-")][@xml:lang="no-nb"][not(child::node())][following-sibling::phi[@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:lang="nb"][not(following-sibling::*)][not(preceding-sibling::theta)]/omega[contains(@token,"ue")][not(preceding-sibling::*)]/zeta[starts-with(@title,"t")][not(following-sibling::*)]/kappa[@data="attribute"][following-sibling::rho[@xml:lang="no"][not(child::node())][following-sibling::delta[@xml:id="id2"][preceding-sibling::*[position() = 2]]//delta[@number][@xml:lang="en-GB"][not(preceding-sibling::*)]//theta[@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:id="id5"][not(following-sibling::*)]//eta[@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:lang="nb"][not(following-sibling::*)]/eta[@xml:lang="nb"]//xi[@xml:id="id6"][following-sibling::eta[@xml:lang="no-nb"][not(child::node())][following-sibling::delta[@delete="this-is-att-value"][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::delta)][following-sibling::mu[starts-with(concat(@true,"-"),"solid 1px green-")][preceding-sibling::*[position() = 3]]][position() = 1]]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <beta> + <alpha false="123456789" xml:lang="no-nb"/> + <phi xml:id="id1"/> + <theta xml:lang="nb"> + <omega token="this-is-att-value"> + <zeta title="true"> + <kappa data="attribute"/> + <rho xml:lang="no"/> + <delta xml:id="id2"> + <delta number="attribute value" xml:lang="en-GB"> + <theta xml:lang="en" xml:id="id3"> + <sigma xml:lang="no" xml:id="id4"/> + <beta xml:id="id5"> + <eta xml:lang="en"/> + <psi xml:lang="nb"> + <eta xml:lang="nb"> + <xi xml:id="id6"/> + <eta xml:lang="no-nb"/> + <delta delete="this-is-att-value" xml:lang="no"/> + <mu true="solid 1px green"> + <green>This text must be green</green> + </mu> + </eta> + </psi> + </beta> + </theta> + </delta> + </delta> + </zeta> + </omega> + </theta> + </beta> + </tree> + </test> + <test> + <xpath>//*/theta[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/rho[starts-with(concat(@src,"-"),"100%-")]/iota[@delete][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]//chi/sigma[@or][@xml:lang="en-US"][following-sibling::omicron[contains(@attrib,"lue")][preceding-sibling::*[position() = 1]]/chi[not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="no"][following-sibling::*[position()=3]][following-sibling::upsilon[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::pi[@attribute][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[contains(@delete,"00%")][not(following-sibling::*)]//omicron[@xml:lang="en-US"][@xml:id="id3"][following-sibling::beta[@insert][@xml:id="id4"][not(child::node())][following-sibling::epsilon[contains(concat(@token,"$"),"e$")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]]//epsilon[@xml:lang="no-nb"][not(preceding-sibling::*)]/chi[contains(concat(@and,"$"),"ank$")][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(@name,"nt")][@xml:lang="en-GB"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::omicron)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <any> + <theta xml:lang="en" xml:id="id1"> + <rho src="100%"> + <iota delete="123456789" xml:lang="en" xml:id="id2"> + <chi> + <sigma or="100%" xml:lang="en-US"/> + <omicron attrib="attribute-value"> + <chi> + <rho xml:lang="no"/> + <upsilon xml:lang="en-GB"/> + <pi attribute="attribute-value"/> + <tau delete="100%"> + <omicron xml:lang="en-US" xml:id="id3"/> + <beta insert="false" xml:id="id4"/> + <epsilon token="attribute-value" xml:lang="en-US" xml:id="id5"> + <epsilon xml:lang="no-nb"> + <chi and="_blank"/> + <omicron name="content" xml:lang="en-GB" xml:id="id6"> + <green>This text must be green</green> + </omicron> + </epsilon> + </epsilon> + </tau> + </chi> + </omicron> + </chi> + </iota> + </rho> + </theta> + </any> + </tree> + </test> + <test> + <xpath>//omega[@xml:lang="en"]/upsilon[@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)]//mu[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[starts-with(@attribute,"att")][@xml:id="id3"][not(following-sibling::*)]/lambda[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::zeta[contains(concat(@true,"$"),"lue$")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/beta[starts-with(concat(@src,"-"),"another attribute value-")][not(preceding-sibling::*)][following-sibling::mu//tau[not(following-sibling::*)]//sigma[@xml:lang="en-GB"][not(preceding-sibling::*)]/pi[starts-with(concat(@attrib,"-"),"_blank-")][@xml:lang="nb"][not(following-sibling::*)]/iota[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-GB"][not(following-sibling::*)]/phi[@xml:lang="en-US"]//omega[@data][@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]//omega[contains(@desciption,"lue")][@xml:id="id10"][not(preceding-sibling::*)]/nu[contains(concat(@desciption,"$"),"deValue$")][@xml:lang="no"][following-sibling::delta[@xml:id="id11"][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id12"][following-sibling::iota[starts-with(concat(@string,"-"),"attribute-")][preceding-sibling::*[position() = 3]][following-sibling::upsilon[@xml:id="id13"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:lang="en"> + <upsilon xml:lang="no-nb" xml:id="id1"> + <mu xml:id="id2"/> + <chi/> + <chi attribute="attribute value" xml:id="id3"> + <lambda xml:lang="en-US" xml:id="id4"/> + <zeta true="attribute value" xml:id="id5"> + <zeta xml:id="id6"/> + <epsilon xml:id="id7"> + <beta src="another attribute value"/> + <mu> + <tau> + <sigma xml:lang="en-GB"> + <pi attrib="_blank" xml:lang="nb"> + <iota xml:lang="en-GB" xml:id="id8"/> + <theta xml:lang="en-GB"> + <phi xml:lang="en-US"> + <omega data="_blank" xml:lang="en" xml:id="id9"> + <omega desciption="attribute-value" xml:id="id10"> + <nu desciption="this.nodeValue" xml:lang="no"/> + <delta xml:id="id11"/> + <upsilon xml:lang="en-GB" xml:id="id12"/> + <iota string="attribute-value"/> + <upsilon xml:id="id13"> + <green>This text must be green</green> + </upsilon> + </omega> + </omega> + </phi> + </theta> + </pi> + </sigma> + </tau> + </mu> + </epsilon> + </zeta> + </chi> + </upsilon> + </omega> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="nb"]/epsilon[not(following-sibling::*)]/omega[starts-with(concat(@title,"-"),"false-")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[contains(concat(@delete,"$"),"e-value$")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]//lambda[contains(concat(@attribute,"$"),"is-att-value$")][@xml:id="id3"][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"]/chi[@or][not(following-sibling::*)]/delta[contains(concat(@desciption,"$"),"bute value$")][@xml:lang="en-GB"][@xml:id="id4"]//gamma[not(preceding-sibling::*)]/chi[@content][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@number,"$"),"blank$")][@xml:id="id5"][preceding-sibling::*[position() = 1]]/pi[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(@false,"attribute val")][not(following-sibling::*)]//alpha[contains(concat(@object,"$"),"ank$")][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@attrib="this.nodeValue"][@xml:lang="nb"][not(preceding-sibling::*)]//rho[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="nb"> + <epsilon> + <omega title="false" xml:id="id1"> + <mu delete="attribute-value" xml:lang="en"/> + <alpha xml:lang="no" xml:id="id2"> + <lambda attribute="this-is-att-value" xml:id="id3"/> + <kappa xml:lang="no-nb"> + <chi or="true"> + <delta desciption="attribute value" xml:lang="en-GB" xml:id="id4"> + <gamma> + <chi content="attribute" xml:lang="no"/> + <sigma number="_blank" xml:id="id5"> + <pi xml:lang="en-GB" xml:id="id6"/> + <upsilon false="attribute value"> + <alpha object="_blank"> + <rho attrib="this.nodeValue" xml:lang="nb"> + <rho xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </rho> + </rho> + </alpha> + </upsilon> + </sigma> + </gamma> + </delta> + </chi> + </kappa> + </alpha> + </omega> + </epsilon> + </upsilon> + </tree> + </test> + <test> + <xpath>//eta[@insert][@xml:lang="no-nb"]/omega[@xml:lang="en-US"][not(preceding-sibling::*)]/chi[@false="this.nodeValue"][@xml:id="id1"]//xi[@xml:id="id2"][following-sibling::omicron[starts-with(@att,"attribute-value")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omicron[@content="true"][preceding-sibling::*[position() = 2]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <eta insert="false" xml:lang="no-nb"> + <omega xml:lang="en-US"> + <chi false="this.nodeValue" xml:id="id1"> + <xi xml:id="id2"/> + <omicron att="attribute-value"/> + <omicron content="true"> + <green>This text must be green</green> + </omicron> + </chi> + </omega> + </eta> + </tree> + </test> + <test> + <xpath>//pi/chi[@data][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::omega[@xml:id="id2"][not(child::node())][following-sibling::beta[@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id4"][not(following-sibling::*)]//omega[contains(@string,"alue")]//eta[starts-with(concat(@data,"-"),"solid 1px green-")][@xml:lang="en-GB"][@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::eta[contains(@attrib,"ue")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::beta[contains(@abort,"00%")][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 3]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <pi> + <chi data="solid 1px green" xml:id="id1"/> + <omega xml:id="id2"/> + <beta xml:id="id3"/> + <xi xml:lang="en-GB" xml:id="id4"> + <omega string="attribute-value"> + <eta data="solid 1px green" xml:lang="en-GB" xml:id="id5"/> + <eta attrib="true" xml:lang="en-US"/> + <delta xml:lang="no-nb"/> + <beta abort="100%" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </beta> + </omega> + </xi> + </pi> + </tree> + </test> + <test> + <xpath>//sigma[@false][@xml:lang="no"][@xml:id="id1"]/sigma[contains(@name,"V")][@xml:id="id2"]/omega[contains(concat(@delete,"$"),"%$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[@insert="123456789"]/mu[@xml:id="id4"][not(following-sibling::*)]/pi[@data="false"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>1</nth> + </result> + <tree> + <sigma false="_blank" xml:lang="no" xml:id="id1"> + <sigma name="this.nodeValue" xml:id="id2"> + <omega delete="100%" xml:id="id3"> + <pi insert="123456789"> + <mu xml:id="id4"> + <pi data="false" xml:id="id5"> + <green>This text must be green</green> + </pi> + </mu> + </pi> + </omega> + </sigma> + </sigma> + </tree> + </test> + <test> + <xpath>//*[@xml:lang="en-GB"][@xml:id="id1"]/tau[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[contains(@name,"is.")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/zeta[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::chi[@xml:id="id3"][following-sibling::alpha[@delete][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[starts-with(concat(@src,"-"),"attribute value-")][following-sibling::phi[@src="attribute"][following-sibling::psi[starts-with(concat(@src,"-"),"true-")][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(preceding-sibling::psi or following-sibling::psi)][not(child::node())][following-sibling::omicron[@attribute][preceding-sibling::*[position() = 3]][following-sibling::rho[@abort="this.nodeValue"][@xml:lang="nb"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::pi[@att]/nu[not(following-sibling::*)]//theta[@token][@xml:id="id7"][not(child::node())][following-sibling::chi[not(following-sibling::*)][position() = 1]]][position() = 1]]]]]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <any xml:lang="en-GB" xml:id="id1"> + <tau xml:lang="en"/> + <phi name="this.nodeValue" xml:lang="nb"> + <zeta xml:id="id2"/> + <chi xml:id="id3"/> + <alpha delete="123456789" xml:lang="en-GB" xml:id="id4"> + <nu src="attribute value"/> + <phi src="attribute"/> + <psi src="true" xml:id="id5"/> + <omicron attribute="this.nodeValue"/> + <rho abort="this.nodeValue" xml:lang="nb" xml:id="id6"/> + <pi att="attribute value"> + <nu> + <theta token="false" xml:id="id7"/> + <chi> + <green>This text must be green</green> + </chi> + </nu> + </pi> + </alpha> + </phi> + </any> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:id="id1"]/mu[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::kappa[@true][@xml:id="id3"]/kappa[@xml:lang="en"][following-sibling::upsilon[starts-with(concat(@insert,"-"),"true-")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@insert="another attribute value"][not(preceding-sibling::*)][not(child::node())][following-sibling::*//zeta[contains(@true,"1234567")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::zeta)]/rho[starts-with(@att,"soli")][@xml:lang="en-GB"]/omicron[contains(concat(@class,"$"),"n$")][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@attr="false"][not(following-sibling::*)]/tau[@desciption="solid 1px green"][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:id="id6"][not(following-sibling::*)]//upsilon[@xml:lang="en-US"][not(following-sibling::*)]//pi[@title="solid 1px green"][@xml:id="id7"][not(preceding-sibling::*)]//kappa[@xml:lang="nb"][not(child::node())][following-sibling::nu[@or][@xml:id="id8"][not(following-sibling::*)]/sigma[following-sibling::phi[contains(@attribute,"eV")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::mu[not(following-sibling::*)]//omicron[@attr][@xml:id="id9"][not(following-sibling::*)]]]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:id="id1"> + <mu xml:lang="en-US" xml:id="id2"/> + <kappa true="true" xml:id="id3"> + <kappa xml:lang="en"/> + <upsilon insert="true" xml:lang="no"> + <phi insert="another attribute value"/> + <any> + <zeta true="123456789" xml:lang="no-nb" xml:id="id4"> + <rho att="solid 1px green" xml:lang="en-GB"> + <omicron class="solid 1px green" xml:id="id5"/> + <upsilon attr="false"> + <tau desciption="solid 1px green" xml:lang="en-US"/> + <epsilon xml:id="id6"> + <upsilon xml:lang="en-US"> + <pi title="solid 1px green" xml:id="id7"> + <kappa xml:lang="nb"/> + <nu or="this.nodeValue" xml:id="id8"> + <sigma/> + <phi attribute="this.nodeValue" xml:lang="nb"/> + <mu> + <omicron attr="100%" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </mu> + </nu> + </pi> + </upsilon> + </epsilon> + </upsilon> + </rho> + </zeta> + </any> + </upsilon> + </kappa> + </upsilon> + </tree> + </test> + <test> + <xpath>//lambda[@att]//nu[contains(concat(@desciption,"$"),"te value$")][@xml:lang="no"][@xml:id="id1"][not(child::node())][following-sibling::chi[@att][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[contains(@true,"lan")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]/beta[contains(@content,"e v")][@xml:lang="en-US"][following-sibling::omega[@string][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(preceding-sibling::omega)][not(child::node())][following-sibling::iota[contains(@true,"e")][@xml:lang="en-GB"][@xml:id="id4"][not(following-sibling::*)]/epsilon[contains(concat(@insert,"$"),"e$")][@xml:lang="no-nb"][@xml:id="id5"]//iota[@and][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][not(child::node())][following-sibling::iota[contains(concat(@attr,"$"),"-value$")][@xml:lang="en"][@xml:id="id6"]//lambda[@xml:lang="no"][@xml:id="id7"][following-sibling::tau[contains(@or,"100")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[contains(concat(@true,"$"),"attribute$")][not(following-sibling::*)]/delta[@attribute][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::zeta[@xml:lang="en"][@xml:id="id8"]//delta[@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[starts-with(concat(@object,"-"),"true-")][@xml:lang="no-nb"]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <lambda att="false"> + <nu desciption="attribute value" xml:lang="no" xml:id="id1"/> + <chi att="attribute value" xml:id="id2"/> + <xi true="_blank" xml:lang="no-nb" xml:id="id3"> + <beta content="another attribute value" xml:lang="en-US"/> + <omega string="attribute value"/> + <iota true="false" xml:lang="en-GB" xml:id="id4"> + <epsilon insert="this-is-att-value" xml:lang="no-nb" xml:id="id5"> + <iota and="false"/> + <kappa xml:lang="no-nb"/> + <iota attr="attribute-value" xml:lang="en" xml:id="id6"> + <lambda xml:lang="no" xml:id="id7"/> + <tau or="100%"> + <xi true="attribute"> + <delta attribute="attribute value" xml:lang="en"/> + <zeta xml:lang="en" xml:id="id8"> + <delta xml:lang="en-GB" xml:id="id9"/> + <zeta object="true" xml:lang="no-nb"> + <green>This text must be green</green> + </zeta> + </zeta> + </xi> + </tau> + </iota> + </epsilon> + </iota> + </xi> + </lambda> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-GB"][@xml:id="id1"]//psi[starts-with(@true,"a")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(@delete,"lue")][@xml:lang="en-US"][following-sibling::*[position()=1]][following-sibling::eta[contains(@insert,"ribute")][@xml:lang="en-US"]/kappa[contains(concat(@title,"$"),"te-value$")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::sigma[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::tau[contains(@attribute,"ute v")][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(preceding-sibling::tau)][not(child::node())][following-sibling::alpha[starts-with(@or,"attrib")][@xml:lang="en"][preceding-sibling::*[position() = 4]][following-sibling::sigma[@and][not(following-sibling::*)]][position() = 1]]]]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-GB" xml:id="id1"> + <psi true="attribute-value" xml:lang="nb" xml:id="id2"> + <iota xml:lang="en-GB" xml:id="id3"/> + <sigma delete="another attribute value" xml:lang="en-US"/> + <eta insert="attribute value" xml:lang="en-US"> + <kappa title="attribute-value" xml:lang="no-nb" xml:id="id4"/> + <sigma xml:lang="en"/> + <epsilon xml:lang="no-nb" xml:id="id5"/> + <tau attribute="attribute value" xml:lang="en-US" xml:id="id6"/> + <alpha or="attribute value" xml:lang="en"/> + <sigma and="this.nodeValue"> + <green>This text must be green</green> + </sigma> + </eta> + </psi> + </kappa> + </tree> + </test> + <test> + <xpath>//lambda//nu[@xml:lang="nb"][not(child::node())][following-sibling::lambda[contains(concat(@desciption,"$"),"id 1px green$")]//omega[@or="attribute-value"][not(child::node())][following-sibling::rho[@xml:lang="en"][@xml:id="id1"][following-sibling::*[position()=2]][not(child::node())][following-sibling::zeta[@string][@xml:lang="en"][not(child::node())][following-sibling::lambda[starts-with(@class,"this-is-a")][@xml:lang="en"][@xml:id="id2"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/eta[contains(@attr," green")]/epsilon[starts-with(concat(@content,"-"),"123456789-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::zeta[@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/eta[@token][not(preceding-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <nu xml:lang="nb"/> + <lambda desciption="solid 1px green"> + <omega or="attribute-value"/> + <rho xml:lang="en" xml:id="id1"/> + <zeta string="attribute" xml:lang="en"/> + <lambda class="this-is-att-value" xml:lang="en" xml:id="id2"> + <eta attr="solid 1px green"> + <epsilon content="123456789"/> + <zeta xml:id="id3"> + <eta token="true"> + <green>This text must be green</green> + </eta> + </zeta> + </eta> + </lambda> + </lambda> + </lambda> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]/xi[@xml:lang="no-nb"]/sigma[@string="true"][@xml:lang="en"][@xml:id="id2"][following-sibling::gamma[@name][@xml:id="id3"][not(preceding-sibling::gamma)][following-sibling::chi[@false][@xml:id="id4"][following-sibling::epsilon[starts-with(@string,"false")][@xml:id="id5"][preceding-sibling::*[position() = 3]][following-sibling::xi[@data="solid 1px green"][@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 4]]/mu[@attrib="_blank"][@xml:lang="en-GB"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::gamma[@desciption="content"][not(following-sibling::*)]//gamma[@and][@xml:lang="no"][following-sibling::psi[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::psi[contains(@attribute,"n")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]/lambda[@xml:id="id8"][not(preceding-sibling::*)][following-sibling::nu[starts-with(@name,"s")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[starts-with(concat(@true,"-"),"this.nodeValue-")][@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:id="id1"> + <xi xml:lang="no-nb"> + <sigma string="true" xml:lang="en" xml:id="id2"/> + <gamma name="123456789" xml:id="id3"/> + <chi false="true" xml:id="id4"/> + <epsilon string="false" xml:id="id5"/> + <xi data="solid 1px green" xml:lang="en-US" xml:id="id6"> + <mu attrib="_blank" xml:lang="en-GB" xml:id="id7"/> + <gamma desciption="content"> + <gamma and="this-is-att-value" xml:lang="no"/> + <psi xml:lang="en"/> + <psi attribute="solid 1px green" xml:lang="nb"> + <lambda xml:id="id8"/> + <nu name="solid 1px green" xml:lang="en"> + <zeta true="this.nodeValue" xml:lang="no-nb"/> + <omicron xml:lang="en-US" xml:id="id9"> + <green>This text must be green</green> + </omicron> + </nu> + </psi> + </gamma> + </xi> + </xi> + </kappa> + </tree> + </test> + <test> + <xpath>//pi//beta[starts-with(concat(@data,"-"),"false-")][not(preceding-sibling::*)][following-sibling::upsilon[contains(concat(@name,"$"),"se$")][@xml:id="id1"]/alpha[@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/mu[@xml:id="id3"]//lambda[@xml:lang="no-nb"][following-sibling::*[position()=5]][following-sibling::psi[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::rho[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::tau[@xml:lang="no-nb"][following-sibling::alpha[@name="this-is-att-value"][@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::gamma[@xml:id="id5"][not(following-sibling::*)]//theta[not(preceding-sibling::*)]/xi[@object][@xml:lang="en-GB"][not(child::node())][following-sibling::chi[@or][@xml:lang="no-nb"]]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <pi> + <beta data="false"/> + <upsilon name="false" xml:id="id1"> + <alpha xml:lang="en-US" xml:id="id2"> + <mu xml:id="id3"> + <lambda xml:lang="no-nb"/> + <psi xml:lang="en-US"/> + <rho xml:id="id4"/> + <tau xml:lang="no-nb"/> + <alpha name="this-is-att-value" xml:lang="nb"/> + <gamma xml:id="id5"> + <theta> + <xi object="123456789" xml:lang="en-GB"/> + <chi or="attribute" xml:lang="no-nb"> + <green>This text must be green</green> + </chi> + </theta> + </gamma> + </mu> + </alpha> + </upsilon> + </pi> + </tree> + </test> + <test> + <xpath>//mu[@token="100%"]//psi[@xml:lang="en-US"][not(preceding-sibling::*)]//nu[starts-with(@token,"another attri")][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="nb"][preceding-sibling::*[position() = 1]]/mu[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:lang="en"][not(following-sibling::*)]/*[@xml:id="id3"][not(following-sibling::*)]/zeta[@xml:id="id4"][not(following-sibling::*)]//sigma[contains(@true,"6789")][following-sibling::*[position()=3]][following-sibling::rho[@and][@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[not(child::node())][following-sibling::zeta[starts-with(concat(@name,"-"),"100%-")][@xml:id="id6"][not(following-sibling::*)][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <mu token="100%"> + <psi xml:lang="en-US"> + <nu token="another attribute value" xml:id="id1"/> + <tau xml:lang="nb"> + <mu xml:lang="en-US" xml:id="id2"> + <sigma/> + <upsilon xml:lang="en"> + <any xml:id="id3"> + <zeta xml:id="id4"> + <sigma true="123456789"/> + <rho and="100%" xml:lang="no" xml:id="id5"/> + <beta/> + <zeta name="100%" xml:id="id6"> + <green>This text must be green</green> + </zeta> + </zeta> + </any> + </upsilon> + </mu> + </tau> + </psi> + </mu> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]//mu[@attrib="123456789"][@xml:id="id2"][not(following-sibling::*)]/upsilon[starts-with(concat(@number,"-"),"attribute value-")][@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)]/upsilon[starts-with(@name,"attribute")][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@att="true"][@xml:lang="en-GB"][not(following-sibling::*)]/iota[starts-with(concat(@content,"-"),"100%-")][@xml:id="id5"][not(preceding-sibling::*)]//sigma[starts-with(@delete,"100%")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::zeta[@attr][@xml:lang="en-US"][@xml:id="id7"][following-sibling::gamma[@xml:lang="nb"][@xml:id="id8"][not(child::node())][following-sibling::phi[starts-with(@and,"this-is-att")][@xml:lang="nb"][preceding-sibling::*[position() = 3]]//zeta[@xml:lang="en-GB"][@xml:id="id9"]//mu[@xml:lang="en-US"]/theta[@xml:id="id10"][following-sibling::gamma[contains(concat(@abort,"$"),"alse$")][@xml:id="id11"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="en-GB"][not(following-sibling::*)]/delta[starts-with(concat(@attribute,"-"),"another attribute value-")][@xml:lang="no-nb"][@xml:id="id12"]//kappa[contains(concat(@desciption,"$"),"alue$")][@xml:lang="en"][@xml:id="id13"][following-sibling::delta[@delete][not(following-sibling::*)]//omicron[@src][@xml:id="id14"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::nu[@xml:lang="en-US"][@xml:id="id15"][preceding-sibling::*[position() = 1]][following-sibling::pi[@string="another attribute value"][preceding-sibling::*[position() = 2]]/gamma[@src][@xml:id="id16"][not(child::node())][following-sibling::*[@true][@xml:lang="no"][@xml:id="id17"][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>1</nth> + </result> + <tree> + <xi xml:id="id1"> + <mu attrib="123456789" xml:id="id2"> + <upsilon number="attribute value" xml:lang="no-nb" xml:id="id3"> + <upsilon name="attribute-value" xml:lang="en" xml:id="id4"/> + <sigma att="true" xml:lang="en-GB"> + <iota content="100%" xml:id="id5"> + <sigma delete="100%" xml:lang="en-GB" xml:id="id6"/> + <zeta attr="false" xml:lang="en-US" xml:id="id7"/> + <gamma xml:lang="nb" xml:id="id8"/> + <phi and="this-is-att-value" xml:lang="nb"> + <zeta xml:lang="en-GB" xml:id="id9"> + <mu xml:lang="en-US"> + <theta xml:id="id10"/> + <gamma abort="false" xml:id="id11"/> + <delta xml:lang="en-GB"> + <delta attribute="another attribute value" xml:lang="no-nb" xml:id="id12"> + <kappa desciption="attribute-value" xml:lang="en" xml:id="id13"/> + <delta delete="_blank"> + <omicron src="true" xml:id="id14"/> + <nu xml:lang="en-US" xml:id="id15"/> + <pi string="another attribute value"> + <gamma src="attribute" xml:id="id16"/> + <any true="_blank" xml:lang="no" xml:id="id17"> + <green>This text must be green</green> + </any> + </pi> + </delta> + </delta> + </delta> + </mu> + </zeta> + </phi> + </iota> + </sigma> + </upsilon> + </mu> + </xi> + </tree> + </test> + <test> + <xpath>//alpha[@xml:id="id1"]/theta[@xml:lang="no"][not(following-sibling::*)]//rho[@or][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::rho[contains(concat(@token,"$"),"true$")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/pi[starts-with(@content,"_")][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::*[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//*[@xml:lang="nb"][@xml:id="id4"][not(child::node())][following-sibling::phi[contains(concat(@name,"$"),"ntent$")][@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//omega[starts-with(concat(@data,"-"),"content-")][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:id="id1"> + <theta xml:lang="no"> + <rho or="solid 1px green" xml:id="id2"/> + <rho token="true" xml:lang="nb"> + <pi content="_blank"/> + <omicron xml:lang="en-US" xml:id="id3"/> + <any> + <any xml:lang="nb" xml:id="id4"/> + <phi name="content" xml:lang="en-US" xml:id="id5"> + <omega data="content"> + <green>This text must be green</green> + </omega> + </phi> + </any> + </rho> + </theta> + </alpha> + </tree> + </test> + <test> + <xpath>//upsilon[contains(@object,"-is-at")][@xml:lang="en-GB"]//mu[@or="false"][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@name][@xml:id="id2"][not(preceding-sibling::*)]/iota[@token][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::iota)]/xi[@title="content"][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::chi[starts-with(concat(@abort,"-"),"solid 1px green-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@src="another attribute value"][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <upsilon object="this-is-att-value" xml:lang="en-GB"> + <mu or="false" xml:lang="en-US" xml:id="id1"> + <rho name="this.nodeValue" xml:id="id2"> + <iota token="solid 1px green" xml:lang="no"> + <xi title="content" xml:lang="en"/> + <chi abort="solid 1px green"> + <beta src="another attribute value" xml:lang="no" xml:id="id3"> + <green>This text must be green</green> + </beta> + </chi> + </iota> + </rho> + </mu> + </upsilon> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@data,"$"),"tribute$")][@xml:lang="no-nb"][@xml:id="id1"]//kappa[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[position()=3]][following-sibling::iota[@string][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[not(following-sibling::*)]//lambda[@false="content"][following-sibling::*[position()=2]][not(child::node())][following-sibling::phi[@xml:lang="en"][following-sibling::sigma[starts-with(@object,"this.nodeValu")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]]/sigma[@attribute][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[starts-with(concat(@string,"-"),"this-")][@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@object][@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::delta[starts-with(@insert,"this-is-a")][@xml:id="id9"][following-sibling::eta[@xml:id="id10"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//tau[starts-with(@true,"con")][@xml:lang="en-GB"][@xml:id="id11"][following-sibling::kappa[starts-with(@title,"fal")][@xml:lang="en-GB"][@xml:id="id12"][preceding-sibling::*[position() = 1]]/delta[@string][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi data="attribute" xml:lang="no-nb" xml:id="id1"> + <kappa xml:lang="en-GB" xml:id="id2"/> + <iota string="content" xml:lang="no" xml:id="id3"/> + <upsilon xml:id="id4"/> + <lambda> + <lambda false="content"/> + <phi xml:lang="en"/> + <sigma object="this.nodeValue" xml:lang="no-nb"> + <sigma attribute="attribute-value" xml:lang="en"> + <upsilon xml:lang="no"/> + <iota xml:lang="en-US" xml:id="id5"> + <upsilon string="this-is-att-value" xml:lang="en-GB" xml:id="id6"/> + <omicron xml:lang="no" xml:id="id7"/> + <kappa object="_blank" xml:id="id8"/> + <delta insert="this-is-att-value" xml:id="id9"/> + <eta xml:id="id10"> + <tau true="content" xml:lang="en-GB" xml:id="id11"/> + <kappa title="false" xml:lang="en-GB" xml:id="id12"> + <delta string="attribute-value" xml:lang="no-nb"/> + <epsilon xml:lang="en-GB"> + <green>This text must be green</green> + </epsilon> + </kappa> + </eta> + </iota> + </sigma> + </sigma> + </lambda> + </phi> + </tree> + </test> + <test> + <xpath>//tau[@name="content"][@xml:id="id1"]//*[contains(@and,"blank")][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[starts-with(concat(@string,"-"),"attribute-")][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@token="this-is-att-value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/theta[@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[@title="100%"][not(preceding-sibling::*)]/epsilon[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::iota[contains(@title,"e")][@xml:id="id7"][following-sibling::lambda[@xml:id="id8"]//mu[@object="this.nodeValue"][@xml:lang="en-US"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)][not(following-sibling::chi)]/psi[starts-with(@insert,"false")][following-sibling::rho[contains(concat(@desciption,"$"),"456789$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <tau name="content" xml:id="id1"> + <any and="_blank" xml:id="id2"/> + <phi string="attribute-value" xml:lang="en-GB" xml:id="id3"/> + <nu token="this-is-att-value"> + <theta xml:id="id4"> + <omega title="100%"> + <epsilon xml:id="id5"> + <upsilon xml:id="id6"/> + <iota title="true" xml:id="id7"/> + <lambda xml:id="id8"> + <mu object="this.nodeValue" xml:lang="en-US" xml:id="id9"> + <chi xml:id="id10"> + <psi insert="false"/> + <rho desciption="123456789" xml:lang="en-GB"> + <green>This text must be green</green> + </rho> + </chi> + </mu> + </lambda> + </epsilon> + </omega> + </theta> + </nu> + </tau> + </tree> + </test> + <test> + <xpath>//phi[@true][@xml:lang="en-GB"][@xml:id="id1"]/iota[@insert][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::zeta[not(following-sibling::*)]//xi[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="no-nb"][not(child::node())][following-sibling::gamma[contains(concat(@attribute,"$"),"ue$")][@xml:id="id3"]/zeta[@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[preceding-sibling::*[position() = 1]]/nu[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[starts-with(@attrib,"_blan")][preceding-sibling::*[position() = 1]][following-sibling::iota[contains(concat(@title,"$"),"e$")][@xml:lang="en-GB"][@xml:id="id6"][following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="en-US"][following-sibling::nu[preceding-sibling::*[position() = 4]]/theta[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[@string="this.nodeValue"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="no-nb"][@xml:id="id8"]/gamma[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[starts-with(concat(@title,"-"),"this-")][@xml:id="id9"][preceding-sibling::*[position() = 1]][following-sibling::epsilon[@xml:lang="en-US"][not(following-sibling::*)]//kappa[following-sibling::theta[contains(@object,"ttribute-val")][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <phi true="attribute value" xml:lang="en-GB" xml:id="id1"> + <iota insert="123456789" xml:lang="en" xml:id="id2"/> + <zeta> + <xi xml:lang="no"> + <iota xml:lang="no-nb"/> + <gamma attribute="this.nodeValue" xml:id="id3"> + <zeta xml:id="id4"/> + <theta> + <nu xml:lang="no" xml:id="id5"/> + <gamma attrib="_blank"/> + <iota title="true" xml:lang="en-GB" xml:id="id6"/> + <mu xml:lang="en-US"/> + <nu> + <theta xml:id="id7"/> + <beta string="this.nodeValue"/> + <delta xml:lang="no-nb" xml:id="id8"> + <gamma xml:lang="no-nb"/> + <nu title="this-is-att-value" xml:id="id9"/> + <epsilon xml:lang="en-US"> + <kappa/> + <theta object="attribute-value"> + <green>This text must be green</green> + </theta> + </epsilon> + </delta> + </nu> + </theta> + </gamma> + </xi> + </zeta> + </phi> + </tree> + </test> + <test> + <xpath>//theta[@delete][@xml:lang="no"][@xml:id="id1"]/theta[starts-with(concat(@content,"-"),"true-")][not(following-sibling::*)]/mu[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:id="id3"][not(following-sibling::*)]//*[contains(@true,"a")][not(preceding-sibling::*)][following-sibling::omicron[@xml:lang="nb"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[starts-with(@object,"conten")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/omega[not(preceding-sibling::omega)]//pi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[contains(@and,"nk")][@xml:id="id5"][not(child::node())][following-sibling::delta[@xml:id="id6"][not(following-sibling::*)]/mu[@or][following-sibling::omicron[starts-with(@or,"anot")][following-sibling::kappa[@src][preceding-sibling::*[position() = 2]][following-sibling::delta[starts-with(concat(@attrib,"-"),"true-")][@xml:lang="no"][@xml:id="id7"]]][position() = 1]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <theta delete="true" xml:lang="no" xml:id="id1"> + <theta content="true"> + <mu xml:id="id2"/> + <alpha xml:lang="nb"/> + <pi xml:id="id3"> + <any true="this-is-att-value"/> + <omicron xml:lang="nb" xml:id="id4"/> + <mu object="content" xml:lang="en-US"> + <omega> + <pi xml:lang="no-nb"/> + <alpha and="_blank" xml:id="id5"/> + <delta xml:id="id6"> + <mu or="false"/> + <omicron or="another attribute value"/> + <kappa src="attribute"/> + <delta attrib="true" xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </delta> + </delta> + </omega> + </mu> + </pi> + </theta> + </theta> + </tree> + </test> + <test> + <xpath>//sigma[starts-with(concat(@desciption,"-"),"100%-")][@xml:lang="nb"][@xml:id="id1"]/epsilon[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)]/pi[@xml:lang="no"]//epsilon[contains(concat(@number,"$"),"0%$")][@xml:lang="no"][not(following-sibling::*)]/mu[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::omicron[@content="attribute-value"][@xml:lang="no-nb"]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <sigma desciption="100%" xml:lang="nb" xml:id="id1"> + <epsilon xml:lang="no-nb" xml:id="id2"> + <pi xml:lang="no"> + <epsilon number="100%" xml:lang="no"> + <mu xml:lang="no"/> + <omicron content="attribute-value" xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </epsilon> + </pi> + </epsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//psi[starts-with(@attribute,"soli")][@xml:id="id1"]/alpha[starts-with(@delete,"100")][@xml:id="id2"][not(following-sibling::*)]//eta//kappa[following-sibling::eta[not(following-sibling::*)]/lambda[not(child::node())][following-sibling::upsilon[contains(@attr,"u")][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::zeta[@content="content"][@xml:lang="no-nb"][@xml:id="id4"][not(child::node())][following-sibling::chi[@xml:lang="en"][following-sibling::phi[starts-with(@string,"cont")][@xml:lang="nb"][preceding-sibling::*[position() = 4]]/sigma[contains(@false,"ont")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:id="id6"][not(following-sibling::*)]/omega[@xml:id="id7"]/tau[contains(@desciption,"lan")][@xml:lang="en-GB"][@xml:id="id8"][not(following-sibling::*)]/chi[@abort="false"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[@xml:id="id9"]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <psi attribute="solid 1px green" xml:id="id1"> + <alpha delete="100%" xml:id="id2"> + <eta> + <kappa/> + <eta> + <lambda/> + <upsilon attr="attribute" xml:lang="en-US" xml:id="id3"/> + <zeta content="content" xml:lang="no-nb" xml:id="id4"/> + <chi xml:lang="en"/> + <phi string="content" xml:lang="nb"> + <sigma false="content" xml:id="id5"> + <delta xml:id="id6"> + <omega xml:id="id7"> + <tau desciption="_blank" xml:lang="en-GB" xml:id="id8"> + <chi abort="false"> + <tau xml:id="id9"> + <green>This text must be green</green> + </tau> + </chi> + </tau> + </omega> + </delta> + </sigma> + </phi> + </eta> + </eta> + </alpha> + </psi> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]/phi[@xml:id="id2"][not(child::node())][following-sibling::mu[starts-with(@title,"this.n")][preceding-sibling::*[position() = 1]][following-sibling::rho[not(child::node())][following-sibling::psi[@xml:lang="en"][@xml:id="id3"]//tau[@xml:id="id4"][not(preceding-sibling::*)]//zeta[starts-with(concat(@object,"-"),"another attribute value-")][@xml:lang="en"][not(preceding-sibling::*)]/sigma[contains(@abort,"ribute")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(@insert,"e")][@xml:id="id5"][preceding-sibling::*[position() = 1]]//iota[contains(concat(@number,"$"),"se$")][@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::iota)]/pi[not(preceding-sibling::*)]/omega[@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[contains(@attribute,"ue")][@xml:lang="en"][@xml:id="id8"][not(following-sibling::*)]/psi[@data][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::pi[contains(concat(@or,"$"),"ribute-value$")][@xml:lang="en-US"][following-sibling::phi[@att="attribute value"][@xml:id="id10"][preceding-sibling::*[position() = 2]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <phi xml:id="id2"/> + <mu title="this.nodeValue"/> + <rho/> + <psi xml:lang="en" xml:id="id3"> + <tau xml:id="id4"> + <zeta object="another attribute value" xml:lang="en"> + <sigma abort="attribute"/> + <sigma insert="true" xml:id="id5"> + <iota number="false" xml:lang="nb" xml:id="id6"> + <pi> + <omega xml:lang="en-US" xml:id="id7"> + <eta attribute="this-is-att-value" xml:lang="en" xml:id="id8"> + <psi data="another attribute value" xml:id="id9"/> + <pi or="attribute-value" xml:lang="en-US"/> + <phi att="attribute value" xml:id="id10"> + <green>This text must be green</green> + </phi> + </eta> + </omega> + </pi> + </iota> + </sigma> + </zeta> + </tau> + </psi> + </mu> + </tree> + </test> + <test> + <xpath>//pi[contains(concat(@and,"$"),"r attribute value$")]//nu[starts-with(@attrib,"100%")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::psi[contains(concat(@name,"$"),"0%$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::tau[@xml:id="id1"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//sigma[not(child::node())][following-sibling::upsilon[@false][@xml:lang="nb"][@xml:id="id2"]/epsilon[starts-with(@and,"another at")]/pi[@string][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::eta[@string="attribute"][@xml:lang="en-GB"][following-sibling::pi[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[@xml:lang="nb"][not(preceding-sibling::*)]//sigma[not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@false][@xml:lang="en-US"][preceding-sibling::*[position() = 1]]/pi[contains(@true,"ther attribute value")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/theta[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[@xml:lang="no"][not(preceding-sibling::xi)][not(child::node())][following-sibling::phi[@xml:id="id5"][preceding-sibling::*[position() = 1]]/theta[starts-with(@attr,"fals")][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[contains(@insert,"nt")]][position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <pi and="another attribute value"> + <nu attrib="100%" xml:lang="en-US"/> + <psi name="100%" xml:lang="en-US"/> + <tau xml:id="id1"> + <sigma/> + <upsilon false="attribute" xml:lang="nb" xml:id="id2"> + <epsilon and="another attribute value"> + <pi string="100%" xml:lang="en-US"/> + <eta string="attribute" xml:lang="en-GB"/> + <pi xml:lang="en" xml:id="id3"> + <alpha xml:lang="nb"> + <sigma/> + <sigma false="100%" xml:lang="en-US"> + <pi true="another attribute value" xml:lang="no-nb" xml:id="id4"> + <theta xml:lang="nb"/> + <alpha> + <xi xml:lang="no"/> + <phi xml:id="id5"> + <theta attr="false" xml:id="id6"/> + <iota insert="content"> + <green>This text must be green</green> + </iota> + </phi> + </alpha> + </pi> + </sigma> + </alpha> + </pi> + </epsilon> + </upsilon> + </tau> + </pi> + </tree> + </test> + <test> + <xpath>//mu[@xml:id="id1"]/upsilon//psi[starts-with(concat(@attr,"-"),"_blank-")][@xml:id="id2"][not(preceding-sibling::*)]//epsilon[starts-with(@delete,"1234")][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id3"][not(following-sibling::*)]//sigma[@object][@xml:lang="en"][not(preceding-sibling::*)]/beta[@class][@xml:lang="nb"]//*[not(child::node())][following-sibling::phi[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[@true][not(preceding-sibling::*)][not(following-sibling::*)]//psi[not(preceding-sibling::*)][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <mu xml:id="id1"> + <upsilon> + <psi attr="_blank" xml:id="id2"> + <epsilon delete="123456789"/> + <lambda xml:id="id3"> + <sigma object="this-is-att-value" xml:lang="en"> + <beta class="attribute" xml:lang="nb"> + <any/> + <phi xml:id="id4"> + <upsilon true="attribute-value"> + <psi> + <green>This text must be green</green> + </psi> + </upsilon> + </phi> + </beta> + </sigma> + </lambda> + </psi> + </upsilon> + </mu> + </tree> + </test> + <test> + <xpath>//theta[contains(@name,"89")][@xml:lang="no"]/eta[contains(concat(@attribute,"$"),"e$")][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::alpha[@xml:lang="no-nb"][@xml:id="id1"][not(child::node())][following-sibling::tau[@xml:lang="nb"][not(following-sibling::*)]/iota[contains(concat(@data,"$"),"bute$")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::eta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <theta name="123456789" xml:lang="no"> + <eta attribute="false"/> + <alpha xml:lang="no-nb" xml:id="id1"/> + <tau xml:lang="nb"> + <iota data="attribute" xml:lang="en-GB"/> + <eta> + <green>This text must be green</green> + </eta> + </tau> + </theta> + </tree> + </test> + <test> + <xpath>//xi[@xml:id="id1"]/omicron[@xml:id="id2"][not(following-sibling::*)]/pi[contains(@string,"t")]//eta[@xml:lang="en-GB"]/beta[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[not(following-sibling::*)]/psi[starts-with(concat(@attribute,"-"),"false-")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@att="attribute"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::phi[@xml:lang="nb"][@xml:id="id4"]//kappa[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::mu[contains(@or,"co")][@xml:lang="en-GB"][not(child::node())][following-sibling::alpha[contains(@src,"12345")][@xml:lang="no-nb"][not(following-sibling::*)]//lambda[starts-with(@attrib,"123456")][@xml:lang="en"][@xml:id="id5"]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:id="id1"> + <omicron xml:id="id2"> + <pi string="content"> + <eta xml:lang="en-GB"> + <beta xml:lang="nb"/> + <rho> + <psi attribute="false" xml:id="id3"> + <delta att="attribute" xml:lang="no-nb"/> + <phi xml:lang="nb" xml:id="id4"> + <kappa xml:lang="no"/> + <mu or="content" xml:lang="en-GB"/> + <alpha src="123456789" xml:lang="no-nb"> + <lambda attrib="123456789" xml:lang="en" xml:id="id5"> + <green>This text must be green</green> + </lambda> + </alpha> + </phi> + </psi> + </rho> + </eta> + </pi> + </omicron> + </xi> + </tree> + </test> + <test> + <xpath>//*/eta[starts-with(@attr,"conten")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::eta)][following-sibling::xi[@xml:lang="en-US"][@xml:id="id2"][following-sibling::xi[@xml:lang="no"][preceding-sibling::*[position() = 2]]//alpha[starts-with(concat(@data,"-"),"attribute-")][@xml:id="id3"][not(child::node())][following-sibling::chi[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::psi[@xml:id="id4"][following-sibling::kappa[@xml:id="id5"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <any> + <eta attr="content" xml:lang="en-US" xml:id="id1"/> + <xi xml:lang="en-US" xml:id="id2"/> + <xi xml:lang="no"> + <alpha data="attribute-value" xml:id="id3"/> + <chi xml:lang="en"/> + <psi xml:id="id4"/> + <kappa xml:id="id5"> + <green>This text must be green</green> + </kappa> + </xi> + </any> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="en"]/upsilon[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[starts-with(@attr,"fals")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[@attr][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]//sigma[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@att][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="en"> + <upsilon xml:id="id1"/> + <psi attr="false"> + <delta attr="_blank" xml:lang="nb" xml:id="id2"> + <sigma xml:lang="en-US"/> + <epsilon att="this.nodeValue"> + <green>This text must be green</green> + </epsilon> + </delta> + </psi> + </pi> + </tree> + </test> + <test> + <xpath>//iota[@attrib][@xml:id="id1"]//phi[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[@delete][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[starts-with(@title,"this-is-att-val")][not(preceding-sibling::*)][following-sibling::epsilon//xi[@attrib][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::gamma[starts-with(@title,"t")][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::epsilon[@xml:id="id5"][not(following-sibling::*)]/psi[position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <iota attrib="true" xml:id="id1"> + <phi xml:lang="en-GB" xml:id="id2"/> + <any delete="true" xml:lang="no" xml:id="id3"> + <theta title="this-is-att-value"/> + <epsilon> + <xi attrib="solid 1px green" xml:lang="no" xml:id="id4"/> + <gamma title="this.nodeValue" xml:lang="no"/> + <epsilon xml:id="id5"> + <psi> + <green>This text must be green</green> + </psi> + </epsilon> + </epsilon> + </any> + </iota> + </tree> + </test> + <test> + <xpath>//tau/psi[@xml:lang="nb"][@xml:id="id1"][following-sibling::beta[not(following-sibling::*)]/kappa[@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]/pi[@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::chi[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/nu[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//upsilon[starts-with(@attribute,"true")][@xml:lang="no"][@xml:id="id7"]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <tau> + <psi xml:lang="nb" xml:id="id1"/> + <beta> + <kappa xml:lang="en-GB" xml:id="id2"> + <pi xml:lang="no" xml:id="id3"/> + <chi xml:lang="no-nb" xml:id="id4"> + <nu xml:id="id5"/> + <beta xml:id="id6"> + <upsilon attribute="true" xml:lang="no" xml:id="id7"> + <green>This text must be green</green> + </upsilon> + </beta> + </chi> + </kappa> + </beta> + </tau> + </tree> + </test> + <test> + <xpath>//lambda[@xml:id="id1"]/pi[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[contains(concat(@attr,"$"),"%$")][@xml:lang="en-US"][@xml:id="id3"][not(child::node())][following-sibling::xi[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::alpha[@attr][@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::alpha)]//upsilon[not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//chi[@data][@xml:lang="en"][@xml:id="id7"][following-sibling::lambda[@xml:lang="en-US"][not(preceding-sibling::lambda)][not(child::node())][following-sibling::delta[@att="100%"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::upsilon[contains(concat(@src,"$"),"bute value$")][@xml:lang="en-US"][preceding-sibling::*[position() = 3]]//gamma[@xml:id="id9"][following-sibling::mu[@xml:lang="en-US"][@xml:id="id10"]/delta[@xml:lang="en-GB"][following-sibling::beta[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[starts-with(concat(@attr,"-"),"content-")][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(@string,"a")][preceding-sibling::*[position() = 3]]//upsilon[contains(@delete,"%")]//theta[@token="another attribute value"][@xml:lang="en-US"][following-sibling::phi[@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi[contains(concat(@attribute,"$"),"lue$")][@xml:lang="en-GB"][@xml:id="id12"][preceding-sibling::*[position() = 2]][position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>1</nth> + </result> + <tree> + <lambda xml:id="id1"> + <pi xml:lang="en-GB" xml:id="id2"> + <lambda attr="100%" xml:lang="en-US" xml:id="id3"/> + <xi xml:id="id4"/> + <alpha attr="attribute" xml:lang="nb" xml:id="id5"> + <upsilon> + <iota xml:id="id6"> + <chi data="content" xml:lang="en" xml:id="id7"/> + <lambda xml:lang="en-US"/> + <delta att="100%" xml:id="id8"/> + <upsilon src="another attribute value" xml:lang="en-US"> + <gamma xml:id="id9"/> + <mu xml:lang="en-US" xml:id="id10"> + <delta xml:lang="en-GB"/> + <beta/> + <omega attr="content"/> + <sigma string="this.nodeValue"> + <upsilon delete="100%"> + <theta token="another attribute value" xml:lang="en-US"/> + <phi xml:lang="nb" xml:id="id11"/> + <chi attribute="attribute value" xml:lang="en-GB" xml:id="id12"> + <green>This text must be green</green> + </chi> + </upsilon> + </sigma> + </mu> + </upsilon> + </iota> + </upsilon> + </alpha> + </pi> + </lambda> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en-US"]//xi[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:lang="en"][following-sibling::pi[@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)]/delta[@xml:lang="en-US"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:id="id3"]//phi[@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::nu[not(following-sibling::*)]//delta[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::gamma[@xml:lang="nb"]/alpha[@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/gamma[contains(@att,"e")][not(preceding-sibling::*)][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 1]]/mu[not(following-sibling::*)]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en-US"> + <xi xml:lang="en-US"> + <theta xml:lang="en"/> + <pi xml:lang="no" xml:id="id1"> + <delta xml:lang="en-US" xml:id="id2"/> + <mu xml:id="id3"> + <phi xml:lang="nb"/> + <nu> + <delta xml:lang="en-US" xml:id="id4"/> + <gamma xml:lang="nb"> + <alpha xml:id="id5"> + <gamma att="true"/> + <any> + <mu> + <green>This text must be green</green> + </mu> + </any> + </alpha> + </gamma> + </nu> + </mu> + </pi> + </xi> + </delta> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en-GB"]/upsilon[@xml:id="id1"][not(following-sibling::*)]//kappa[@xml:lang="en-US"][following-sibling::upsilon[@xml:lang="en-GB"][following-sibling::*[position()=2]][following-sibling::lambda[@abort][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@content][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//phi[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 1]]//tau[starts-with(concat(@title,"-"),"_blank-")][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[starts-with(@abort,"this.n")][@xml:lang="en-GB"]]]]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en-GB"> + <upsilon xml:id="id1"> + <kappa xml:lang="en-US"/> + <upsilon xml:lang="en-GB"/> + <lambda abort="another attribute value" xml:id="id2"/> + <pi content="true" xml:lang="no-nb" xml:id="id3"> + <phi xml:lang="en-GB"/> + <tau> + <tau title="_blank"/> + <tau abort="this.nodeValue" xml:lang="en-GB"> + <green>This text must be green</green> + </tau> + </tau> + </pi> + </upsilon> + </delta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="no"][@xml:id="id1"]//mu[not(preceding-sibling::*)][following-sibling::xi[starts-with(@string,"sol")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(preceding-sibling::xi)]//gamma[contains(concat(@token,"$"),"e$")][@xml:lang="en-GB"][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::pi[contains(concat(@insert,"$"),"green$")][following-sibling::*[position()=1]][following-sibling::gamma[@att][@xml:lang="en-US"][not(following-sibling::*)]//chi[@delete][@xml:id="id4"][not(following-sibling::*)]//zeta[@xml:lang="no-nb"][@xml:id="id5"][not(child::node())][following-sibling::*[starts-with(@src,"attr")][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[@delete="content"][@xml:lang="en"]//mu[@xml:id="id7"]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="no" xml:id="id1"> + <mu/> + <xi string="solid 1px green" xml:id="id2"> + <gamma token="false" xml:lang="en-GB" xml:id="id3"/> + <pi insert="solid 1px green"/> + <gamma att="attribute value" xml:lang="en-US"> + <chi delete="100%" xml:id="id4"> + <zeta xml:lang="no-nb" xml:id="id5"/> + <any src="attribute value" xml:id="id6"/> + <upsilon delete="content" xml:lang="en"> + <mu xml:id="id7"> + <green>This text must be green</green> + </mu> + </upsilon> + </chi> + </gamma> + </xi> + </sigma> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-GB"]/gamma[@xml:lang="en"][@xml:id="id1"]//mu[contains(concat(@att,"$"),"px green$")][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[starts-with(concat(@object,"-"),"attribute-")][@xml:lang="no-nb"]/psi[starts-with(concat(@src,"-"),"attribute-")][@xml:id="id2"][not(preceding-sibling::*)]//chi[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[@insert="attribute value"][@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@xml:lang="no"][following-sibling::rho[starts-with(concat(@desciption,"-"),"123456789-")][preceding-sibling::*[position() = 2]]/mu[@token][@xml:lang="en"][@xml:id="id5"]/kappa[starts-with(@number,"fals")][not(child::node())][following-sibling::alpha[@src][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:lang="en"]/iota[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[starts-with(concat(@name,"-"),"attribute-")][@xml:lang="no"][@xml:id="id7"]/theta[@number="solid 1px green"][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-GB"> + <gamma xml:lang="en" xml:id="id1"> + <mu att="solid 1px green"/> + <iota object="attribute" xml:lang="no-nb"> + <psi src="attribute" xml:id="id2"> + <chi xml:id="id3"> + <lambda insert="attribute value" xml:lang="nb" xml:id="id4"/> + <zeta xml:lang="no"/> + <rho desciption="123456789"> + <mu token="attribute-value" xml:lang="en" xml:id="id5"> + <kappa number="false"/> + <alpha src="attribute-value" xml:lang="en-GB"/> + <sigma xml:lang="en"> + <iota xml:id="id6"/> + <sigma name="attribute-value" xml:lang="no" xml:id="id7"> + <theta number="solid 1px green" xml:lang="en"> + <green>This text must be green</green> + </theta> + </sigma> + </sigma> + </mu> + </rho> + </chi> + </psi> + </iota> + </gamma> + </phi> + </tree> + </test> + <test> + <xpath>//phi[contains(@delete,"r attribu")][@xml:lang="no-nb"]/epsilon[@xml:id="id1"][not(preceding-sibling::*)]/beta[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@delete][@xml:id="id3"][not(following-sibling::*)]//psi[starts-with(concat(@src,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta[@true="100%"][@xml:lang="en-US"]//upsilon[@xml:id="id6"][following-sibling::omega[@xml:id="id7"]/upsilon[not(preceding-sibling::*)][not(following-sibling::*)]/rho[@insert][@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id9"]//delta[@xml:lang="en"][@xml:id="id10"]//iota[@xml:lang="no-nb"][@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@xml:lang="nb"][@xml:id="id12"][following-sibling::tau[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::beta[@xml:id="id13"][not(following-sibling::*)]//pi[@class][@xml:id="id14"][following-sibling::*[position()=1]][following-sibling::delta[@and][@xml:id="id15"][preceding-sibling::*[position() = 1]]/alpha[contains(@abort,"bute-v")][@xml:lang="en-GB"][@xml:id="id16"]/epsilon[@xml:lang="en-US"][@xml:id="id17"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <phi delete="another attribute value" xml:lang="no-nb"> + <epsilon xml:id="id1"> + <beta xml:id="id2"> + <upsilon delete="_blank" xml:id="id3"> + <psi src="this.nodeValue"> + <lambda xml:id="id4"/> + <delta xml:lang="nb" xml:id="id5"> + <zeta true="100%" xml:lang="en-US"> + <upsilon xml:id="id6"/> + <omega xml:id="id7"> + <upsilon> + <rho insert="solid 1px green" xml:lang="no" xml:id="id8"/> + <upsilon xml:id="id9"> + <delta xml:lang="en" xml:id="id10"> + <iota xml:lang="no-nb" xml:id="id11"> + <xi xml:lang="nb" xml:id="id12"/> + <tau xml:lang="no-nb"/> + <beta xml:id="id13"> + <pi class="attribute-value" xml:id="id14"/> + <delta and="_blank" xml:id="id15"> + <alpha abort="attribute-value" xml:lang="en-GB" xml:id="id16"> + <epsilon xml:lang="en-US" xml:id="id17"> + <green>This text must be green</green> + </epsilon> + </alpha> + </delta> + </beta> + </iota> + </delta> + </upsilon> + </upsilon> + </omega> + </zeta> + </delta> + </psi> + </upsilon> + </beta> + </epsilon> + </phi> + </tree> + </test> + <test> + <xpath>//beta[starts-with(concat(@and,"-"),"this.nodeValue-")][@xml:id="id1"]/zeta[starts-with(@false,"con")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)][not(following-sibling::theta)]/delta[@xml:id="id4"]/eta[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)]//pi[@desciption][@xml:lang="no"]/pi[not(following-sibling::*)]//pi[following-sibling::*[position()=3]][not(child::node())][following-sibling::upsilon[@false][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]//eta[contains(@att," value")][@xml:lang="en"][not(preceding-sibling::*)][not(preceding-sibling::eta)]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <beta and="this.nodeValue" xml:id="id1"> + <zeta false="content" xml:lang="nb" xml:id="id2"/> + <theta xml:lang="en-US" xml:id="id3"> + <delta xml:id="id4"> + <eta xml:lang="en-GB" xml:id="id5"> + <pi desciption="this.nodeValue" xml:lang="no"> + <pi> + <pi/> + <upsilon false="attribute value"/> + <theta xml:lang="en-US" xml:id="id6"/> + <pi xml:lang="no-nb" xml:id="id7"> + <eta att="attribute value" xml:lang="en"> + <green>This text must be green</green> + </eta> + </pi> + </pi> + </pi> + </eta> + </delta> + </theta> + </beta> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]//sigma[@xml:lang="no-nb"][not(following-sibling::*)]/eta[@xml:id="id2"][not(following-sibling::*)]/sigma[starts-with(concat(@title,"-"),"content-")][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::*)]/tau[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omega[@xml:lang="en"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[@xml:id="id4"][preceding-sibling::*[position() = 2]]//omicron[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:lang="no-nb"][not(following-sibling::*)]//tau[contains(@string,"true")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha//phi[@attr][@xml:lang="no-nb"][@xml:id="id5"]/zeta[@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[starts-with(@or,"false")][@xml:id="id7"][not(following-sibling::*)]//upsilon[@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@xml:lang="nb"][not(following-sibling::*)]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <rho xml:id="id1"> + <sigma xml:lang="no-nb"> + <eta xml:id="id2"> + <sigma title="content" xml:lang="no" xml:id="id3"> + <tau xml:lang="no"/> + <omega xml:lang="en"/> + <lambda xml:id="id4"> + <omicron xml:lang="en-US"/> + <chi src="this.nodeValue" xml:lang="no-nb"> + <tau string="true" xml:lang="no"/> + <alpha> + <phi attr="another attribute value" xml:lang="no-nb" xml:id="id5"> + <zeta xml:id="id6"/> + <alpha or="false" xml:id="id7"> + <upsilon xml:lang="nb"/> + <theta xml:lang="nb"> + <green>This text must be green</green> + </theta> + </alpha> + </phi> + </alpha> + </chi> + </lambda> + </sigma> + </eta> + </sigma> + </rho> + </tree> + </test> + <test> + <xpath>//kappa[contains(concat(@object,"$"),"ribute value$")][@xml:id="id1"]/epsilon[starts-with(@attrib,"fa")][@xml:id="id2"][not(preceding-sibling::*)]//omega[starts-with(concat(@delete,"-"),"attribute value-")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//phi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::nu[@true][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::mu[starts-with(@and,"this-is-att-val")][not(following-sibling::*)]/pi[contains(@attr,"ibute")][@xml:id="id5"][not(preceding-sibling::*)]/phi[@xml:id="id6"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[not(following-sibling::*)]/epsilon[@or="attribute-value"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[starts-with(@data,"fal")][@xml:id="id8"][following-sibling::epsilon//chi[@attribute="false"][@xml:lang="en"][following-sibling::rho[@insert="this-is-att-value"][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <kappa object="attribute value" xml:id="id1"> + <epsilon attrib="false" xml:id="id2"> + <omega delete="attribute value" xml:id="id3"> + <phi xml:lang="no-nb"/> + <omicron xml:id="id4"/> + <nu true="content" xml:lang="en-US"/> + <mu and="this-is-att-value"> + <pi attr="attribute" xml:id="id5"> + <phi xml:id="id6"/> + <chi> + <epsilon or="attribute-value" xml:id="id7"/> + <kappa data="false" xml:id="id8"/> + <epsilon> + <chi attribute="false" xml:lang="en"/> + <rho insert="this-is-att-value"> + <green>This text must be green</green> + </rho> + </epsilon> + </chi> + </pi> + </mu> + </omega> + </epsilon> + </kappa> + </tree> + </test> + <test> + <xpath>//lambda[@xml:lang="no"]//*[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::iota[@name="123456789"][@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omicron[preceding-sibling::*[position() = 2]]/tau[starts-with(concat(@src,"-"),"this.nodeValue-")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[contains(concat(@abort,"$"),"-att-value$")][following-sibling::nu[starts-with(concat(@attrib,"-"),"123456789-")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@xml:id="id4"][preceding-sibling::*[position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:lang="no"> + <any xml:lang="en-US" xml:id="id1"/> + <iota name="123456789" xml:lang="no"/> + <omicron> + <tau src="this.nodeValue" xml:lang="no"> + <beta abort="this-is-att-value"/> + <nu attrib="123456789" xml:id="id2"> + <alpha xml:id="id3"/> + <nu xml:id="id4"> + <green>This text must be green</green> + </nu> + </nu> + </tau> + </omicron> + </lambda> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="en-US"][@xml:id="id1"]/psi[@and][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[not(child::node())][following-sibling::theta[@true="true"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(concat(@src,"$"),"Value$")][@xml:id="id3"][not(following-sibling::*)]//upsilon[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[contains(@attrib,"reen")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::xi[contains(concat(@name,"$"),"89$")][@xml:id="id5"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::nu[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//xi//eta[@or][@xml:lang="nb"][@xml:id="id6"]//iota//phi[@object][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::iota[following-sibling::*[position()=3]][following-sibling::mu[@xml:lang="en"][preceding-sibling::*[position() = 2]][following-sibling::delta[@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::gamma[starts-with(@and,"this.nod")][preceding-sibling::*[position() = 4]]/kappa[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][not(child::node())][following-sibling::nu[@xml:id="id7"]]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="en-US" xml:id="id1"> + <psi and="true" xml:id="id2"> + <pi/> + <theta true="true"/> + <delta src="this.nodeValue" xml:id="id3"> + <upsilon xml:lang="en-US" xml:id="id4"> + <epsilon attrib="solid 1px green" xml:lang="en-US"/> + <xi name="123456789" xml:id="id5"/> + <nu/> + <nu xml:lang="no"> + <xi> + <eta or="attribute value" xml:lang="nb" xml:id="id6"> + <iota> + <phi object="this.nodeValue" xml:lang="en-GB"/> + <iota/> + <mu xml:lang="en"/> + <delta xml:lang="nb"/> + <gamma and="this.nodeValue"> + <kappa xml:lang="nb"/> + <pi xml:lang="no-nb"/> + <nu xml:id="id7"> + <green>This text must be green</green> + </nu> + </gamma> + </iota> + </eta> + </xi> + </nu> + </upsilon> + </delta> + </psi> + </beta> + </tree> + </test> + <test> + <xpath>//gamma[contains(concat(@content,"$"),"this.nodeValue$")]//lambda[@xml:lang="no-nb"][not(preceding-sibling::*)]/upsilon[@xml:lang="en"]/beta[@xml:lang="en-GB"][not(following-sibling::*)]/omicron[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]/kappa[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:lang="en-GB"][following-sibling::*[position()=1]][not(preceding-sibling::beta)][following-sibling::nu[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//xi[not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]//sigma[@attr="this.nodeValue"][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[contains(concat(@desciption,"$"),"rue$")][@xml:id="id5"][preceding-sibling::*[position() = 1]]/tau[@xml:id="id6"][not(preceding-sibling::*)][not(preceding-sibling::tau)][following-sibling::delta[contains(@token,"-va")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <gamma content="this.nodeValue"> + <lambda xml:lang="no-nb"> + <upsilon xml:lang="en"> + <beta xml:lang="en-GB"> + <omicron xml:id="id1"/> + <upsilon xml:lang="no" xml:id="id2"> + <kappa xml:lang="en"> + <beta xml:lang="en-GB"/> + <nu xml:lang="en-GB"> + <xi/> + <sigma xml:lang="en" xml:id="id3"> + <sigma attr="this.nodeValue" xml:lang="en-GB" xml:id="id4"/> + <mu desciption="true" xml:id="id5"> + <tau xml:id="id6"/> + <delta token="attribute-value" xml:lang="en-US" xml:id="id7"> + <omicron xml:lang="en" xml:id="id8"> + <green>This text must be green</green> + </omicron> + </delta> + </mu> + </sigma> + </nu> + </kappa> + </upsilon> + </beta> + </upsilon> + </lambda> + </gamma> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="en-US"]//phi[@class][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::kappa[@delete]//gamma[starts-with(@att,"conten")][@xml:lang="nb"][not(preceding-sibling::*)]/chi[contains(concat(@desciption,"$"),"100%$")][@xml:lang="no"][not(following-sibling::*)]/omicron[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::chi[contains(@true,"alue")][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="en-US"> + <phi class="_blank" xml:lang="no-nb" xml:id="id1"/> + <kappa delete="attribute"> + <gamma att="content" xml:lang="nb"> + <chi desciption="100%" xml:lang="no"> + <omicron xml:id="id2"/> + <chi true="attribute value"> + <green>This text must be green</green> + </chi> + </chi> + </gamma> + </kappa> + </beta> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="no"]//epsilon[@xml:lang="en"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="en-US"]/phi[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::tau[@xml:id="id2"][not(child::node())][following-sibling::omicron[@abort="attribute"][@xml:lang="no"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::sigma/rho[@string][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(concat(@name,"-"),"content-")][not(child::node())][following-sibling::upsilon[@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]/zeta[@data][@xml:lang="nb"][following-sibling::*[position()=2]][following-sibling::xi[@true="true"][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::beta[@class][@xml:lang="nb"][preceding-sibling::*[position() = 2]]/epsilon[@insert][@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::theta[@xml:lang="no"][not(following-sibling::*)]/eta[contains(@token,"ute")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@xml:lang="en-GB"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[starts-with(@attr,"_")][@xml:lang="en-US"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::sigma[contains(@class,"ribut")][@xml:id="id8"]//pi[@false][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[@xml:id="id9"]][position() = 1]][position() = 1]]]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="no"> + <epsilon xml:lang="en"/> + <iota xml:lang="en-US"> + <phi xml:id="id1"/> + <tau xml:lang="en-US"/> + <eta/> + <tau xml:id="id2"/> + <omicron abort="attribute" xml:lang="no"/> + <sigma> + <rho string="another attribute value" xml:id="id3"/> + <pi name="content"/> + <upsilon xml:lang="nb" xml:id="id4"> + <zeta data="false" xml:lang="nb"/> + <xi true="true" xml:lang="en-GB"/> + <beta class="this.nodeValue" xml:lang="nb"> + <epsilon insert="123456789" xml:lang="nb" xml:id="id5"/> + <theta xml:lang="no"> + <eta token="attribute" xml:lang="no-nb"> + <theta xml:lang="en-GB" xml:id="id6"> + <gamma attr="_blank" xml:lang="en-US" xml:id="id7"/> + <sigma class="attribute" xml:id="id8"> + <pi false="this.nodeValue"/> + <theta xml:id="id9"> + <green>This text must be green</green> + </theta> + </sigma> + </theta> + </eta> + </theta> + </beta> + </upsilon> + </sigma> + </iota> + </pi> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="en-US"]/theta[@xml:id="id1"][not(child::node())][following-sibling::iota[@data][@xml:lang="nb"][not(child::node())][following-sibling::omega[@xml:id="id2"][not(child::node())][following-sibling::zeta[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/xi[@number="attribute-value"][@xml:id="id3"][not(preceding-sibling::*)]//mu[@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[@content][@xml:lang="en-GB"][not(preceding-sibling::*)]//upsilon[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@src][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[contains(@att,"is-att-value")][@xml:lang="en-US"][following-sibling::theta[@xml:id="id7"]/psi[@or][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::xi[preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="en-US"> + <theta xml:id="id1"/> + <iota data="_blank" xml:lang="nb"/> + <omega xml:id="id2"/> + <zeta> + <xi number="attribute-value" xml:id="id3"> + <mu xml:lang="en" xml:id="id4"> + <sigma content="100%" xml:lang="en-GB"> + <upsilon xml:id="id5"/> + <omicron src="123456789" xml:id="id6"> + <psi att="this-is-att-value" xml:lang="en-US"/> + <theta xml:id="id7"> + <psi or="solid 1px green" xml:id="id8"/> + <xi> + <green>This text must be green</green> + </xi> + </theta> + </omicron> + </sigma> + </mu> + </xi> + </zeta> + </pi> + </tree> + </test> + <test> + <xpath>//tau/theta[contains(@delete,"_blan")][@xml:lang="en-GB"][not(child::node())][following-sibling::epsilon[contains(concat(@title,"$"),"green$")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[not(following-sibling::*)]/chi[@or][not(preceding-sibling::*)]/zeta[@attrib][@xml:lang="no-nb"][@xml:id="id1"][not(following-sibling::*)]/theta[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[contains(@object,".nodeV")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//gamma[@xml:lang="no"][not(preceding-sibling::gamma or following-sibling::gamma)][not(child::node())][following-sibling::sigma[contains(concat(@and,"$"),"e$")][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::alpha[@xml:lang="no"][@xml:id="id4"][following-sibling::kappa[starts-with(concat(@false,"-"),"false-")][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 3]]//rho[@xml:id="id6"][not(preceding-sibling::*)]/omicron[contains(@attribute,"nt")][@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]//lambda[@false][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::tau[@xml:lang="en-US"][not(child::node())][following-sibling::tau[@token]/iota[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <tau> + <theta delete="_blank" xml:lang="en-GB"/> + <epsilon title="solid 1px green" xml:lang="nb"/> + <rho> + <chi or="false"> + <zeta attrib="content" xml:lang="no-nb" xml:id="id1"> + <theta xml:lang="en-US" xml:id="id2"/> + <nu object="this.nodeValue"> + <gamma xml:lang="no"/> + <sigma and="true" xml:id="id3"/> + <alpha xml:lang="no" xml:id="id4"/> + <kappa false="false" xml:lang="nb" xml:id="id5"> + <rho xml:id="id6"> + <omicron attribute="content" xml:lang="en" xml:id="id7"> + <lambda false="100%" xml:lang="no-nb"/> + <any xml:id="id8"/> + <tau xml:lang="en-US"/> + <tau token="attribute"> + <iota xml:lang="nb"> + <green>This text must be green</green> + </iota> + </tau> + </omicron> + </rho> + </kappa> + </nu> + </zeta> + </chi> + </rho> + </tau> + </tree> + </test> + <test> + <xpath>//pi[starts-with(concat(@delete,"-"),"this.nodeValue-")][@xml:lang="no-nb"]/tau[starts-with(concat(@content,"-"),"true-")][not(following-sibling::*)]//omega[starts-with(@data,"attribu")][@xml:lang="no-nb"][not(following-sibling::*)]//gamma[@xml:id="id1"][not(following-sibling::*)]/eta[@xml:lang="no-nb"][not(preceding-sibling::*)]/zeta[@false="true"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[not(following-sibling::*)]//omega[@xml:lang="en-GB"][following-sibling::*[position()=6]][following-sibling::iota[@xml:lang="en"][following-sibling::*[position()=5]][following-sibling::tau[@content="100%"][@xml:lang="nb"][following-sibling::sigma[starts-with(concat(@insert,"-"),"100%-")][@xml:lang="nb"][@xml:id="id2"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=3]][not(child::node())][following-sibling::gamma[@false="this-is-att-value"][@xml:id="id3"][not(child::node())][following-sibling::upsilon[following-sibling::chi[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]//theta[@insert][@xml:lang="en"][@xml:id="id5"][not(child::node())][following-sibling::iota[contains(concat(@delete,"$"),"ue$")][@xml:lang="en-GB"][@xml:id="id6"][not(following-sibling::*)]//mu[@xml:lang="en"][not(preceding-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <pi delete="this.nodeValue" xml:lang="no-nb"> + <tau content="true"> + <omega data="attribute-value" xml:lang="no-nb"> + <gamma xml:id="id1"> + <eta xml:lang="no-nb"> + <zeta false="true"/> + <epsilon> + <omega xml:lang="en-GB"/> + <iota xml:lang="en"/> + <tau content="100%" xml:lang="nb"/> + <sigma insert="100%" xml:lang="nb" xml:id="id2"/> + <gamma false="this-is-att-value" xml:id="id3"/> + <upsilon/> + <chi xml:lang="no-nb" xml:id="id4"> + <theta insert="_blank" xml:lang="en" xml:id="id5"/> + <iota delete="true" xml:lang="en-GB" xml:id="id6"> + <mu xml:lang="en"> + <green>This text must be green</green> + </mu> + </iota> + </chi> + </epsilon> + </eta> + </gamma> + </omega> + </tau> + </pi> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="nb"]/alpha[contains(@string,"8")][@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]/rho[contains(@data,"6789")][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[contains(concat(@and,"$"),"6789$")][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(concat(@src,"-"),"this-")][@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::iota[@string][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::kappa[@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@true="attribute"][@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 4]]//kappa[following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]]//kappa[@xml:lang="no-nb"][@xml:id="id6"][following-sibling::beta[starts-with(@string,"100")][@xml:lang="no"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="nb"> + <alpha string="123456789" xml:lang="nb" xml:id="id1"> + <rho data="123456789"> + <sigma and="123456789" xml:id="id2"/> + <upsilon src="this-is-att-value" xml:lang="en-GB" xml:id="id3"/> + <iota string="123456789" xml:lang="no-nb"/> + <kappa xml:lang="en-US"/> + <iota true="attribute" xml:lang="no-nb" xml:id="id4"> + <kappa/> + <chi xml:lang="no" xml:id="id5"> + <kappa xml:lang="no-nb" xml:id="id6"/> + <beta string="100%" xml:lang="no"> + <green>This text must be green</green> + </beta> + </chi> + </iota> + </rho> + </alpha> + </tau> + </tree> + </test> + <test> + <xpath>//gamma[contains(@insert,"bla")][@xml:lang="en-GB"][@xml:id="id1"]//omega[@xml:lang="en-US"][@xml:id="id2"][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::upsilon[@xml:id="id4"][preceding-sibling::*[position() = 2]]/beta[@delete][not(preceding-sibling::*)][not(following-sibling::*)]/kappa[@xml:lang="no-nb"][@xml:id="id5"][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <gamma insert="_blank" xml:lang="en-GB" xml:id="id1"> + <omega xml:lang="en-US" xml:id="id2"/> + <psi xml:lang="no" xml:id="id3"/> + <upsilon xml:id="id4"> + <beta delete="attribute value"> + <kappa xml:lang="no-nb" xml:id="id5"> + <green>This text must be green</green> + </kappa> + </beta> + </upsilon> + </gamma> + </tree> + </test> + <test> + <xpath>//zeta[contains(@delete,"%")][@xml:id="id1"]/mu[@xml:lang="en"][following-sibling::*[position()=1]][following-sibling::gamma[@xml:lang="no-nb"]/phi[@xml:lang="en-US"][@xml:id="id2"][following-sibling::upsilon[@and][@xml:lang="no"][@xml:id="id3"][not(preceding-sibling::upsilon)][following-sibling::pi[preceding-sibling::*[position() = 2]]/omega[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]/phi[@xml:id="id5"][following-sibling::pi[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::pi)]/theta[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::phi[starts-with(concat(@attribute,"-"),"this.nodeValue-")][@xml:lang="en"][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[starts-with(concat(@or,"-"),"attribute value-")][@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::psi[contains(concat(@att,"$"),"123456789$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 4]]/delta[not(preceding-sibling::*)][not(following-sibling::*)]/iota[@name="false"]//alpha[@xml:lang="en-GB"][@xml:id="id10"][not(preceding-sibling::*)]/nu[@xml:id="id11"][not(preceding-sibling::*)]//theta[@xml:lang="no-nb"][not(preceding-sibling::*)]/*/iota[contains(concat(@object,"$"),"true$")][@xml:id="id12"][not(child::node())][following-sibling::kappa[contains(@token,"k")][@xml:lang="nb"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta delete="100%" xml:id="id1"> + <mu xml:lang="en"/> + <gamma xml:lang="no-nb"> + <phi xml:lang="en-US" xml:id="id2"/> + <upsilon and="this.nodeValue" xml:lang="no" xml:id="id3"/> + <pi> + <omega xml:lang="no-nb" xml:id="id4"> + <phi xml:id="id5"/> + <pi xml:lang="en-US" xml:id="id6"> + <theta xml:id="id7"/> + <phi attribute="this.nodeValue" xml:lang="en" xml:id="id8"/> + <omega/> + <delta or="attribute value" xml:lang="en" xml:id="id9"/> + <psi att="123456789" xml:lang="en-GB"> + <delta> + <iota name="false"> + <alpha xml:lang="en-GB" xml:id="id10"> + <nu xml:id="id11"> + <theta xml:lang="no-nb"> + <any> + <iota object="true" xml:id="id12"/> + <kappa token="_blank" xml:lang="nb"> + <green>This text must be green</green> + </kappa> + </any> + </theta> + </nu> + </alpha> + </iota> + </delta> + </psi> + </pi> + </omega> + </pi> + </gamma> + </zeta> + </tree> + </test> + <test> + <xpath>//beta[@data][@xml:lang="en-US"]//iota[@attr="100%"][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::delta[contains(concat(@true,"$"),"ibute value$")][@xml:lang="en-US"]//rho[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)]//iota[not(preceding-sibling::*)][not(following-sibling::*)]//nu[contains(@name,"ute")][@xml:lang="no"][not(following-sibling::*)]/omega[@title][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]/theta[@delete][@xml:lang="no"][not(following-sibling::*)]/psi[not(child::node())][following-sibling::delta[@xml:id="id3"]/xi[contains(concat(@desciption,"$"),"te$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[preceding-sibling::*[position() = 1]]/upsilon[not(preceding-sibling::*)][not(following-sibling::*)]//iota/chi[contains(concat(@object,"$"),"e$")][@xml:id="id4"][following-sibling::omega[@class="attribute"][@xml:lang="no"][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <beta data="attribute-value" xml:lang="en-US"> + <iota attr="100%" xml:lang="en-US"/> + <delta true="another attribute value" xml:lang="en-US"> + <rho xml:lang="no" xml:id="id1"> + <iota> + <nu name="attribute" xml:lang="no"> + <omega title="123456789" xml:lang="en" xml:id="id2"> + <theta delete="content" xml:lang="no"> + <psi/> + <delta xml:id="id3"> + <xi desciption="attribute"/> + <pi> + <upsilon> + <iota> + <chi object="false" xml:id="id4"/> + <omega class="attribute" xml:lang="no"> + <green>This text must be green</green> + </omega> + </iota> + </upsilon> + </pi> + </delta> + </theta> + </omega> + </nu> + </iota> + </rho> + </delta> + </beta> + </tree> + </test> + <test> + <xpath>//chi[@att="this.nodeValue"][@xml:lang="en-GB"]/epsilon[@xml:lang="en-GB"][@xml:id="id1"][following-sibling::sigma[contains(concat(@data,"$"),"een$")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//gamma[@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[starts-with(@false,"c")][@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/alpha[contains(@number,"no")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]//mu[contains(concat(@and,"$"),"Value$")][following-sibling::rho[starts-with(concat(@data,"-"),"attribute-")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[contains(@title,"Value")][@xml:id="id6"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[@xml:lang="en-US"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <chi att="this.nodeValue" xml:lang="en-GB"> + <epsilon xml:lang="en-GB" xml:id="id1"/> + <sigma data="solid 1px green" xml:lang="en-US"> + <gamma xml:lang="no-nb" xml:id="id2"> + <tau false="content" xml:lang="en" xml:id="id3"> + <alpha number="another attribute value" xml:lang="en-US" xml:id="id4"> + <mu and="this.nodeValue"/> + <rho data="attribute" xml:id="id5"/> + <gamma title="this.nodeValue" xml:id="id6"/> + <omega xml:lang="en-US"> + <green>This text must be green</green> + </omega> + </alpha> + </tau> + </gamma> + </sigma> + </chi> + </tree> + </test> + <test> + <xpath>//xi[contains(@att,"ri")][@xml:id="id1"]//chi[@string="content"][@xml:id="id2"][not(preceding-sibling::*)]/pi[@abort][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id5"][not(following-sibling::*)]/chi[not(preceding-sibling::*)][following-sibling::iota[@name][@xml:lang="en-US"][following-sibling::rho[contains(concat(@att,"$"),"bute value$")][not(following-sibling::*)]/delta[@att][@xml:id="id6"][following-sibling::tau[contains(@attr,"t")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@xml:id="id8"][preceding-sibling::*[position() = 2]][not(preceding-sibling::kappa or following-sibling::kappa)]//psi[@xml:lang="en-GB"][@xml:id="id9"]/delta[@string][not(preceding-sibling::*)]//omicron/eta[starts-with(concat(@class,"-"),"content-")][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[starts-with(concat(@class,"-"),"123456789-")][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <xi att="attribute value" xml:id="id1"> + <chi string="content" xml:id="id2"> + <pi abort="attribute-value" xml:lang="en" xml:id="id3"/> + <chi> + <epsilon xml:id="id4"/> + <iota xml:id="id5"> + <chi/> + <iota name="_blank" xml:lang="en-US"/> + <rho att="another attribute value"> + <delta att="false" xml:id="id6"/> + <tau attr="attribute-value" xml:lang="en-US" xml:id="id7"/> + <kappa xml:id="id8"> + <psi xml:lang="en-GB" xml:id="id9"> + <delta string="attribute-value"> + <omicron> + <eta class="content" xml:lang="nb"> + <nu class="123456789"> + <green>This text must be green</green> + </nu> + </eta> + </omicron> + </delta> + </psi> + </kappa> + </rho> + </iota> + </chi> + </chi> + </xi> + </tree> + </test> + <test> + <xpath>//beta[@name]//rho[@desciption][@xml:id="id1"]/mu[@xml:lang="en"][not(child::node())][following-sibling::chi[@object][@xml:id="id2"][not(following-sibling::*)]/kappa[contains(concat(@or,"$"),"0%$")][@xml:id="id3"][following-sibling::omicron[starts-with(concat(@number,"-"),"another attribute value-")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=9]][not(preceding-sibling::omicron)][following-sibling::eta[@or="false"][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::sigma[@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=7]][following-sibling::epsilon[contains(concat(@delete,"$"),"rue$")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::eta[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=5]][following-sibling::beta[@xml:id="id7"][preceding-sibling::*[position() = 6]][not(child::node())][following-sibling::gamma[@xml:lang="en-GB"][preceding-sibling::*[position() = 7]][following-sibling::*[position()=3]][not(child::node())][following-sibling::pi[starts-with(@title,"ano")][@xml:lang="nb"][not(child::node())][following-sibling::eta[@content][@xml:lang="en-US"][@xml:id="id8"][following-sibling::*[starts-with(@and,"_blank")][@xml:lang="en-GB"][@xml:id="id9"][not(following-sibling::*)]/omicron[@abort="false"][@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@xml:lang="en-US"][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[starts-with(concat(@or,"-"),"false-")][@xml:lang="no"][@xml:id="id12"][preceding-sibling::*[position() = 1]]//rho[@xml:lang="no-nb"][@xml:id="id13"][following-sibling::zeta[starts-with(@name,"another attrib")][@xml:lang="no-nb"][not(child::node())][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id14"][not(following-sibling::*)]]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <beta name="this.nodeValue"> + <rho desciption="attribute" xml:id="id1"> + <mu xml:lang="en"/> + <chi object="attribute" xml:id="id2"> + <kappa or="100%" xml:id="id3"/> + <omicron number="another attribute value"/> + <eta or="false" xml:lang="en-US"/> + <sigma xml:lang="no-nb" xml:id="id4"/> + <epsilon delete="true" xml:lang="en-GB" xml:id="id5"/> + <eta xml:lang="en-US" xml:id="id6"/> + <beta xml:id="id7"/> + <gamma xml:lang="en-GB"/> + <pi title="another attribute value" xml:lang="nb"/> + <eta content="123456789" xml:lang="en-US" xml:id="id8"/> + <any and="_blank" xml:lang="en-GB" xml:id="id9"> + <omicron abort="false" xml:lang="no-nb" xml:id="id10"> + <lambda xml:lang="en-US" xml:id="id11"/> + <epsilon or="false" xml:lang="no" xml:id="id12"> + <rho xml:lang="no-nb" xml:id="id13"/> + <zeta name="another attribute value" xml:lang="no-nb"/> + <upsilon xml:lang="en-GB" xml:id="id14"> + <green>This text must be green</green> + </upsilon> + </epsilon> + </omicron> + </any> + </chi> + </rho> + </beta> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en"][@xml:id="id1"]/kappa[@src][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[contains(@attr,"another ")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::delta[not(preceding-sibling::delta or following-sibling::delta)]/*[@xml:lang="nb"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[starts-with(@and,"12345678")][@xml:lang="en-GB"][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omega[@delete="attribute-value"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//xi[@xml:lang="en"][following-sibling::iota[@xml:lang="en"][following-sibling::*[position()=1]][not(following-sibling::iota)][following-sibling::gamma[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//eta[@xml:id="id7"]/zeta[@true][@xml:id="id8"]/xi[contains(@token,"fa")][not(following-sibling::*)]//omicron[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//delta[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[starts-with(@att,"attr")][not(following-sibling::*)]//zeta[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[starts-with(concat(@true,"-"),"_blank-")][@xml:lang="en-GB"][@xml:id="id10"][not(preceding-sibling::*)]/theta[@object][@xml:lang="en-US"][@xml:id="id11"][not(preceding-sibling::*)][not(child::node())][following-sibling::theta[contains(@token,"blank")]/omega[not(preceding-sibling::*)][not(following-sibling::*)][not(parent::*/*[position()=2])]/iota[starts-with(@or,"_")][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[contains(concat(@insert,"$"),"ttribute$")][not(following-sibling::*)]//alpha[@xml:lang="no-nb"][not(preceding-sibling::*)]]][position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en" xml:id="id1"> + <kappa src="100%" xml:id="id2"/> + <upsilon attr="another attribute value" xml:lang="no" xml:id="id3"/> + <delta> + <any xml:lang="nb" xml:id="id4"/> + <psi and="123456789" xml:lang="en-GB" xml:id="id5"/> + <omega delete="attribute-value"> + <xi xml:lang="en"/> + <iota xml:lang="en"/> + <gamma xml:id="id6"> + <eta xml:id="id7"> + <zeta true="content" xml:id="id8"> + <xi token="false"> + <omicron xml:id="id9"> + <delta xml:lang="en-GB"/> + <xi att="attribute-value"> + <zeta xml:lang="nb"> + <alpha true="_blank" xml:lang="en-GB" xml:id="id10"> + <theta object="attribute-value" xml:lang="en-US" xml:id="id11"/> + <theta token="_blank"> + <omega> + <iota or="_blank"> + <sigma insert="attribute"> + <alpha xml:lang="no-nb"> + <green>This text must be green</green> + </alpha> + </sigma> + </iota> + </omega> + </theta> + </alpha> + </zeta> + </xi> + </omicron> + </xi> + </zeta> + </eta> + </gamma> + </omega> + </delta> + </sigma> + </tree> + </test> + <test> + <xpath>//eta[@true]/beta[starts-with(@attrib,"a")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="en-GB"][not(following-sibling::*)]/kappa[@title][@xml:lang="no"][following-sibling::omega[@xml:id="id1"][not(following-sibling::*)]/delta[@xml:lang="en-GB"][not(preceding-sibling::*)]//beta[@xml:lang="en-GB"]//eta[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@abort][following-sibling::*[position()=1]][following-sibling::rho[@xml:id="id3"]/gamma[@xml:id="id4"][not(following-sibling::*)]/gamma[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]]/epsilon[@false][@xml:lang="nb"][not(preceding-sibling::*)]/nu[not(parent::*/*[position()=2])]/zeta[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]//delta[@name="this-is-att-value"][not(child::node())][following-sibling::pi[@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <eta true="100%"> + <beta attrib="another attribute value" xml:lang="nb"/> + <psi xml:lang="en-GB"> + <kappa title="100%" xml:lang="no"/> + <omega xml:id="id1"> + <delta xml:lang="en-GB"> + <beta xml:lang="en-GB"> + <eta xml:lang="no" xml:id="id2"/> + <chi abort="attribute value"/> + <rho xml:id="id3"> + <gamma xml:id="id4"> + <gamma xml:id="id5"/> + <zeta xml:lang="en-US" xml:id="id6"> + <epsilon false="100%" xml:lang="nb"> + <nu> + <zeta xml:lang="en-GB" xml:id="id7"> + <delta name="this-is-att-value"/> + <pi xml:lang="en-GB"> + <green>This text must be green</green> + </pi> + </zeta> + </nu> + </epsilon> + </zeta> + </gamma> + </rho> + </beta> + </delta> + </omega> + </psi> + </eta> + </tree> + </test> + <test> + <xpath>//omega[starts-with(concat(@true,"-"),"123456789-")]//xi[contains(concat(@src,"$"),"true$")][@xml:id="id1"][not(following-sibling::*)]/psi[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::zeta[@xml:id="id3"]/upsilon[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::alpha[contains(concat(@content,"$"),"alse$")][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="en-GB"][@xml:id="id5"][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <omega true="123456789"> + <xi src="true" xml:id="id1"> + <psi xml:lang="en" xml:id="id2"/> + <zeta xml:id="id3"> + <upsilon xml:id="id4"/> + <alpha content="false" xml:lang="en"/> + <phi xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </phi> + </zeta> + </xi> + </omega> + </tree> + </test> + <test> + <xpath>//lambda[@insert][@xml:lang="en-US"]//delta[@xml:lang="en-GB"][@xml:id="id1"][following-sibling::*[position()=2]][following-sibling::kappa[@attribute][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@data][@xml:id="id3"][not(following-sibling::kappa)]/zeta[contains(@att,"1")][@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]/kappa[@xml:lang="en-US"][not(following-sibling::*)]//*[contains(@src,"u")][@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[contains(concat(@att,"$"),"e$")][@xml:lang="en"][@xml:id="id6"][not(following-sibling::*)]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <lambda insert="100%" xml:lang="en-US"> + <delta xml:lang="en-GB" xml:id="id1"/> + <kappa attribute="123456789" xml:id="id2"/> + <kappa data="another attribute value" xml:id="id3"> + <zeta att="100%" xml:lang="en-US" xml:id="id4"> + <kappa xml:lang="en-US"> + <any src="true" xml:lang="no-nb" xml:id="id5"> + <psi att="false" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </psi> + </any> + </kappa> + </zeta> + </kappa> + </lambda> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="en-GB"]//*[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[starts-with(concat(@and,"-"),"another attribute value-")][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//delta[@content="false"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::delta[starts-with(@delete,"12")][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[@xml:id="id3"][not(following-sibling::*)]/kappa[contains(concat(@attrib,"$")," attribute value$")][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:id="id4"][not(following-sibling::*)]/sigma[not(preceding-sibling::*)][not(following-sibling::*)]//delta[contains(@insert,"ank")][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//phi/delta[starts-with(@src,"attribut")][@xml:id="id6"][not(preceding-sibling::*)]/gamma[@xml:lang="en-GB"][@xml:id="id7"][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="en-GB"> + <any/> + <xi and="another attribute value" xml:id="id1"> + <delta content="false" xml:id="id2"/> + <delta delete="123456789"/> + <nu> + <tau xml:id="id3"> + <kappa attrib="another attribute value"/> + <gamma xml:id="id4"> + <sigma> + <delta insert="_blank" xml:lang="en" xml:id="id5"> + <phi> + <delta src="attribute" xml:id="id6"> + <gamma xml:lang="en-GB" xml:id="id7"> + <green>This text must be green</green> + </gamma> + </delta> + </phi> + </delta> + </sigma> + </gamma> + </tau> + </nu> + </xi> + </delta> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="no"]//omega[starts-with(@src,"tru")][@xml:lang="en"][not(following-sibling::*)]//omega[starts-with(@false,"another attribu")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:id="id1"][not(following-sibling::*)]/pi[@and][@xml:lang="en"][not(following-sibling::*)]/omicron[@xml:id="id2"][following-sibling::zeta[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::omega[contains(concat(@name,"$"),"lse$")][@xml:lang="en"][not(following-sibling::*)]//theta[@att][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::eta[@token][@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/gamma[@xml:id="id4"]//beta[@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 1]]//tau[@attr][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="en"][@xml:id="id6"][not(preceding-sibling::delta)]/tau[starts-with(@attrib,"c")][@xml:lang="no"][not(preceding-sibling::*)]/gamma[contains(@true,"alue")][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>1</nth> + </result> + <tree> + <kappa xml:lang="no"> + <omega src="true" xml:lang="en"> + <omega false="another attribute value" xml:lang="en-US"/> + <xi xml:id="id1"> + <pi and="123456789" xml:lang="en"> + <omicron xml:id="id2"/> + <zeta/> + <omega name="false" xml:lang="en"> + <theta att="100%" xml:id="id3"/> + <eta token="true" xml:lang="no"> + <gamma xml:id="id4"> + <beta xml:lang="nb" xml:id="id5"/> + <upsilon> + <tau attr="content"/> + <delta xml:lang="en" xml:id="id6"> + <tau attrib="content" xml:lang="no"> + <gamma true="this.nodeValue"> + <green>This text must be green</green> + </gamma> + </tau> + </delta> + </upsilon> + </gamma> + </eta> + </omega> + </pi> + </xi> + </omega> + </kappa> + </tree> + </test> + <test> + <xpath>//kappa[@delete][@xml:id="id1"]/gamma[starts-with(@name,"false")][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=4]][not(child::node())][following-sibling::mu[following-sibling::kappa[starts-with(concat(@delete,"-"),"attribute-")][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::iota[starts-with(concat(@class,"-"),"this.nodeValue-")][@xml:id="id4"][not(child::node())][following-sibling::*[@xml:id="id5"][preceding-sibling::*[position() = 4]]/delta[contains(@object,"t")][@xml:id="id6"]/iota[@content][@xml:lang="en-GB"][@xml:id="id7"][not(child::node())][following-sibling::pi[@xml:lang="no-nb"][@xml:id="id8"]//phi[@content][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:lang="no-nb"][not(following-sibling::*)]//iota[starts-with(@and,"soli")][not(preceding-sibling::*)][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <kappa delete="attribute value" xml:id="id1"> + <gamma name="false" xml:lang="nb" xml:id="id2"/> + <mu/> + <kappa delete="attribute" xml:lang="no-nb" xml:id="id3"/> + <iota class="this.nodeValue" xml:id="id4"/> + <any xml:id="id5"> + <delta object="another attribute value" xml:id="id6"> + <iota content="another attribute value" xml:lang="en-GB" xml:id="id7"/> + <pi xml:lang="no-nb" xml:id="id8"> + <phi content="this.nodeValue" xml:id="id9"/> + <lambda xml:lang="no-nb"> + <iota and="solid 1px green"> + <green>This text must be green</green> + </iota> + </lambda> + </pi> + </delta> + </any> + </kappa> + </tree> + </test> + <test> + <xpath>//*[contains(@class,"23")][@xml:id="id1"]//omicron[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)]//psi[starts-with(@attribute,"solid 1px gr")][@xml:lang="no-nb"][following-sibling::*[position()=7]][following-sibling::xi[contains(@number,"k")][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=6]][following-sibling::eta[@xml:id="id4"][following-sibling::sigma[@xml:lang="nb"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::pi[@delete="content"][preceding-sibling::*[position() = 4]][following-sibling::*[@xml:lang="no"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::gamma[contains(@class,"his-is-att-value")][@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 6]][following-sibling::lambda[@xml:id="id6"][preceding-sibling::*[position() = 7]]/rho[@xml:lang="nb"][not(preceding-sibling::*)]/eta[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[starts-with(concat(@attrib,"-"),"this-")][@xml:lang="nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::theta[@and][@xml:id="id8"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/*[@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/*[@insert][not(preceding-sibling::*)]//gamma[@true][@xml:lang="no"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@abort="another attribute value"][@xml:lang="en-GB"]]][position() = 1]]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <any class="123456789" xml:id="id1"> + <omicron token="attribute-value" xml:lang="no" xml:id="id2"> + <psi attribute="solid 1px green" xml:lang="no-nb"/> + <xi number="_blank" xml:lang="no-nb" xml:id="id3"/> + <eta xml:id="id4"/> + <sigma xml:lang="nb"/> + <pi delete="content"/> + <any xml:lang="no"/> + <gamma class="this-is-att-value" xml:lang="nb" xml:id="id5"/> + <lambda xml:id="id6"> + <rho xml:lang="nb"> + <eta xml:lang="en" xml:id="id7"> + <lambda attrib="this-is-att-value" xml:lang="nb"/> + <theta and="true" xml:id="id8"> + <any xml:lang="no"> + <any insert="attribute value"> + <gamma true="100%" xml:lang="no" xml:id="id9"/> + <kappa abort="another attribute value" xml:lang="en-GB"> + <green>This text must be green</green> + </kappa> + </any> + </any> + </theta> + </eta> + </rho> + </lambda> + </omicron> + </any> + </tree> + </test> + <test> + <xpath>//rho[@token][@xml:lang="nb"]//omicron[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::epsilon[@xml:id="id2"][preceding-sibling::*[position() = 2]]//epsilon[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::omicron[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(concat(@abort,"$"),"0%$")][not(preceding-sibling::delta)][following-sibling::phi[@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <rho token="solid 1px green" xml:lang="nb"> + <omicron xml:id="id1"/> + <upsilon xml:lang="en-GB"/> + <epsilon xml:id="id2"> + <epsilon xml:lang="no" xml:id="id3"/> + <omicron/> + <delta abort="100%"/> + <phi xml:lang="en-GB"> + <green>This text must be green</green> + </phi> + </epsilon> + </rho> + </tree> + </test> + <test> + <xpath>//eta[contains(concat(@false,"$"),"true$")][@xml:lang="no-nb"]/iota[starts-with(@insert,"c")][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::omega[@xml:lang="nb"][not(following-sibling::*)]/nu[starts-with(@string,"f")][@xml:lang="en-GB"][@xml:id="id2"]/eta[@xml:lang="en"][not(following-sibling::*)]/xi[starts-with(concat(@token,"-"),"123456789-")][@xml:id="id3"][not(child::node())][following-sibling::pi[starts-with(@content,"100%")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[starts-with(@false,"12")][@xml:lang="no-nb"][following-sibling::*[position()=1]][following-sibling::*[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta[contains(@string,"nk")][@xml:id="id7"][following-sibling::gamma[@number][@xml:lang="no"][@xml:id="id8"][following-sibling::phi[contains(concat(@title,"$"),"0%$")]//omega[@xml:lang="no-nb"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::zeta[contains(concat(@and,"$"),"tribute value$")][@xml:id="id10"][preceding-sibling::*[position() = 1]]//tau[@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::zeta[@xml:id="id12"][preceding-sibling::*[position() = 1]]/sigma[contains(@token,"456789")][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <eta false="true" xml:lang="no-nb"> + <iota insert="content" xml:id="id1"/> + <omega xml:lang="nb"> + <nu string="false" xml:lang="en-GB" xml:id="id2"> + <eta xml:lang="en"> + <xi token="123456789" xml:id="id3"/> + <pi content="100%" xml:lang="no" xml:id="id4"> + <epsilon xml:lang="en" xml:id="id5"> + <tau false="123456789" xml:lang="no-nb"/> + <any xml:lang="en-US" xml:id="id6"> + <zeta string="_blank" xml:id="id7"/> + <gamma number="123456789" xml:lang="no" xml:id="id8"/> + <phi title="100%"> + <omega xml:lang="no-nb" xml:id="id9"/> + <zeta and="another attribute value" xml:id="id10"> + <tau xml:id="id11"/> + <zeta xml:id="id12"> + <sigma token="123456789"> + <green>This text must be green</green> + </sigma> + </zeta> + </zeta> + </phi> + </any> + </epsilon> + </pi> + </eta> + </nu> + </omega> + </eta> + </tree> + </test> + <test> + <xpath>//kappa[contains(concat(@insert,"$"),"00%$")][@xml:lang="en-GB"][@xml:id="id1"]//pi[@xml:lang="no"][@xml:id="id2"][not(following-sibling::*)]/zeta[@xml:lang="en-US"][not(preceding-sibling::*)]/tau[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::delta[@token="this.nodeValue"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[not(preceding-sibling::*)][not(child::node())][following-sibling::alpha/pi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::eta[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(preceding-sibling::eta)][following-sibling::tau[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//mu[starts-with(concat(@desciption,"-"),"100%-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@string="attribute-value"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <kappa insert="100%" xml:lang="en-GB" xml:id="id1"> + <pi xml:lang="no" xml:id="id2"> + <zeta xml:lang="en-US"> + <tau xml:id="id3"/> + <delta token="this.nodeValue"> + <phi/> + <alpha> + <pi xml:lang="no-nb"/> + <eta xml:lang="en" xml:id="id4"/> + <tau xml:lang="en-US" xml:id="id5"> + <mu desciption="100%"/> + <any xml:lang="en-GB"> + <chi string="attribute-value" xml:id="id6"> + <green>This text must be green</green> + </chi> + </any> + </tau> + </alpha> + </delta> + </zeta> + </pi> + </kappa> + </tree> + </test> + <test> + <xpath>//upsilon[starts-with(concat(@att,"-"),"_blank-")][@xml:lang="no-nb"]/chi[@object][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)]/alpha[@xml:lang="no-nb"][@xml:id="id3"]//iota[starts-with(@object,"1")][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::omega[starts-with(@delete,"123456")][@xml:lang="nb"][preceding-sibling::*[position() = 1]]/xi[starts-with(@content,"attribute-v")][@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::phi[not(following-sibling::*)]//lambda[contains(@token,"als")][@xml:lang="no"][@xml:id="id6"][following-sibling::lambda[starts-with(concat(@data,"-"),"false-")][@xml:id="id7"][not(following-sibling::*)]/iota[contains(@desciption,"k")][@xml:lang="en"][@xml:id="id8"]//theta[@insert][@xml:id="id9"][not(preceding-sibling::*)]//alpha[@xml:id="id10"][following-sibling::*[position()=2]][following-sibling::mu[@xml:lang="nb"][@xml:id="id11"][following-sibling::pi[contains(@attr,"ttribute")][@xml:lang="en-US"][@xml:id="id12"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/alpha[starts-with(concat(@or,"-"),"_blank-")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[starts-with(concat(@name,"-"),"attribute-")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::alpha[@xml:lang="nb"][following-sibling::*[position()=1]][not(preceding-sibling::alpha)][not(child::node())][following-sibling::upsilon[@xml:lang="nb"]/kappa[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::sigma[@xml:id="id13"][not(following-sibling::*)]//gamma[@xml:lang="nb"][@xml:id="id14"][not(following-sibling::*)]/omicron[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <upsilon att="_blank" xml:lang="no-nb"> + <chi object="true" xml:lang="no-nb" xml:id="id1"> + <nu xml:lang="nb" xml:id="id2"> + <alpha xml:lang="no-nb" xml:id="id3"> + <iota object="123456789" xml:lang="en-GB" xml:id="id4"/> + <omega delete="123456789" xml:lang="nb"> + <xi content="attribute-value" xml:lang="no-nb" xml:id="id5"/> + <phi> + <lambda token="false" xml:lang="no" xml:id="id6"/> + <lambda data="false" xml:id="id7"> + <iota desciption="_blank" xml:lang="en" xml:id="id8"> + <theta insert="attribute" xml:id="id9"> + <alpha xml:id="id10"/> + <mu xml:lang="nb" xml:id="id11"/> + <pi attr="attribute" xml:lang="en-US" xml:id="id12"> + <alpha or="_blank" xml:lang="no-nb"> + <xi name="attribute-value" xml:lang="en-GB"/> + <alpha xml:lang="nb"/> + <upsilon xml:lang="nb"> + <kappa xml:lang="no-nb"/> + <sigma xml:id="id13"> + <gamma xml:lang="nb" xml:id="id14"> + <omicron xml:lang="nb"> + <green>This text must be green</green> + </omicron> + </gamma> + </sigma> + </upsilon> + </alpha> + </pi> + </theta> + </iota> + </lambda> + </phi> + </omega> + </alpha> + </nu> + </chi> + </upsilon> + </tree> + </test> + <test> + <xpath>//eta[starts-with(concat(@object,"-"),"content-")]/nu[@and="solid 1px green"][@xml:lang="en-US"][@xml:id="id1"][not(child::node())][following-sibling::tau[contains(concat(@attribute,"$"),"lank$")]//tau[@xml:id="id2"][not(child::node())][following-sibling::mu[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[contains(concat(@number,"$"),"ontent$")][@xml:id="id3"][not(following-sibling::*)]/iota[contains(concat(@class,"$"),"odeValue$")][@xml:id="id4"][not(following-sibling::*)]//lambda[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@string][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::omega[@xml:id="id5"][preceding-sibling::*[position() = 2]]/phi[@xml:lang="no"]/*[starts-with(concat(@attrib,"-"),"this.nodeValue-")][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@xml:lang="nb"]/beta[starts-with(concat(@token,"-"),"false-")][@xml:lang="nb"][following-sibling::mu[starts-with(concat(@content,"-"),"another attribute value-")][@xml:lang="no"][@xml:id="id8"][following-sibling::delta[preceding-sibling::*[position() = 2]][following-sibling::omega[contains(@desciption,"tr")]/phi[not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[@xml:lang="en-US"]/eta[@xml:lang="no-nb"][@xml:id="id9"][not(following-sibling::*)]/sigma[@xml:lang="nb"][@xml:id="id10"][not(following-sibling::*)]/lambda[not(following-sibling::*)]/upsilon[starts-with(concat(@content,"-"),"content-")][@xml:lang="en-US"][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <eta object="content"> + <nu and="solid 1px green" xml:lang="en-US" xml:id="id1"/> + <tau attribute="_blank"> + <tau xml:id="id2"/> + <mu xml:lang="en-US"> + <tau number="content" xml:id="id3"> + <iota class="this.nodeValue" xml:id="id4"> + <lambda xml:lang="en"/> + <rho string="attribute" xml:lang="en-GB"/> + <omega xml:id="id5"> + <phi xml:lang="no"> + <any attrib="this.nodeValue" xml:id="id6"> + <iota xml:id="id7"> + <alpha xml:lang="nb"> + <beta token="false" xml:lang="nb"/> + <mu content="another attribute value" xml:lang="no" xml:id="id8"/> + <delta/> + <omega desciption="true"> + <phi/> + <sigma xml:lang="en-US"> + <eta xml:lang="no-nb" xml:id="id9"> + <sigma xml:lang="nb" xml:id="id10"> + <lambda> + <upsilon content="content" xml:lang="en-US"> + <green>This text must be green</green> + </upsilon> + </lambda> + </sigma> + </eta> + </sigma> + </omega> + </alpha> + </iota> + </any> + </phi> + </omega> + </iota> + </tau> + </mu> + </tau> + </eta> + </tree> + </test> + <test> + <xpath>//psi[contains(@name,"e")][@xml:lang="no"][@xml:id="id1"]//chi[@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:id="id3"][not(following-sibling::*)]/alpha[not(preceding-sibling::*)]//nu[@xml:id="id4"]//kappa[contains(concat(@false,"$"),"nother attribute value$")][following-sibling::sigma[@xml:lang="en-US"][not(following-sibling::*)]/mu[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[starts-with(@delete,"solid 1p")]/psi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[not(following-sibling::*)]/chi[contains(@name,"%")][@xml:lang="no-nb"][@xml:id="id6"][following-sibling::phi[preceding-sibling::*[position() = 1]]//iota[@xml:lang="no-nb"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@xml:lang="en"][@xml:id="id8"][not(preceding-sibling::*)]/chi[starts-with(concat(@delete,"-"),"true-")][@xml:lang="en-US"][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <psi name="another attribute value" xml:lang="no" xml:id="id1"> + <chi xml:lang="en" xml:id="id2"/> + <phi xml:id="id3"> + <alpha> + <nu xml:id="id4"> + <kappa false="another attribute value"/> + <sigma xml:lang="en-US"> + <mu xml:id="id5"/> + <lambda xml:lang="no"/> + <nu delete="solid 1px green"> + <psi xml:lang="no-nb"/> + <omega> + <chi name="100%" xml:lang="no-nb" xml:id="id6"/> + <phi> + <iota xml:lang="no-nb" xml:id="id7"/> + <xi> + <chi xml:lang="en" xml:id="id8"> + <chi delete="true" xml:lang="en-US"> + <green>This text must be green</green> + </chi> + </chi> + </xi> + </phi> + </omega> + </nu> + </sigma> + </nu> + </alpha> + </phi> + </psi> + </tree> + </test> + <test> + <xpath>//zeta[@xml:lang="en-US"]/theta[@title][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::nu[@number="123456789"][@xml:lang="no"]/sigma[starts-with(@attribute,"attribu")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en"][following-sibling::*[position()=2]][not(child::node())][following-sibling::sigma[@and][@xml:id="id1"][preceding-sibling::sigma[2]][not(child::node())][following-sibling::omega[@xml:id="id2"]/nu[@insert="123456789"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[contains(concat(@abort,"$"),"eValue$")][@xml:id="id4"][not(child::node())][following-sibling::kappa[preceding-sibling::*[position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <zeta xml:lang="en-US"> + <theta title="solid 1px green" xml:lang="en-US"/> + <nu number="123456789" xml:lang="no"> + <sigma attribute="attribute-value" xml:lang="nb"/> + <sigma xml:lang="en"/> + <sigma and="123456789" xml:id="id1"/> + <omega xml:id="id2"> + <nu insert="123456789" xml:id="id3"> + <omega abort="this.nodeValue" xml:id="id4"/> + <kappa> + <green>This text must be green</green> + </kappa> + </nu> + </omega> + </nu> + </zeta> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no-nb"]/omega[@xml:lang="en-GB"][@xml:id="id1"][not(following-sibling::*)]//alpha[@xml:lang="no"][@xml:id="id2"]//tau[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[following-sibling::eta[@number][@xml:lang="no"][@xml:id="id3"]//epsilon[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]/sigma[@xml:id="id5"][not(child::node())][following-sibling::theta[starts-with(concat(@name,"-"),"true-")][@xml:lang="en-US"][not(child::node())][following-sibling::rho//xi[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="en"][@xml:id="id6"]//sigma[@title][@xml:lang="en"][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <beta xml:lang="no-nb"> + <omega xml:lang="en-GB" xml:id="id1"> + <alpha xml:lang="no" xml:id="id2"> + <tau xml:lang="en-GB"/> + <lambda/> + <eta number="solid 1px green" xml:lang="no" xml:id="id3"> + <epsilon xml:lang="en-US" xml:id="id4"> + <sigma xml:id="id5"/> + <theta name="true" xml:lang="en-US"/> + <rho> + <xi content="attribute-value" xml:lang="en" xml:id="id6"> + <sigma title="100%" xml:lang="en"> + <green>This text must be green</green> + </sigma> + </xi> + </rho> + </epsilon> + </eta> + </alpha> + </omega> + </beta> + </tree> + </test> + <test> + <xpath>//zeta[@content]/chi[not(child::node())][following-sibling::*[starts-with(@abort,"att")][@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 1]]//mu[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[contains(@false,"ribute")][@xml:lang="en-GB"]/alpha[@number][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@src][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::omicron[@abort="_blank"][@xml:id="id4"][not(child::node())][following-sibling::iota[@xml:lang="nb"][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::omega[@xml:lang="no-nb"][@xml:id="id5"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//xi[following-sibling::*[position()=2]][not(child::node())][following-sibling::mu[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::tau[@data][@xml:id="id6"][not(following-sibling::*)]//iota[@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en"][preceding-sibling::*[position() = 1]]//sigma[@true][@xml:lang="en"][@xml:id="id8"][following-sibling::beta[preceding-sibling::*[position() = 1]][following-sibling::omicron[@xml:lang="no-nb"][not(following-sibling::*)][position() = 1]]]]][position() = 1]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <zeta content="this-is-att-value"> + <chi/> + <any abort="attribute" xml:lang="en-US" xml:id="id1"> + <mu xml:lang="en-GB" xml:id="id2"> + <alpha false="attribute" xml:lang="en-GB"> + <alpha number="this-is-att-value" xml:lang="en-GB"> + <epsilon src="solid 1px green" xml:id="id3"/> + <omicron abort="_blank" xml:id="id4"/> + <iota xml:lang="nb"/> + <phi/> + <omega xml:lang="no-nb" xml:id="id5"> + <xi/> + <mu xml:lang="no"/> + <tau data="another attribute value" xml:id="id6"> + <iota xml:id="id7"/> + <omicron xml:lang="en"> + <sigma true="_blank" xml:lang="en" xml:id="id8"/> + <beta/> + <omicron xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </omicron> + </tau> + </omega> + </alpha> + </alpha> + </mu> + </any> + </zeta> + </tree> + </test> + <test> + <xpath>//gamma[@xml:id="id1"]/*[following-sibling::*[position()=3]][not(child::node())][following-sibling::eta[preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="en-GB"][following-sibling::lambda[@xml:lang="no-nb"][@xml:id="id2"][preceding-sibling::*[position() = 3]]/omega[not(preceding-sibling::*)][not(following-sibling::*)]//omega//delta[starts-with(@attrib,"10")][following-sibling::*[position()=3]][not(child::node())][following-sibling::gamma[@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::chi[starts-with(@content,"100%")][@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[starts-with(@string,"att")][@xml:id="id4"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/sigma[@xml:lang="nb"][@xml:id="id5"][not(child::node())][following-sibling::nu[starts-with(concat(@att,"-"),"_blank-")][preceding-sibling::*[position() = 1]]/rho[@xml:lang="nb"][@xml:id="id6"]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <gamma xml:id="id1"> + <any/> + <eta/> + <xi xml:lang="en-GB"/> + <lambda xml:lang="no-nb" xml:id="id2"> + <omega> + <omega> + <delta attrib="100%"/> + <gamma xml:lang="no" xml:id="id3"/> + <chi content="100%" xml:lang="no"/> + <any string="attribute value" xml:id="id4"> + <sigma xml:lang="nb" xml:id="id5"/> + <nu att="_blank"> + <rho xml:lang="nb" xml:id="id6"> + <green>This text must be green</green> + </rho> + </nu> + </any> + </omega> + </omega> + </lambda> + </gamma> + </tree> + </test> + <test> + <xpath>//phi[@xml:lang="en-GB"]//chi[@xml:id="id1"][not(child::node())][following-sibling::delta[@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[starts-with(@number,"123456")][@xml:lang="en"][not(following-sibling::*)]//zeta[@xml:id="id2"][not(preceding-sibling::*)]//beta[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:lang="no"][@xml:id="id4"][not(child::node())][following-sibling::alpha[contains(@false,"0%")][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[following-sibling::tau[@xml:id="id6"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//psi[starts-with(@string,"12345")][@xml:lang="nb"][@xml:id="id7"][not(preceding-sibling::*)]//delta[@delete][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//mu[@delete][not(preceding-sibling::*)]//xi[starts-with(concat(@abort,"-"),"123456789-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(preceding-sibling::xi)]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <phi xml:lang="en-GB"> + <chi xml:id="id1"/> + <delta xml:lang="en"/> + <any xml:lang="en"> + <lambda number="123456789" xml:lang="en"> + <zeta xml:id="id2"> + <beta xml:id="id3"> + <psi xml:lang="no" xml:id="id4"/> + <alpha false="100%" xml:id="id5"/> + <zeta/> + <tau xml:id="id6"> + <psi string="123456789" xml:lang="nb" xml:id="id7"> + <delta delete="_blank" xml:lang="en-US"> + <mu delete="attribute value"> + <xi abort="123456789" xml:lang="en-GB"> + <green>This text must be green</green> + </xi> + </mu> + </delta> + </psi> + </tau> + </beta> + </zeta> + </lambda> + </any> + </phi> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no"]//omega[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::rho[@xml:lang="en"][@xml:id="id1"][following-sibling::*[position()=2]][not(child::node())][following-sibling::nu[starts-with(concat(@string,"-"),"attribute-")][@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::chi[starts-with(concat(@object,"-"),"123456789-")][@xml:id="id3"][not(following-sibling::*)]//psi[@true][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="no-nb"][@xml:id="id4"][not(following-sibling::*)]//rho[contains(@true,"%")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@xml:id="id6"][not(following-sibling::*)]//lambda[@title][@xml:lang="en"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@att][@xml:id="id8"][preceding-sibling::*[position() = 1]]/*[@desciption][@xml:id="id9"][not(preceding-sibling::any)][not(child::node())][following-sibling::zeta[@att][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::phi[@attribute="this.nodeValue"][@xml:lang="no"][preceding-sibling::*[position() = 2]]//beta[contains(@title,"ue")][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@xml:id="id11"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[contains(@insert,"lan")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::epsilon[@name][@xml:id="id12"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no"> + <omega xml:lang="en-US"/> + <rho xml:lang="en" xml:id="id1"/> + <nu string="attribute-value" xml:id="id2"/> + <chi object="123456789" xml:id="id3"> + <psi true="true"/> + <xi xml:lang="no-nb" xml:id="id4"> + <rho true="100%" xml:id="id5"> + <pi xml:id="id6"> + <lambda title="123456789" xml:lang="en" xml:id="id7"/> + <mu att="solid 1px green" xml:id="id8"> + <any desciption="123456789" xml:id="id9"/> + <zeta att="this-is-att-value" xml:lang="no-nb"/> + <phi attribute="this.nodeValue" xml:lang="no"> + <beta title="attribute-value" xml:id="id10"/> + <pi xml:id="id11"/> + <delta insert="_blank" xml:lang="en-US"/> + <epsilon name="this-is-att-value" xml:id="id12"> + <green>This text must be green</green> + </epsilon> + </phi> + </mu> + </pi> + </rho> + </xi> + </chi> + </iota> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="nb"][@xml:id="id1"]//xi[not(following-sibling::*)]//sigma/chi[starts-with(concat(@delete,"-"),"false-")][not(preceding-sibling::*)][not(following-sibling::*)]//phi[not(child::node())][following-sibling::iota[@attr][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[@attribute="solid 1px green"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:lang="en"]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="nb" xml:id="id1"> + <xi> + <sigma> + <chi delete="false"> + <phi/> + <iota attr="attribute-value"> + <phi attribute="solid 1px green"> + <sigma xml:lang="en"> + <green>This text must be green</green> + </sigma> + </phi> + </iota> + </chi> + </sigma> + </xi> + </iota> + </tree> + </test> + <test> + <xpath>//xi[contains(@object,"al")][@xml:lang="nb"][@xml:id="id1"]/omega[starts-with(@data,"12345678")][@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@token][@xml:lang="en-US"][following-sibling::lambda[@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]/omega[starts-with(concat(@data,"-"),"true-")][@xml:id="id5"][not(following-sibling::*)]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <xi object="false" xml:lang="nb" xml:id="id1"> + <omega data="123456789" xml:lang="en-GB" xml:id="id2"/> + <any xml:lang="en" xml:id="id3"/> + <alpha token="false" xml:lang="en-US"/> + <lambda xml:lang="nb" xml:id="id4"> + <omega data="true" xml:id="id5"> + <green>This text must be green</green> + </omega> + </lambda> + </xi> + </tree> + </test> + <test> + <xpath>//lambda[@string="another attribute value"][@xml:id="id1"]/delta[@xml:lang="en-US"][not(following-sibling::*)]/kappa[@attrib="solid 1px green"][@xml:id="id2"][not(preceding-sibling::*)]//iota[@xml:id="id3"][not(preceding-sibling::*)]//chi[following-sibling::*[position()=4]][not(child::node())][following-sibling::rho[@xml:id="id4"][following-sibling::tau[@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 3]][following-sibling::zeta[@xml:id="id6"]//lambda[@xml:lang="no-nb"][following-sibling::theta[starts-with(concat(@data,"-"),"another attribute value-")][not(following-sibling::*)]/delta[starts-with(concat(@token,"-"),"false-")][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[@xml:id="id7"][preceding-sibling::*[position() = 1]]//iota[starts-with(concat(@attribute,"-"),"true-")][@xml:id="id8"][not(following-sibling::*)]/lambda[@xml:lang="en"][@xml:id="id9"][not(following-sibling::*)]//omicron[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[@token][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[@xml:lang="no"][@xml:id="id11"][not(preceding-sibling::*)]/psi[starts-with(@att,"this-is")][@xml:lang="en"][not(preceding-sibling::*)][following-sibling::*[@attrib][@xml:lang="en-US"][@xml:id="id12"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//iota[@or="solid 1px green"][@xml:id="id13"][not(preceding-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <lambda string="another attribute value" xml:id="id1"> + <delta xml:lang="en-US"> + <kappa attrib="solid 1px green" xml:id="id2"> + <iota xml:id="id3"> + <chi/> + <rho xml:id="id4"/> + <tau xml:lang="no" xml:id="id5"/> + <beta/> + <zeta xml:id="id6"> + <lambda xml:lang="no-nb"/> + <theta data="another attribute value"> + <delta token="false"/> + <lambda xml:id="id7"> + <iota attribute="true" xml:id="id8"> + <lambda xml:lang="en" xml:id="id9"> + <omicron xml:lang="en-GB"> + <beta xml:id="id10"> + <nu token="another attribute value"> + <sigma xml:lang="no" xml:id="id11"> + <psi att="this-is-att-value" xml:lang="en"/> + <any attrib="false" xml:lang="en-US" xml:id="id12"> + <iota or="solid 1px green" xml:id="id13"> + <green>This text must be green</green> + </iota> + </any> + </sigma> + </nu> + </beta> + </omicron> + </lambda> + </iota> + </lambda> + </theta> + </zeta> + </iota> + </kappa> + </delta> + </lambda> + </tree> + </test> + <test> + <xpath>//xi/nu[starts-with(@name,"_bla")][@xml:id="id1"]//upsilon[@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 1]]/chi[@string][@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[contains(@attrib,"tt-value")][not(following-sibling::*)]//chi[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[starts-with(@class,"c")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi//alpha[not(following-sibling::*)]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <xi> + <nu name="_blank" xml:id="id1"> + <upsilon xml:lang="en-GB"/> + <upsilon> + <chi string="true" xml:lang="nb" xml:id="id2"/> + <sigma attrib="this-is-att-value"> + <chi xml:lang="en-US" xml:id="id3"/> + <rho class="content"/> + <pi> + <alpha> + <green>This text must be green</green> + </alpha> + </pi> + </sigma> + </upsilon> + </nu> + </xi> + </tree> + </test> + <test> + <xpath>//alpha[starts-with(concat(@attribute,"-"),"_blank-")][@xml:lang="en-US"]/omicron[@and="attribute-value"][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::zeta[@attribute][@xml:id="id1"][not(following-sibling::*)]/delta[@content][not(following-sibling::*)]//delta[@xml:lang="no-nb"]//lambda[@xml:lang="no-nb"][not(preceding-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <alpha attribute="_blank" xml:lang="en-US"> + <omicron and="attribute-value" xml:lang="no"/> + <zeta attribute="123456789" xml:id="id1"> + <delta content="another attribute value"> + <delta xml:lang="no-nb"> + <lambda xml:lang="no-nb"> + <green>This text must be green</green> + </lambda> + </delta> + </delta> + </zeta> + </alpha> + </tree> + </test> + <test> + <xpath>//alpha[contains(concat(@string,"$"),"e value$")][@xml:id="id1"]//delta[contains(concat(@attrib,"$"),"tribute$")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//gamma[contains(@desciption,"u")][not(preceding-sibling::*)]/mu[@xml:lang="no-nb"][not(following-sibling::*)]//chi[@xml:lang="no"][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota[@xml:lang="en"][not(following-sibling::*)]/psi[starts-with(@name,"con")][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[contains(@src,"value")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//nu[@xml:id="id3"]//zeta[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]/iota[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <alpha string="attribute value" xml:id="id1"> + <delta attrib="attribute" xml:lang="no-nb" xml:id="id2"> + <gamma desciption="another attribute value"> + <mu xml:lang="no-nb"> + <chi xml:lang="no"/> + <iota xml:lang="en"> + <psi name="content" xml:lang="en-US"/> + <rho src="this-is-att-value"> + <nu xml:id="id3"> + <zeta xml:lang="no-nb" xml:id="id4"> + <iota xml:lang="en" xml:id="id5"> + <green>This text must be green</green> + </iota> + </zeta> + </nu> + </rho> + </iota> + </mu> + </gamma> + </delta> + </alpha> + </tree> + </test> + <test> + <xpath>//beta[@attrib]//sigma[@xml:lang="en-US"][@xml:id="id1"][following-sibling::*[position()=5]][not(child::node())][following-sibling::lambda[@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][not(child::node())][following-sibling::theta[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::rho[starts-with(concat(@and,"-"),"123456789-")][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::*[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::pi[@name][not(following-sibling::*)]/kappa[starts-with(@or,"a")][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::theta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::phi[@xml:id="id6"][not(following-sibling::*)]/gamma[@att][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <beta attrib="123456789"> + <sigma xml:lang="en-US" xml:id="id1"/> + <lambda xml:lang="nb"/> + <theta xml:id="id2"/> + <rho and="123456789" xml:id="id3"/> + <any xml:lang="no" xml:id="id4"/> + <pi name="false"> + <kappa or="another attribute value" xml:id="id5"/> + <theta xml:lang="en-GB"/> + <phi xml:id="id6"> + <gamma att="content"> + <green>This text must be green</green> + </gamma> + </phi> + </pi> + </beta> + </tree> + </test> + <test> + <xpath>//omega[@delete][@xml:lang="no"][@xml:id="id1"]//psi[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::delta[@object][@xml:lang="no"]/phi[@xml:id="id3"]//nu[@xml:id="id4"][not(child::node())][following-sibling::theta[@desciption][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/epsilon[@xml:lang="no-nb"][not(child::node())][following-sibling::psi[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta/phi[contains(@or,"te")][@xml:lang="no-nb"][not(following-sibling::*)]//alpha[@src][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:lang="no"][not(child::node())][following-sibling::sigma[following-sibling::*[position()=1]][not(child::node())][following-sibling::alpha[starts-with(@or,"attribute ")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]/alpha[contains(concat(@attr,"$"),"%$")][@xml:lang="en"][@xml:id="id7"][not(child::node())][following-sibling::epsilon[starts-with(concat(@content,"-"),"another attribute value-")][not(following-sibling::epsilon)]//gamma[@number="solid 1px green"][@xml:id="id8"][not(following-sibling::*)]//eta[contains(@object,"tru")][@xml:lang="en-GB"][@xml:id="id9"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[contains(concat(@attr,"$"),"-is-att-value$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id10"][preceding-sibling::*[position() = 2]][following-sibling::theta[preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]]]]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <omega delete="content" xml:lang="no" xml:id="id1"> + <psi xml:lang="en-GB" xml:id="id2"/> + <delta object="attribute" xml:lang="no"> + <phi xml:id="id3"> + <nu xml:id="id4"/> + <theta desciption="this-is-att-value"> + <epsilon xml:lang="no-nb"/> + <psi xml:id="id5"> + <zeta> + <phi or="attribute" xml:lang="no-nb"> + <alpha src="false"/> + <omega xml:lang="no"/> + <sigma/> + <alpha or="attribute value" xml:lang="nb" xml:id="id6"> + <alpha attr="100%" xml:lang="en" xml:id="id7"/> + <epsilon content="another attribute value"> + <gamma number="solid 1px green" xml:id="id8"> + <eta object="true" xml:lang="en-GB" xml:id="id9"/> + <psi attr="this-is-att-value" xml:lang="en-GB"/> + <xi xml:lang="en-GB" xml:id="id10"/> + <theta> + <green>This text must be green</green> + </theta> + </gamma> + </epsilon> + </alpha> + </phi> + </zeta> + </psi> + </theta> + </phi> + </delta> + </omega> + </tree> + </test> + <test> + <xpath>//xi[@xml:lang="no-nb"]/alpha[@insert][@xml:lang="no-nb"][@xml:id="id1"][not(preceding-sibling::*)]//psi[@attrib][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::lambda[starts-with(@att,"another attribute")][@xml:lang="no"][@xml:id="id3"][not(child::node())][following-sibling::omega[contains(@src,"se")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//psi[not(following-sibling::*)][not(preceding-sibling::psi)]//epsilon[@xml:id="id4"][not(preceding-sibling::*)]//kappa[contains(@token,"ttribut")][@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)]//nu[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[@attrib="_blank"][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[not(following-sibling::*)]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <xi xml:lang="no-nb"> + <alpha insert="true" xml:lang="no-nb" xml:id="id1"> + <psi attrib="false" xml:lang="en-US" xml:id="id2"/> + <lambda att="another attribute value" xml:lang="no" xml:id="id3"/> + <omega src="false" xml:lang="no"> + <psi> + <epsilon xml:id="id4"> + <kappa token="attribute-value" xml:lang="en" xml:id="id5"> + <nu xml:id="id6"/> + <any attrib="_blank" xml:id="id7"/> + <nu> + <green>This text must be green</green> + </nu> + </kappa> + </epsilon> + </psi> + </omega> + </alpha> + </xi> + </tree> + </test> + <test> + <xpath>//theta[@xml:id="id1"]//iota[@attrib][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::kappa[contains(@and,"an")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::beta[@src="content"][@xml:lang="no-nb"][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::psi[contains(concat(@attrib,"$"),"6789$")][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 3]]/gamma[not(following-sibling::*)]//gamma[starts-with(@att,"this-is-att-va")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:id="id1"> + <iota attrib="this.nodeValue" xml:id="id2"/> + <kappa and="_blank" xml:lang="en"/> + <beta src="content" xml:lang="no-nb" xml:id="id3"/> + <psi attrib="123456789" xml:lang="nb" xml:id="id4"> + <gamma> + <gamma att="this-is-att-value" xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </gamma> + </gamma> + </psi> + </theta> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="en-US"][@xml:id="id1"]/rho[@xml:lang="en"][@xml:id="id2"][not(following-sibling::*)]/delta[@xml:id="id3"][following-sibling::*[@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/tau//zeta[@xml:lang="en-US"][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="en-US" xml:id="id1"> + <rho xml:lang="en" xml:id="id2"> + <delta xml:id="id3"/> + <any xml:lang="en-US" xml:id="id4"/> + <chi xml:lang="nb"> + <tau> + <zeta xml:lang="en-US"> + <green>This text must be green</green> + </zeta> + </tau> + </chi> + </rho> + </alpha> + </tree> + </test> + <test> + <xpath>//iota[@xml:lang="no-nb"][@xml:id="id1"]/omega[@xml:lang="en-US"][not(preceding-sibling::*)]//rho[@xml:lang="en"][not(following-sibling::*)]//theta[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:id="id3"][following-sibling::alpha[@xml:lang="nb"][not(following-sibling::*)]/nu[@false="123456789"][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::epsilon[@xml:lang="en-US"][@xml:id="id4"][following-sibling::omega[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 2]]]]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:lang="no-nb" xml:id="id1"> + <omega xml:lang="en-US"> + <rho xml:lang="en"> + <theta xml:lang="en-GB" xml:id="id2"/> + <phi xml:id="id3"/> + <alpha xml:lang="nb"> + <nu false="123456789" xml:lang="no-nb"/> + <epsilon xml:lang="en-US" xml:id="id4"/> + <omega xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </omega> + </alpha> + </rho> + </omega> + </iota> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]/sigma[starts-with(concat(@delete,"-"),"this-")][@xml:lang="no"][@xml:id="id2"][not(child::node())][following-sibling::sigma[@xml:id="id3"][not(following-sibling::*)]/sigma[@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::chi[contains(@object,"i")][@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::theta[@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::psi[@and][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][following-sibling::theta[starts-with(concat(@insert,"-"),"content-")][@xml:id="id7"]]]]]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <sigma delete="this-is-att-value" xml:lang="no" xml:id="id2"/> + <sigma xml:id="id3"> + <sigma xml:lang="en-GB" xml:id="id4"/> + <chi object="attribute" xml:id="id5"/> + <theta xml:id="id6"/> + <psi and="100%" xml:lang="en-GB"/> + <theta insert="content" xml:id="id7"> + <green>This text must be green</green> + </theta> + </sigma> + </nu> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="en"][@xml:id="id1"]//psi[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[@xml:lang="no"][@xml:id="id2"][following-sibling::iota[starts-with(@insert,"this.nodeValue")][not(following-sibling::*)]/alpha[following-sibling::sigma[contains(@abort,"s.")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[not(following-sibling::*)]//phi[@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::delta[preceding-sibling::*[position() = 1]]/phi[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(concat(@or,"$"),"value$")][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//zeta//theta[@xml:id="id5"][following-sibling::*[position()=8]][not(child::node())][following-sibling::tau[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[contains(concat(@class,"$"),"ue$")][not(child::node())][following-sibling::beta[starts-with(concat(@string,"-"),"solid 1px green-")][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 3]][following-sibling::lambda[@desciption][@xml:lang="no-nb"][@xml:id="id8"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::chi[@object][@xml:lang="en"][preceding-sibling::*[position() = 5]][not(following-sibling::chi)][following-sibling::delta[@att][@xml:lang="no"][@xml:id="id9"][preceding-sibling::*[position() = 6]][not(child::node())][following-sibling::rho[contains(@insert,"e")][preceding-sibling::*[position() = 7]][following-sibling::*[position()=1]][following-sibling::rho[@xml:lang="nb"][preceding-sibling::*[position() = 8]]//epsilon[contains(@attrib,"other attribute value")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@xml:lang="en-US"][not(following-sibling::*)]/omicron[@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="en" xml:id="id1"> + <psi xml:lang="no-nb"> + <tau xml:lang="no" xml:id="id2"/> + <iota insert="this.nodeValue"> + <alpha/> + <sigma abort="this.nodeValue"> + <alpha> + <phi xml:lang="no-nb"/> + <delta> + <phi xml:id="id3"/> + <kappa or="this-is-att-value" xml:id="id4"> + <zeta> + <theta xml:id="id5"/> + <tau xml:id="id6"/> + <delta class="this-is-att-value"/> + <beta string="solid 1px green" xml:lang="en" xml:id="id7"/> + <lambda desciption="true" xml:lang="no-nb" xml:id="id8"/> + <chi object="true" xml:lang="en"/> + <delta att="true" xml:lang="no" xml:id="id9"/> + <rho insert="solid 1px green"/> + <rho xml:lang="nb"> + <epsilon attrib="another attribute value" xml:lang="en"> + <kappa xml:lang="en-US"> + <omicron xml:lang="en-GB"> + <green>This text must be green</green> + </omicron> + </kappa> + </epsilon> + </rho> + </zeta> + </kappa> + </delta> + </alpha> + </sigma> + </iota> + </psi> + </eta> + </tree> + </test> + <test> + <xpath>//*[@xml:id="id1"]//psi[@data][@xml:id="id2"]/iota[@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::gamma[starts-with(@delete,"10")][@xml:id="id3"][not(following-sibling::*)]//omega[@xml:lang="no"][not(preceding-sibling::*)]/chi[contains(@insert,"at")]//omega[contains(concat(@attribute,"$"),"true$")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[contains(@object,"conte")][@xml:lang="no"][@xml:id="id4"]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <any xml:id="id1"> + <psi data="_blank" xml:id="id2"> + <iota xml:lang="nb"/> + <gamma delete="100%" xml:id="id3"> + <omega xml:lang="no"> + <chi insert="attribute value"> + <omega attribute="true" xml:lang="en"> + <upsilon object="content" xml:lang="no" xml:id="id4"> + <green>This text must be green</green> + </upsilon> + </omega> + </chi> + </omega> + </gamma> + </psi> + </any> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="en"][@xml:id="id1"]/nu[not(preceding-sibling::*)]/mu[starts-with(@false,"th")][@xml:id="id2"][not(following-sibling::*)]//omicron[@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]/epsilon[@attribute][@xml:lang="en-US"][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[@desciption="false"][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)]//omega[contains(concat(@class,"$"),"false$")][following-sibling::*[position()=1]][following-sibling::phi[@data="100%"][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="en" xml:id="id1"> + <nu> + <mu false="this-is-att-value" xml:id="id2"> + <omicron xml:lang="nb" xml:id="id3"> + <epsilon attribute="false" xml:lang="en-US"/> + <kappa> + <eta desciption="false" xml:lang="en-GB" xml:id="id4"> + <omega class="false"/> + <phi data="100%" xml:lang="no-nb"> + <green>This text must be green</green> + </phi> + </eta> + </kappa> + </omicron> + </mu> + </nu> + </nu> + </tree> + </test> + <test> + <xpath>//kappa[starts-with(concat(@object,"-"),"100%-")][@xml:lang="en-US"]//pi[@or][@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]]//alpha[@attr][@xml:lang="en-GB"]//kappa[contains(@or,"ntent")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)]//omicron[not(preceding-sibling::*)]/omega[not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@insert][not(preceding-sibling::*)][following-sibling::gamma[contains(concat(@false,"$"),"%$")][@xml:id="id4"][not(following-sibling::*)]/theta[@xml:lang="en"]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <kappa object="100%" xml:lang="en-US"> + <pi or="solid 1px green" xml:id="id1"/> + <psi xml:lang="no" xml:id="id2"> + <alpha attr="another attribute value" xml:lang="en-GB"> + <kappa or="content" xml:lang="en" xml:id="id3"> + <omicron> + <omega> + <xi xml:lang="en-US"> + <mu insert="123456789"/> + <gamma false="100%" xml:id="id4"> + <theta xml:lang="en"> + <green>This text must be green</green> + </theta> + </gamma> + </xi> + </omega> + </omicron> + </kappa> + </alpha> + </psi> + </kappa> + </tree> + </test> + <test> + <xpath>//delta[@xml:id="id1"]/theta[@xml:lang="en-GB"][@xml:id="id2"][not(preceding-sibling::*)]//lambda[starts-with(@att,"another attribute")][@xml:lang="no"][not(preceding-sibling::*)]//pi[contains(@token,"ank")][@xml:lang="en"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id5"][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[starts-with(concat(@abort,"-"),"this.nodeValue-")][@xml:lang="no-nb"][@xml:id="id6"][not(following-sibling::kappa)][following-sibling::psi[contains(concat(@attrib,"$"),"ribute value$")][@xml:id="id7"][preceding-sibling::*[position() = 3]]//psi[@token][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=5]][not(child::node())][following-sibling::mu[preceding-sibling::*[position() = 1]][following-sibling::*[@insert][@xml:id="id9"][following-sibling::lambda[@attr][@xml:lang="no-nb"][@xml:id="id10"][following-sibling::rho[starts-with(concat(@desciption,"-"),"this-")][@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::alpha[@xml:lang="en-GB"][@xml:id="id11"]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:id="id1"> + <theta xml:lang="en-GB" xml:id="id2"> + <lambda att="another attribute value" xml:lang="no"> + <pi token="_blank" xml:lang="en" xml:id="id3"> + <zeta xml:id="id4"/> + <tau xml:lang="en-GB" xml:id="id5"/> + <kappa abort="this.nodeValue" xml:lang="no-nb" xml:id="id6"/> + <psi attrib="attribute value" xml:id="id7"> + <psi token="this-is-att-value" xml:id="id8"/> + <mu/> + <any insert="this-is-att-value" xml:id="id9"/> + <lambda attr="another attribute value" xml:lang="no-nb" xml:id="id10"/> + <rho desciption="this-is-att-value" xml:lang="nb"/> + <alpha xml:lang="en-GB" xml:id="id11"> + <green>This text must be green</green> + </alpha> + </psi> + </pi> + </lambda> + </theta> + </delta> + </tree> + </test> + <test> + <xpath>//nu[starts-with(concat(@attrib,"-"),"this-")]//gamma/rho[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@xml:id="id2"][not(child::node())][following-sibling::epsilon/upsilon[contains(concat(@object,"$"),"ntent$")][@xml:lang="nb"][not(following-sibling::*)]/pi[@xml:lang="en-GB"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[preceding-sibling::*[position() = 1]]/*[@delete][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=3]][following-sibling::lambda[@xml:id="id4"][not(child::node())][following-sibling::delta[@xml:lang="en-GB"][following-sibling::psi[not(following-sibling::*)]/zeta[starts-with(@or,"attribute")][not(preceding-sibling::*)]/rho[contains(@string,"bute-value")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"]//upsilon[@abort="attribute-value"][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]/upsilon[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:id="id6"][not(following-sibling::*)]/beta[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[contains(@content,"t")][@xml:lang="en"][@xml:id="id8"][not(child::node())][following-sibling::*[starts-with(@token,"_bl")][@xml:id="id9"][following-sibling::rho[contains(concat(@content,"$"),"ribute-value$")][@xml:lang="no-nb"][@xml:id="id10"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <nu attrib="this-is-att-value"> + <gamma> + <rho xml:lang="nb" xml:id="id1"> + <alpha xml:id="id2"/> + <epsilon> + <upsilon object="content" xml:lang="nb"> + <pi xml:lang="en-GB" xml:id="id3"/> + <omega> + <any delete="_blank" xml:lang="nb"/> + <lambda xml:id="id4"/> + <delta xml:lang="en-GB"/> + <psi> + <zeta or="attribute-value"> + <rho string="attribute-value" xml:lang="no"/> + <epsilon xml:lang="no-nb"> + <upsilon abort="attribute-value" xml:lang="en-GB"> + <upsilon xml:id="id5"/> + <eta xml:id="id6"> + <beta xml:lang="en-GB" xml:id="id7"> + <lambda content="true" xml:lang="en" xml:id="id8"/> + <any token="_blank" xml:id="id9"/> + <rho content="attribute-value" xml:lang="no-nb" xml:id="id10"> + <tau> + <green>This text must be green</green> + </tau> + </rho> + </beta> + </eta> + </upsilon> + </epsilon> + </zeta> + </psi> + </omega> + </upsilon> + </epsilon> + </rho> + </gamma> + </nu> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="nb"]/delta[not(preceding-sibling::*)]//omicron[contains(concat(@content,"$"),"nodeValue$")][@xml:lang="nb"][not(following-sibling::*)]//tau[@xml:lang="nb"][@xml:id="id1"]/theta[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:lang="en-US"]/delta[@xml:lang="en-US"][not(preceding-sibling::*)]//theta[not(child::node())][following-sibling::kappa[starts-with(concat(@desciption,"-"),"another attribute value-")][@xml:lang="no-nb"][@xml:id="id2"][not(following-sibling::*)]//chi[@string][@xml:id="id3"][following-sibling::sigma[following-sibling::*[position()=1]][following-sibling::gamma[starts-with(concat(@attr,"-"),"_blank-")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]/epsilon[contains(concat(@false,"$"),"e$")][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//theta[@data="solid 1px green"][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[not(preceding-sibling::*)][not(following-sibling::*)]/zeta[not(following-sibling::*)]//lambda[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)]//omicron[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][not(following-sibling::*)]/omicron[@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="nb"> + <delta> + <omicron content="this.nodeValue" xml:lang="nb"> + <tau xml:lang="nb" xml:id="id1"> + <theta xml:lang="en-US"/> + <omicron xml:lang="en-US"> + <delta xml:lang="en-US"> + <theta/> + <kappa desciption="another attribute value" xml:lang="no-nb" xml:id="id2"> + <chi string="123456789" xml:id="id3"/> + <sigma/> + <gamma attr="_blank" xml:lang="nb"> + <epsilon false="attribute value" xml:id="id4"> + <theta data="solid 1px green" xml:lang="en-US"> + <xi> + <zeta> + <lambda xml:lang="en-US" xml:id="id5"> + <omicron xml:lang="no" xml:id="id6"/> + <chi xml:lang="en-GB"> + <omicron xml:lang="en" xml:id="id7"> + <green>This text must be green</green> + </omicron> + </chi> + </lambda> + </zeta> + </xi> + </theta> + </epsilon> + </gamma> + </kappa> + </delta> + </omicron> + </tau> + </omicron> + </delta> + </tau> + </tree> + </test> + <test> + <xpath>//lambda[@xml:id="id1"]/kappa[contains(concat(@false,"$"),"k$")][@xml:id="id2"][following-sibling::zeta[not(child::node())][following-sibling::pi[contains(concat(@attrib,"$"),"e$")][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::delta[@xml:lang="en-GB"][not(child::node())][following-sibling::gamma[contains(@title,"ttribu")][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/iota[@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::upsilon)]//sigma[@true][not(preceding-sibling::*)]/eta[@xml:lang="no-nb"]//lambda[@token][@xml:lang="en"][@xml:id="id7"][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <lambda xml:id="id1"> + <kappa false="_blank" xml:id="id2"/> + <zeta/> + <pi attrib="true" xml:id="id3"/> + <delta xml:lang="en-GB"/> + <gamma title="attribute" xml:id="id4"> + <iota xml:id="id5"/> + <upsilon xml:lang="en-US" xml:id="id6"> + <sigma true="100%"> + <eta xml:lang="no-nb"> + <lambda token="100%" xml:lang="en" xml:id="id7"> + <green>This text must be green</green> + </lambda> + </eta> + </sigma> + </upsilon> + </gamma> + </lambda> + </tree> + </test> + <test> + <xpath>//kappa[@string="attribute"][@xml:id="id1"]/iota[contains(@title,"%")][@xml:id="id2"][following-sibling::xi[starts-with(concat(@src,"-"),"this.nodeValue-")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//theta[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]//pi[position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <kappa string="attribute" xml:id="id1"> + <iota title="100%" xml:id="id2"/> + <xi src="this.nodeValue"> + <theta xml:lang="nb" xml:id="id3"/> + <beta xml:lang="en-US" xml:id="id4"> + <pi> + <green>This text must be green</green> + </pi> + </beta> + </xi> + </kappa> + </tree> + </test> + <test> + <xpath>//mu[starts-with(concat(@data,"-"),"attribute-")]//gamma[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[contains(@name,"-a")][@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[@xml:id="id2"][not(following-sibling::*)]//kappa[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(@number,"a")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::delta[contains(@attribute,"r attribute value")][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[starts-with(concat(@src,"-"),"this-")][@xml:lang="en"][@xml:id="id5"][not(following-sibling::*)]/*[@or="_blank"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::lambda[starts-with(concat(@title,"-"),"content-")][@xml:lang="nb"][following-sibling::*[position()=1]][following-sibling::nu[starts-with(@token,"attrib")][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/beta[not(preceding-sibling::*)][not(following-sibling::*)]//zeta[starts-with(@att,"another attribu")][not(child::node())][following-sibling::phi[starts-with(concat(@data,"-"),"100%-")][@xml:lang="en-US"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][not(child::node())][following-sibling::pi[not(child::node())][following-sibling::*//pi[@xml:id="id6"][not(following-sibling::*)]//alpha[starts-with(concat(@abort,"-"),"true-")][@xml:id="id7"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <mu data="attribute"> + <gamma xml:id="id1"> + <pi name="this-is-att-value" xml:lang="nb"/> + <tau xml:id="id2"> + <kappa xml:id="id3"> + <zeta number="attribute" xml:lang="no" xml:id="id4"/> + <delta attribute="another attribute value"/> + <beta> + <nu src="this-is-att-value" xml:lang="en" xml:id="id5"> + <any or="_blank"/> + <lambda title="content" xml:lang="nb"/> + <nu token="attribute-value"> + <beta> + <zeta att="another attribute value"/> + <phi data="100%" xml:lang="en-US"/> + <pi/> + <any> + <pi xml:id="id6"> + <alpha abort="true" xml:id="id7"> + <green>This text must be green</green> + </alpha> + </pi> + </any> + </beta> + </nu> + </nu> + </beta> + </kappa> + </tau> + </gamma> + </mu> + </tree> + </test> + <test> + <xpath>//*[contains(@string,"ent")][@xml:lang="nb"]//*[starts-with(@and,"true")][@xml:lang="en-US"][following-sibling::eta[@content="this.nodeValue"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::delta[@xml:lang="no"][not(child::node())][following-sibling::beta[contains(@src," 1")][@xml:id="id2"][following-sibling::psi[contains(concat(@string,"$"),"00%$")][@xml:id="id3"][following-sibling::iota[@xml:id="id4"][preceding-sibling::*[position() = 5]][not(following-sibling::*)][not(preceding-sibling::iota)]//zeta[contains(@string,"green")][@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]//beta[not(following-sibling::*)]/sigma[starts-with(@attribute,"another attribut")][@xml:lang="no"][not(preceding-sibling::*)]/delta[@string][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@class][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::nu[@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::beta[contains(@delete,"0%")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//mu[@xml:lang="no-nb"][not(following-sibling::*)]/eta[@xml:id="id8"][following-sibling::*[position()=5]][not(child::node())][following-sibling::phi[@xml:lang="no"][preceding-sibling::*[position() = 1]][following-sibling::zeta[contains(concat(@content,"$"),"-value$")][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::tau[contains(@or,"10")][@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 3]][following-sibling::psi[@xml:id="id10"][following-sibling::beta[@xml:lang="no-nb"]/mu[@xml:id="id11"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]]]][position() = 1]][position() = 1]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>1</nth> + </result> + <tree> + <any string="content" xml:lang="nb"> + <any and="true" xml:lang="en-US"/> + <eta content="this.nodeValue" xml:id="id1"/> + <delta xml:lang="no"/> + <beta src="solid 1px green" xml:id="id2"/> + <psi string="100%" xml:id="id3"/> + <iota xml:id="id4"> + <zeta string="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <beta> + <sigma attribute="another attribute value" xml:lang="no"> + <delta string="content" xml:lang="en"> + <rho class="this-is-att-value" xml:id="id6"/> + <nu xml:lang="en-US" xml:id="id7"/> + <beta delete="100%" xml:lang="no"> + <mu xml:lang="no-nb"> + <eta xml:id="id8"/> + <phi xml:lang="no"/> + <zeta content="this-is-att-value"/> + <tau or="100%" xml:lang="en-GB" xml:id="id9"/> + <psi xml:id="id10"/> + <beta xml:lang="no-nb"> + <mu xml:id="id11"> + <green>This text must be green</green> + </mu> + </beta> + </mu> + </beta> + </delta> + </sigma> + </beta> + </zeta> + </iota> + </any> + </tree> + </test> + <test> + <xpath>//xi//*[starts-with(concat(@abort,"-"),"attribute value-")][@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)]//beta[starts-with(@object,"this.nodeV")][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@and]/omicron[@xml:id="id2"]//lambda[@src="this-is-att-value"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[@token][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>1</nth> + </result> + <tree> + <xi> + <any abort="attribute value" xml:lang="en-US" xml:id="id1"> + <beta object="this.nodeValue" xml:lang="en-US"> + <theta and="attribute-value"> + <omicron xml:id="id2"> + <lambda src="this-is-att-value" xml:id="id3"> + <theta token="_blank" xml:lang="en-GB" xml:id="id4"> + <green>This text must be green</green> + </theta> + </lambda> + </omicron> + </theta> + </beta> + </any> + </xi> + </tree> + </test> + <test> + <xpath>//rho/psi[@xml:id="id1"][following-sibling::beta[contains(concat(@class,"$"),"6789$")][@xml:lang="nb"][not(following-sibling::*)]/omicron[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::eta[@and][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[preceding-sibling::*[position() = 2]][following-sibling::theta/omicron[starts-with(concat(@object,"-"),"123456789-")][@xml:id="id2"][not(following-sibling::*)]//pi[@name][not(preceding-sibling::*)]/zeta[@class]//mu[contains(@insert,"u")][@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/gamma[starts-with(concat(@string,"-"),"100%-")][@xml:lang="no-nb"][not(preceding-sibling::*)][following-sibling::nu[@xml:id="id4"][preceding-sibling::*[position() = 1]]/epsilon[starts-with(concat(@attrib,"-"),"solid 1px green-")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="en-GB"][@xml:id="id6"]/lambda[contains(concat(@string,"$"),"e$")][not(preceding-sibling::*)][following-sibling::nu/xi[starts-with(@abort,"attribute")][@xml:lang="nb"][not(preceding-sibling::*)]/*[contains(@number,"ttribute")][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@content][@xml:lang="en-US"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <rho> + <psi xml:id="id1"/> + <beta class="123456789" xml:lang="nb"> + <omicron xml:lang="en-US"/> + <eta and="attribute" xml:lang="en"/> + <any/> + <theta> + <omicron object="123456789" xml:id="id2"> + <pi name="solid 1px green"> + <zeta class="this.nodeValue"> + <mu insert="true" xml:lang="en-US" xml:id="id3"> + <gamma string="100%" xml:lang="no-nb"/> + <nu xml:id="id4"> + <epsilon attrib="solid 1px green" xml:id="id5"> + <xi xml:lang="en-GB" xml:id="id6"> + <lambda string="false"/> + <nu> + <xi abort="attribute" xml:lang="nb"> + <any number="attribute value"> + <iota content="attribute value" xml:lang="en-US"> + <green>This text must be green</green> + </iota> + </any> + </xi> + </nu> + </xi> + </epsilon> + </nu> + </mu> + </zeta> + </pi> + </omicron> + </theta> + </beta> + </rho> + </tree> + </test> + <test> + <xpath>//phi[@object]/sigma[contains(@insert,"tr")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[starts-with(@abort,"12345678")][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@or]/beta[not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[@desciption][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//zeta[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)]/omicron[@content][not(preceding-sibling::*)][not(following-sibling::*)]/lambda[contains(concat(@or,"$"),"lank$")][@xml:id="id2"]//sigma[@xml:id="id3"][following-sibling::gamma[@attribute][not(following-sibling::*)]//omicron[@attribute][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(preceding-sibling::omicron)][following-sibling::iota[@src][not(child::node())][following-sibling::rho[@xml:id="id5"][not(child::node())][following-sibling::*[@xml:lang="no"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//gamma[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@att][@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//zeta[@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:id="id8"][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <phi object="solid 1px green"> + <sigma insert="true" xml:lang="en"> + <kappa abort="123456789"/> + <mu or="attribute-value"> + <beta/> + <chi desciption="false" xml:lang="en-GB"> + <zeta xml:lang="en-US" xml:id="id1"> + <omicron content="another attribute value"> + <lambda or="_blank" xml:id="id2"> + <sigma xml:id="id3"/> + <gamma attribute="attribute"> + <omicron attribute="this-is-att-value" xml:id="id4"/> + <iota src="another attribute value"/> + <rho xml:id="id5"/> + <any xml:lang="no"> + <gamma xml:lang="en-US" xml:id="id6"> + <alpha att="solid 1px green" xml:lang="en-GB"> + <zeta xml:id="id7"> + <eta xml:id="id8"> + <green>This text must be green</green> + </eta> + </zeta> + </alpha> + </gamma> + </any> + </gamma> + </lambda> + </omicron> + </zeta> + </chi> + </mu> + </sigma> + </phi> + </tree> + </test> + <test> + <xpath>//zeta[@token="attribute"][@xml:lang="en-US"]//zeta[@and][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[contains(concat(@title,"$"),"attribute value$")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/omicron[@xml:lang="en"]//nu[contains(@insert," value")][@xml:lang="en-GB"][@xml:id="id1"][following-sibling::tau[@true][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/xi[starts-with(@content,"t")][following-sibling::delta[@xml:lang="no"][@xml:id="id2"]/nu[contains(concat(@attr,"$"),"this-is-att-value$")][@xml:id="id3"][not(preceding-sibling::*)]//omicron[starts-with(concat(@delete,"-"),"false-")][@xml:lang="no"][@xml:id="id4"]//beta[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@abort][@xml:lang="no"][@xml:id="id6"]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>1</nth> + </result> + <tree> + <zeta token="attribute" xml:lang="en-US"> + <zeta and="123456789"/> + <tau title="another attribute value" xml:lang="en-GB"> + <omicron xml:lang="en"> + <nu insert="another attribute value" xml:lang="en-GB" xml:id="id1"/> + <tau true="attribute"> + <xi content="true"/> + <delta xml:lang="no" xml:id="id2"> + <nu attr="this-is-att-value" xml:id="id3"> + <omicron delete="false" xml:lang="no" xml:id="id4"> + <beta content="this.nodeValue" xml:id="id5"/> + <any abort="_blank" xml:lang="no" xml:id="id6"> + <green>This text must be green</green> + </any> + </omicron> + </nu> + </delta> + </tau> + </omicron> + </tau> + </zeta> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="no"][@xml:id="id1"]/*[starts-with(concat(@desciption,"-"),"attribute value-")][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::psi[@xml:id="id2"][preceding-sibling::*[position() = 1]]//chi[@xml:lang="nb"][not(following-sibling::*)]/beta[contains(@src,"bute")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@delete][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::tau[@xml:id="id4"][not(following-sibling::*)]//chi[@content="this-is-att-value"][@xml:lang="en-GB"][following-sibling::theta[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa[@content][@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::theta[contains(@attrib,"nt")][@xml:lang="en-GB"][following-sibling::gamma[starts-with(concat(@token,"-"),"_blank-")][@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::omicron[starts-with(@name,"_blan")][not(following-sibling::*)]//pi[@xml:lang="en"]/theta[@xml:lang="no"][not(following-sibling::*)]//iota[@xml:lang="no"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[contains(@and,"als")][@xml:id="id10"][not(child::node())][following-sibling::sigma[contains(@data,"bute valu")][not(following-sibling::*)]//gamma[not(preceding-sibling::*)]//mu[@xml:id="id11"]]][position() = 1]]]][position() = 1]]]]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="no" xml:id="id1"> + <any desciption="attribute value"/> + <psi xml:id="id2"> + <chi xml:lang="nb"> + <beta src="attribute" xml:id="id3"> + <alpha delete="this.nodeValue" xml:lang="en-US"/> + <tau xml:id="id4"> + <chi content="this-is-att-value" xml:lang="en-GB"/> + <theta xml:id="id5"> + <kappa content="attribute" xml:lang="no" xml:id="id6"/> + <theta attrib="content" xml:lang="en-GB"/> + <gamma token="_blank" xml:lang="no" xml:id="id7"/> + <omicron name="_blank"> + <pi xml:lang="en"> + <theta xml:lang="no"> + <iota xml:lang="no" xml:id="id8"/> + <iota xml:lang="en" xml:id="id9"/> + <nu and="false" xml:id="id10"/> + <sigma data="another attribute value"> + <gamma> + <mu xml:id="id11"> + <green>This text must be green</green> + </mu> + </gamma> + </sigma> + </theta> + </pi> + </omicron> + </theta> + </tau> + </beta> + </chi> + </psi> + </eta> + </tree> + </test> + <test> + <xpath>//zeta//delta[following-sibling::*[position()=9]][not(preceding-sibling::delta)][not(child::node())][following-sibling::psi[@xml:lang="nb"][following-sibling::phi[contains(concat(@att,"$"),"%$")][not(child::node())][following-sibling::omega[@xml:lang="en-US"][@xml:id="id1"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::pi[@xml:lang="no"][following-sibling::tau[starts-with(concat(@and,"-"),"this-")][@xml:id="id2"][preceding-sibling::*[position() = 5]][not(child::node())][following-sibling::beta[starts-with(@number,"this.nodeVa")][@xml:id="id3"][preceding-sibling::*[position() = 6]][following-sibling::beta[starts-with(concat(@object,"-"),"123456789-")][@xml:id="id4"][not(child::node())][following-sibling::iota[contains(concat(@or,"$"),"nk$")][@xml:lang="no"][not(child::node())][following-sibling::kappa[not(following-sibling::*)]/tau[not(following-sibling::*)]/*[@xml:lang="nb"][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id5"]/rho[@xml:id="id6"][not(following-sibling::*)]/phi[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[@xml:lang="no"][@xml:id="id7"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//xi[@xml:id="id8"][following-sibling::zeta[@xml:lang="en-GB"][not(following-sibling::*)]//theta[@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]//eta[starts-with(@desciption,"this.n")]/phi[starts-with(@number,"con")][@xml:lang="no"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::psi[@xml:lang="no-nb"][@xml:id="id11"][preceding-sibling::*[position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <zeta> + <delta/> + <psi xml:lang="nb"/> + <phi att="100%"/> + <omega xml:lang="en-US" xml:id="id1"/> + <pi xml:lang="no"/> + <tau and="this-is-att-value" xml:id="id2"/> + <beta number="this.nodeValue" xml:id="id3"/> + <beta object="123456789" xml:id="id4"/> + <iota or="_blank" xml:lang="no"/> + <kappa> + <tau> + <any xml:lang="nb"/> + <delta xml:lang="en-GB" xml:id="id5"> + <rho xml:id="id6"> + <phi xml:lang="en"/> + <chi/> + <gamma xml:lang="no" xml:id="id7"> + <xi xml:id="id8"/> + <zeta xml:lang="en-GB"> + <theta xml:id="id9"> + <eta desciption="this.nodeValue"> + <phi number="content" xml:lang="no" xml:id="id10"/> + <psi xml:lang="no-nb" xml:id="id11"> + <green>This text must be green</green> + </psi> + </eta> + </theta> + </zeta> + </gamma> + </rho> + </delta> + </tau> + </kappa> + </zeta> + </tree> + </test> + <test> + <xpath>//delta[contains(concat(@or,"$"),"e$")]//phi[@xml:lang="en-GB"][not(child::node())][following-sibling::sigma[starts-with(@token,"10")]/*[starts-with(@src,"true")][@xml:lang="en-US"][following-sibling::*[position()=3]][following-sibling::alpha[@xml:lang="en"][@xml:id="id1"][following-sibling::tau[@string][@xml:id="id2"][not(child::node())][following-sibling::lambda[preceding-sibling::*[position() = 3]][not(following-sibling::*)]]]]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <delta or="attribute value"> + <phi xml:lang="en-GB"/> + <sigma token="100%"> + <any src="true" xml:lang="en-US"/> + <alpha xml:lang="en" xml:id="id1"/> + <tau string="attribute" xml:id="id2"/> + <lambda> + <green>This text must be green</green> + </lambda> + </sigma> + </delta> + </tree> + </test> + <test> + <xpath>//gamma[starts-with(@false,"_blank")][@xml:lang="en"]//omicron[@xml:lang="no"][@xml:id="id1"][not(following-sibling::*)][not(preceding-sibling::omicron)]/omega[not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::nu[@object]//omicron[@xml:lang="en-US"][not(child::node())][following-sibling::zeta[@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::sigma[@attribute][@xml:lang="en-GB"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::xi[preceding-sibling::*[position() = 4]][not(following-sibling::*)]//theta[starts-with(concat(@object,"-"),"this-")][@xml:id="id5"]/pi[@attrib][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[starts-with(concat(@desciption,"-"),"false-")][@xml:lang="no"][@xml:id="id6"][preceding-sibling::*[position() = 1]]//*[@xml:id="id7"][not(preceding-sibling::*)][not(preceding-sibling::any)][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]/chi[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::iota[@xml:lang="en-US"][preceding-sibling::*[position() = 1]]//rho[not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]][position() = 1]]]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <gamma false="_blank" xml:lang="en"> + <omicron xml:lang="no" xml:id="id1"> + <omega/> + <omicron xml:id="id2"/> + <nu object="true"> + <omicron xml:lang="en-US"/> + <zeta xml:lang="en-US" xml:id="id3"/> + <iota xml:id="id4"/> + <sigma attribute="solid 1px green" xml:lang="en-GB"/> + <xi> + <theta object="this-is-att-value" xml:id="id5"> + <pi attrib="solid 1px green"/> + <rho desciption="false" xml:lang="no" xml:id="id6"> + <any xml:id="id7"/> + <chi xml:lang="no" xml:id="id8"> + <chi xml:lang="en-GB"/> + <iota xml:lang="en-US"> + <rho> + <green>This text must be green</green> + </rho> + </iota> + </chi> + </rho> + </theta> + </xi> + </nu> + </omicron> + </gamma> + </tree> + </test> + <test> + <xpath>//tau[@xml:id="id1"]/kappa[@xml:lang="no"]//psi[@xml:lang="no-nb"][@xml:id="id2"][not(child::node())][following-sibling::sigma[@desciption="_blank"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[@xml:id="id3"][not(preceding-sibling::*)]//omicron[@object][not(preceding-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:id="id1"> + <kappa xml:lang="no"> + <psi xml:lang="no-nb" xml:id="id2"/> + <sigma desciption="_blank"> + <theta xml:id="id3"> + <omicron object="content"> + <green>This text must be green</green> + </omicron> + </theta> + </sigma> + </kappa> + </tau> + </tree> + </test> + <test> + <xpath>//omicron//beta[starts-with(concat(@string,"-"),"123456789-")][@xml:lang="en-GB"][not(preceding-sibling::*)][not(child::node())][following-sibling::epsilon[@or="this.nodeValue"][not(following-sibling::*)]//pi[starts-with(concat(@att,"-"),"_blank-")][@xml:lang="no-nb"]/delta[@delete]/rho[contains(@or,"lue")][@xml:lang="en-GB"]/alpha[not(preceding-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <omicron> + <beta string="123456789" xml:lang="en-GB"/> + <epsilon or="this.nodeValue"> + <pi att="_blank" xml:lang="no-nb"> + <delta delete="solid 1px green"> + <rho or="this-is-att-value" xml:lang="en-GB"> + <alpha> + <green>This text must be green</green> + </alpha> + </rho> + </delta> + </pi> + </epsilon> + </omicron> + </tree> + </test> + <test> + <xpath>//epsilon[contains(concat(@true,"$"),"olid 1px green$")]//upsilon[@attribute][@xml:lang="no"][@xml:id="id1"][following-sibling::*[position()=1]][following-sibling::eta[@xml:id="id2"][preceding-sibling::*[position() = 1]]//omicron[@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//lambda[@att][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::omicron[@and][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[@name][following-sibling::*[@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::pi[@xml:id="id6"][following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[starts-with(concat(@data,"-"),"attribute-")][@xml:lang="no"][preceding-sibling::*[position() = 3]][following-sibling::rho[@number][@xml:lang="nb"][not(child::node())][following-sibling::kappa[contains(concat(@attribute,"$"),"ibute-value$")][@xml:lang="en-GB"]//*[@desciption="attribute-value"][not(child::node())][following-sibling::zeta[@name][@xml:lang="no-nb"][@xml:id="id7"][not(following-sibling::*)]//omega[@xml:id="id8"][not(following-sibling::*)]/phi[not(preceding-sibling::*)]//psi[@xml:id="id9"][not(child::node())][following-sibling::epsilon[contains(concat(@insert,"$"),"nt$")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <epsilon true="solid 1px green"> + <upsilon attribute="solid 1px green" xml:lang="no" xml:id="id1"/> + <eta xml:id="id2"> + <omicron xml:id="id3"> + <lambda att="false" xml:id="id4"/> + <omicron and="this.nodeValue"> + <sigma name="_blank"/> + <any xml:id="id5"/> + <pi xml:id="id6"/> + <omega data="attribute" xml:lang="no"/> + <rho number="this.nodeValue" xml:lang="nb"/> + <kappa attribute="attribute-value" xml:lang="en-GB"> + <any desciption="attribute-value"/> + <zeta name="this-is-att-value" xml:lang="no-nb" xml:id="id7"> + <omega xml:id="id8"> + <phi> + <psi xml:id="id9"/> + <epsilon insert="content" xml:lang="nb"/> + <sigma xml:lang="en"> + <green>This text must be green</green> + </sigma> + </phi> + </omega> + </zeta> + </kappa> + </omicron> + </omicron> + </eta> + </epsilon> + </tree> + </test> + <test> + <xpath>//eta//psi[following-sibling::upsilon[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@false][@xml:lang="no-nb"][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@xml:id="id1"][not(following-sibling::*)]/theta[not(preceding-sibling::*)][not(child::node())][following-sibling::delta[contains(concat(@name,"$"),"ue$")]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>psi</localname> + <nth>0</nth> + </result> + <tree> + <eta> + <psi/> + <upsilon/> + <xi false="another attribute value" xml:lang="no-nb"/> + <lambda xml:id="id1"> + <theta/> + <delta name="true"> + <green>This text must be green</green> + </delta> + </lambda> + </eta> + </tree> + </test> + <test> + <xpath>//chi[@object][@xml:lang="no"]//nu[@xml:lang="en-US"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=6]][not(child::node())][following-sibling::iota[starts-with(@data,"sol")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][following-sibling::xi[@attribute][following-sibling::mu[@xml:lang="en"][@xml:id="id2"][following-sibling::upsilon[@xml:lang="nb"][not(child::node())][following-sibling::mu[starts-with(@token,"attribute")][@xml:lang="en-US"][@xml:id="id3"][not(child::node())][following-sibling::epsilon[contains(concat(@number,"$"),"456789$")][@xml:lang="no"][preceding-sibling::*[position() = 6]]//kappa[starts-with(@desciption,"fal")][@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@token="content"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[@xml:lang="nb"][following-sibling::iota[@xml:id="id6"]/pi[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="no"][not(preceding-sibling::*)][not(following-sibling::*)]/chi[not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id7"][preceding-sibling::*[position() = 1]]//mu[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id8"][following-sibling::mu[@class][@xml:lang="nb"][@xml:id="id9"][not(following-sibling::*)]/phi[@attribute][@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]][position() = 1]]]]]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <chi object="attribute value" xml:lang="no"> + <nu xml:lang="en-US" xml:id="id1"/> + <iota data="solid 1px green"/> + <xi attribute="solid 1px green"/> + <mu xml:lang="en" xml:id="id2"/> + <upsilon xml:lang="nb"/> + <mu token="attribute" xml:lang="en-US" xml:id="id3"/> + <epsilon number="123456789" xml:lang="no"> + <kappa desciption="false" xml:lang="no-nb" xml:id="id4"/> + <any token="content" xml:id="id5"> + <sigma xml:lang="nb"/> + <iota xml:id="id6"> + <pi att="attribute" xml:lang="no"> + <chi/> + <delta xml:id="id7"> + <mu xml:lang="en-US"/> + <psi xml:lang="no" xml:id="id8"/> + <mu class="another attribute value" xml:lang="nb" xml:id="id9"> + <phi attribute="true" xml:id="id10"/> + <kappa xml:id="id11"> + <green>This text must be green</green> + </kappa> + </mu> + </delta> + </pi> + </iota> + </any> + </epsilon> + </chi> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="no"]/omega[@xml:lang="no"][@xml:id="id1"]/gamma[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//iota[@xml:id="id2"]/mu[@xml:lang="en"][@xml:id="id3"]/delta[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@and,"$"),"ttribute$")][@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[@att][@xml:id="id5"][not(child::node())][following-sibling::gamma//omicron[@xml:id="id6"][not(child::node())][following-sibling::delta[@src="attribute value"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][not(child::node())][following-sibling::*[@xml:lang="nb"][@xml:id="id7"][following-sibling::*[position()=2]][following-sibling::iota[@xml:id="id8"][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 4]]//chi[@xml:lang="no-nb"][@xml:id="id9"]/gamma[contains(concat(@name,"$"),"true$")][@xml:lang="en-GB"][@xml:id="id10"][not(preceding-sibling::*)][not(preceding-sibling::gamma)]/phi[@number="123456789"][@xml:lang="nb"][@xml:id="id11"][not(preceding-sibling::*)][following-sibling::*[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[not(preceding-sibling::*)]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="no"> + <omega xml:lang="no" xml:id="id1"> + <gamma xml:lang="en-US"> + <iota xml:id="id2"> + <mu xml:lang="en" xml:id="id3"> + <delta xml:lang="en"/> + <sigma and="attribute" xml:lang="no" xml:id="id4"> + <delta att="content" xml:id="id5"/> + <gamma> + <omicron xml:id="id6"/> + <delta src="attribute value"/> + <any xml:lang="nb" xml:id="id7"/> + <iota xml:id="id8"/> + <beta> + <chi xml:lang="no-nb" xml:id="id9"> + <gamma name="true" xml:lang="en-GB" xml:id="id10"> + <phi number="123456789" xml:lang="nb" xml:id="id11"/> + <any xml:lang="en-US"> + <phi> + <green>This text must be green</green> + </phi> + </any> + </gamma> + </chi> + </beta> + </gamma> + </sigma> + </mu> + </iota> + </gamma> + </omega> + </tau> + </tree> + </test> + <test> + <xpath>//pi[contains(@desciption,"%")][@xml:lang="nb"]/lambda[@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[@insert][@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]/beta[contains(concat(@attribute,"$"),"tribute$")][@xml:lang="en-GB"]/mu[@desciption][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::zeta[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::tau[@number][@xml:id="id4"]/kappa[not(preceding-sibling::*)][following-sibling::nu[contains(@data,"is.nodeValue")][@xml:lang="en"][@xml:id="id5"]/mu[not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@attr="content"][@xml:id="id6"][not(following-sibling::*)]//delta[not(following-sibling::*)]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <pi desciption="100%" xml:lang="nb"> + <lambda xml:id="id1"> + <alpha insert="solid 1px green" xml:lang="en-US" xml:id="id2"> + <beta attribute="attribute" xml:lang="en-GB"> + <mu desciption="attribute" xml:lang="nb"/> + <zeta xml:id="id3"/> + <tau number="this.nodeValue" xml:id="id4"> + <kappa/> + <nu data="this.nodeValue" xml:lang="en" xml:id="id5"> + <mu/> + <phi attr="content" xml:id="id6"> + <delta> + <green>This text must be green</green> + </delta> + </phi> + </nu> + </tau> + </beta> + </alpha> + </lambda> + </pi> + </tree> + </test> + <test> + <xpath>//pi//lambda[@xml:id="id1"]//epsilon[@xml:id="id2"][following-sibling::alpha[contains(concat(@name,"$"),"rue$")][@xml:lang="en"][@xml:id="id3"][not(following-sibling::*)]/phi[contains(concat(@insert,"$"),"e$")][@xml:id="id4"][not(preceding-sibling::*)]/chi[@xml:lang="no-nb"][not(preceding-sibling::*)][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi> + <lambda xml:id="id1"> + <epsilon xml:id="id2"/> + <alpha name="true" xml:lang="en" xml:id="id3"> + <phi insert="attribute-value" xml:id="id4"> + <chi xml:lang="no-nb"> + <green>This text must be green</green> + </chi> + </phi> + </alpha> + </lambda> + </pi> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en-GB"][@xml:id="id1"]//eta[contains(@object,"id 1px")][@xml:lang="en-US"][@xml:id="id2"][not(following-sibling::*)]//omega[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::kappa[@false="this.nodeValue"][@xml:lang="en-US"][following-sibling::mu[@attribute][preceding-sibling::*[position() = 2]]/gamma[@class][@xml:lang="en-GB"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::sigma[contains(@class,"-is-att-v")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//pi[contains(concat(@data,"$"),"ank$")][not(preceding-sibling::*)]//omega[starts-with(concat(@false,"-"),"this-")][@xml:id="id5"]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en-GB" xml:id="id1"> + <eta object="solid 1px green" xml:lang="en-US" xml:id="id2"> + <omega xml:id="id3"/> + <kappa false="this.nodeValue" xml:lang="en-US"/> + <mu attribute="attribute-value"> + <gamma class="false" xml:lang="en-GB" xml:id="id4"/> + <sigma class="this-is-att-value" xml:lang="no-nb"> + <pi data="_blank"> + <omega false="this-is-att-value" xml:id="id5"> + <green>This text must be green</green> + </omega> + </pi> + </sigma> + </mu> + </eta> + </sigma> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]/tau[@xml:lang="nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::psi[preceding-sibling::*[position() = 2]]/pi[@xml:lang="no"][not(child::node())][following-sibling::omega[contains(concat(@string,"$"),"ttribute$")][@xml:lang="en-GB"][following-sibling::mu[@xml:lang="en"][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::tau[contains(@insert,"lank")][@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]/xi[@number="123456789"][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/epsilon[@xml:lang="no"][not(child::node())][following-sibling::beta[starts-with(concat(@number,"-"),"_blank-")][@xml:id="id6"][preceding-sibling::*[position() = 1]][following-sibling::beta[starts-with(@src,"1234")][@xml:lang="en-US"][@xml:id="id7"][preceding-sibling::*[position() = 2]]/xi[@xml:lang="no-nb"][not(following-sibling::*)]/epsilon[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id9"][following-sibling::lambda[contains(@attribute,"alue")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <tau xml:lang="nb" xml:id="id2"/> + <upsilon xml:lang="en-GB" xml:id="id3"/> + <psi> + <pi xml:lang="no"/> + <omega string="attribute" xml:lang="en-GB"/> + <mu xml:lang="en" xml:id="id4"/> + <tau insert="_blank" xml:lang="en-GB" xml:id="id5"> + <xi number="123456789" xml:lang="no-nb"> + <epsilon xml:lang="no"/> + <beta number="_blank" xml:id="id6"/> + <beta src="123456789" xml:lang="en-US" xml:id="id7"> + <xi xml:lang="no-nb"> + <epsilon xml:lang="en-GB" xml:id="id8"> + <beta xml:id="id9"/> + <lambda attribute="attribute-value"> + <green>This text must be green</green> + </lambda> + </epsilon> + </xi> + </beta> + </xi> + </tau> + </psi> + </pi> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="en-US"]/nu[contains(@number,"se")][@xml:lang="en-US"][not(child::node())][following-sibling::chi[@false][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//omega[contains(concat(@and,"$"),"123456789$")][@xml:lang="en-GB"]/theta[not(preceding-sibling::*)][not(following-sibling::*)]/*[@content][@xml:id="id2"][not(following-sibling::*)]//phi[contains(concat(@false,"$"),"ttribute-value$")][@xml:lang="en-US"][not(child::node())][following-sibling::omega[starts-with(concat(@attribute,"-"),"solid 1px green-")][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::theta[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/beta[@content][@xml:lang="no"]/beta[following-sibling::theta[@object="content"][@xml:lang="en-GB"][@xml:id="id4"]/rho[starts-with(@title,"100")][@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="en-US"> + <nu number="false" xml:lang="en-US"/> + <chi false="this-is-att-value" xml:id="id1"> + <omega and="123456789" xml:lang="en-GB"> + <theta> + <any content="100%" xml:id="id2"> + <phi false="attribute-value" xml:lang="en-US"/> + <omega attribute="solid 1px green" xml:id="id3"/> + <theta xml:lang="no"> + <beta content="attribute value" xml:lang="no"> + <beta/> + <theta object="content" xml:lang="en-GB" xml:id="id4"> + <rho title="100%" xml:lang="no" xml:id="id5"> + <green>This text must be green</green> + </rho> + </theta> + </beta> + </theta> + </any> + </theta> + </omega> + </chi> + </epsilon> + </tree> + </test> + <test> + <xpath>//*//tau[@content][@xml:lang="en"][following-sibling::nu[@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::eta[@xml:id="id2"][following-sibling::psi[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::phi[@xml:lang="nb"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//mu[@xml:id="id3"][not(following-sibling::*)]//delta[not(preceding-sibling::*)][following-sibling::kappa[starts-with(concat(@number,"-"),"100%-")][@xml:lang="en-US"][following-sibling::delta[starts-with(@abort,"this-")][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[@xml:lang="en-US"][@xml:id="id5"][not(preceding-sibling::*)]//nu[starts-with(@src,"at")][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <any> + <tau content="this-is-att-value" xml:lang="en"/> + <nu xml:id="id1"/> + <eta xml:id="id2"/> + <psi xml:lang="en-US"/> + <phi xml:lang="nb"> + <mu xml:id="id3"> + <delta/> + <kappa number="100%" xml:lang="en-US"/> + <delta abort="this-is-att-value" xml:id="id4"> + <nu xml:lang="en-US" xml:id="id5"> + <nu src="attribute"> + <green>This text must be green</green> + </nu> + </nu> + </delta> + </mu> + </phi> + </any> + </tree> + </test> + <test> + <xpath>//delta[@title]/tau[@xml:lang="nb"][@xml:id="id1"][not(child::node())][following-sibling::omicron[@xml:lang="en-US"][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/lambda[@object="attribute-value"][not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:lang="en-US"][@xml:id="id3"][following-sibling::xi[contains(@false,"a")][@xml:lang="en-US"][preceding-sibling::*[position() = 2]][following-sibling::epsilon[@number][@xml:lang="en-US"][@xml:id="id4"][not(child::node())][following-sibling::nu[@src="attribute value"][@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]//xi[@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::upsilon[starts-with(@src,"this.no")][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <delta title="_blank"> + <tau xml:lang="nb" xml:id="id1"/> + <omicron xml:lang="en-US"/> + <tau xml:id="id2"> + <lambda object="attribute-value"/> + <iota xml:lang="en-US" xml:id="id3"/> + <xi false="false" xml:lang="en-US"/> + <epsilon number="attribute" xml:lang="en-US" xml:id="id4"/> + <nu src="attribute value" xml:lang="en-US" xml:id="id5"> + <xi xml:id="id6"/> + <upsilon src="this.nodeValue" xml:id="id7"> + <chi xml:lang="en-GB" xml:id="id8"> + <green>This text must be green</green> + </chi> + </upsilon> + </nu> + </tau> + </delta> + </tree> + </test> + <test> + <xpath>//xi[@false]//rho[@xml:id="id1"][not(preceding-sibling::*)]//delta[@xml:id="id2"]/psi[@xml:lang="no-nb"][not(following-sibling::*)]/theta[@xml:id="id3"][not(preceding-sibling::*)]/sigma[@xml:lang="en-US"]/phi[@content="another attribute value"][@xml:lang="en-GB"][not(child::node())][following-sibling::chi[@desciption][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/iota[contains(concat(@attrib,"$"),"ute$")][@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]/sigma[@xml:id="id6"]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <xi false="attribute-value"> + <rho xml:id="id1"> + <delta xml:id="id2"> + <psi xml:lang="no-nb"> + <theta xml:id="id3"> + <sigma xml:lang="en-US"> + <phi content="another attribute value" xml:lang="en-GB"/> + <chi desciption="false" xml:id="id4"> + <iota attrib="attribute" xml:lang="en-US" xml:id="id5"> + <sigma xml:id="id6"> + <green>This text must be green</green> + </sigma> + </iota> + </chi> + </sigma> + </theta> + </psi> + </delta> + </rho> + </xi> + </tree> + </test> + <test> + <xpath>//sigma/epsilon[@attr][@xml:id="id1"]/xi[@xml:id="id2"][not(preceding-sibling::*)]//sigma[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[@xml:id="id3"][not(preceding-sibling::*)][following-sibling::*[position()=4]][following-sibling::xi[@title][@xml:id="id4"][preceding-sibling::*[position() = 1]][not(preceding-sibling::xi)][not(child::node())][following-sibling::pi[@xml:id="id5"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::omicron[@attr][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=1]][following-sibling::*[preceding-sibling::*[position() = 4]]//theta[not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::chi[@xml:id="id8"][following-sibling::*[position()=2]][following-sibling::theta[@xml:lang="en-US"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::upsilon[contains(@true,"_b")][@xml:lang="en"][@xml:id="id9"][preceding-sibling::*[position() = 3]]/epsilon[@xml:id="id10"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(@or," gree")][@xml:id="id11"][following-sibling::alpha[@token][@xml:id="id12"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::psi[@desciption="123456789"][@xml:lang="no"][preceding-sibling::*[position() = 3]]/gamma[@title][not(child::node())][following-sibling::omega[@xml:id="id13"][preceding-sibling::*[position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <epsilon attr="this-is-att-value" xml:id="id1"> + <xi xml:id="id2"> + <sigma xml:lang="en-US"> + <beta xml:id="id3"/> + <xi title="this-is-att-value" xml:id="id4"/> + <pi xml:id="id5"/> + <omicron attr="this.nodeValue" xml:id="id6"/> + <any> + <theta> + <epsilon xml:id="id7"/> + <chi xml:id="id8"/> + <theta xml:lang="en-US"/> + <upsilon true="_blank" xml:lang="en" xml:id="id9"> + <epsilon xml:id="id10"/> + <omicron or="solid 1px green" xml:id="id11"/> + <alpha token="another attribute value" xml:id="id12"/> + <psi desciption="123456789" xml:lang="no"> + <gamma title="attribute value"/> + <omega xml:id="id13"> + <green>This text must be green</green> + </omega> + </psi> + </upsilon> + </theta> + </any> + </sigma> + </xi> + </epsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//kappa[@string][@xml:lang="nb"][@xml:id="id1"]//lambda[starts-with(@attribute,"fal")][@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]/nu[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::theta[starts-with(@attribute,"con")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="en-GB"]/lambda[@xml:id="id4"][not(following-sibling::*)]/omega[starts-with(@token,"tru")][@xml:id="id5"]//tau[@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:id="id6"]/mu[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 1]]//gamma[starts-with(@data,"thi")][not(preceding-sibling::*)]//theta[starts-with(concat(@desciption,"-"),"true-")][@xml:lang="en"][following-sibling::lambda[not(following-sibling::*)]//phi[@xml:lang="nb"][@xml:id="id8"][not(child::node())][following-sibling::*[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[starts-with(concat(@content,"-"),"this.nodeValue-")][@xml:id="id9"]/epsilon[position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <kappa string="solid 1px green" xml:lang="nb" xml:id="id1"> + <lambda attribute="false" xml:lang="en-GB" xml:id="id2"> + <nu xml:lang="no-nb" xml:id="id3"/> + <theta attribute="content"/> + <xi xml:lang="en-GB"> + <lambda xml:id="id4"> + <omega token="true" xml:id="id5"> + <tau xml:lang="no-nb"> + <psi xml:id="id6"> + <mu xml:lang="nb"/> + <delta xml:lang="nb" xml:id="id7"> + <gamma data="this-is-att-value"> + <theta desciption="true" xml:lang="en"/> + <lambda> + <phi xml:lang="nb" xml:id="id8"/> + <any/> + <tau content="this.nodeValue" xml:id="id9"> + <epsilon> + <green>This text must be green</green> + </epsilon> + </tau> + </lambda> + </gamma> + </delta> + </psi> + </tau> + </omega> + </lambda> + </xi> + </lambda> + </kappa> + </tree> + </test> + <test> + <xpath>//psi[@name][@xml:lang="no-nb"]/epsilon[@abort="attribute-value"][@xml:id="id1"]//pi[contains(concat(@attr,"$"),"k$")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(concat(@token,"$"),"content$")][@xml:lang="no"][not(preceding-sibling::eta)][following-sibling::pi[starts-with(@string,"another attribute va")][@xml:id="id3"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][following-sibling::upsilon[starts-with(@attribute,"at")][@xml:id="id4"][following-sibling::pi[contains(concat(@string,"$")," attribute value$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 4]][following-sibling::alpha[@xml:id="id5"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <psi name="100%" xml:lang="no-nb"> + <epsilon abort="attribute-value" xml:id="id1"> + <pi attr="_blank" xml:lang="en" xml:id="id2"/> + <eta token="content" xml:lang="no"/> + <pi string="another attribute value" xml:id="id3"/> + <upsilon attribute="attribute-value" xml:id="id4"/> + <pi string="another attribute value" xml:lang="no-nb"/> + <alpha xml:id="id5"> + <green>This text must be green</green> + </alpha> + </epsilon> + </psi> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="no-nb"][@xml:id="id1"]//*[contains(@and,"%")][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@content="false"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/kappa[starts-with(@delete,"fa")][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@xml:lang="no"][@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=4]][following-sibling::sigma[@xml:id="id5"][following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[@xml:lang="nb"][preceding-sibling::*[position() = 3]][following-sibling::*[position()=2]][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::rho[@xml:lang="en-GB"][not(following-sibling::*)][position() = 1]]][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>any</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="no-nb" xml:id="id1"> + <any and="100%"/> + <alpha content="false" xml:id="id2"> + <kappa delete="false" xml:id="id3"/> + <psi xml:lang="no" xml:id="id4"/> + <sigma xml:id="id5"/> + <tau xml:lang="nb"/> + <rho xml:lang="en-GB"/> + <rho xml:lang="en-GB"> + <green>This text must be green</green> + </rho> + </alpha> + </delta> + </tree> + </test> + <test> + <xpath>//*[contains(@attr,"blank")]//sigma[contains(@abort,"t")][not(preceding-sibling::*)]/pi[@xml:lang="en-GB"]//phi[@string][@xml:id="id1"][following-sibling::*[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[starts-with(concat(@token,"-"),"another attribute value-")][@xml:id="id3"][not(preceding-sibling::*)][not(preceding-sibling::kappa or following-sibling::kappa)]/mu[not(preceding-sibling::*)][following-sibling::psi[@string][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::delta[starts-with(concat(@number,"-"),"123456789-")][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/sigma[contains(@false,"alue")][@xml:lang="nb"]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>phi</localname> + <nth>0</nth> + </result> + <tree> + <any attr="_blank"> + <sigma abort="content"> + <pi xml:lang="en-GB"> + <phi string="attribute value" xml:id="id1"/> + <any xml:lang="no" xml:id="id2"> + <kappa token="another attribute value" xml:id="id3"> + <mu/> + <psi string="_blank"/> + <alpha xml:lang="nb" xml:id="id4"/> + <delta number="123456789"> + <sigma false="this-is-att-value" xml:lang="nb"> + <green>This text must be green</green> + </sigma> + </delta> + </kappa> + </any> + </pi> + </sigma> + </any> + </tree> + </test> + <test> + <xpath>//eta[@desciption][@xml:id="id1"]//theta[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[starts-with(concat(@string,"-"),"100%-")][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]/omicron[starts-with(@true,"conten")][@xml:id="id3"][not(preceding-sibling::*)][following-sibling::lambda[@xml:lang="en"]//mu[not(preceding-sibling::*)]//*[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//nu[starts-with(concat(@and,"-"),"solid 1px green-")][not(preceding-sibling::*)]//psi[@xml:lang="en-US"][@xml:id="id4"]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <eta desciption="false" xml:id="id1"> + <theta xml:lang="en-US"> + <xi string="100%" xml:lang="en-US" xml:id="id2"> + <omicron true="content" xml:id="id3"/> + <lambda xml:lang="en"> + <mu> + <any xml:lang="en-GB"> + <nu and="solid 1px green"> + <psi xml:lang="en-US" xml:id="id4"> + <green>This text must be green</green> + </psi> + </nu> + </any> + </mu> + </lambda> + </xi> + </theta> + </eta> + </tree> + </test> + <test> + <xpath>//pi[@xml:lang="en-GB"]/tau[@attribute][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[contains(concat(@desciption,"$"),"attribute value$")][@xml:lang="no"]//pi[starts-with(@class,"true")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]/sigma[contains(concat(@att,"$")," 1px green$")][not(preceding-sibling::*)][not(following-sibling::*)]//sigma[starts-with(concat(@string,"-"),"false-")]//phi[contains(@desciption,"100%")][@xml:lang="en-GB"][not(following-sibling::*)]//zeta[@xml:id="id3"][not(following-sibling::*)]/pi[@class="another attribute value"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[starts-with(concat(@attribute,"-"),"attribute value-")][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:lang="en-US"][@xml:id="id5"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::lambda[@false="attribute"][@xml:lang="en"][@xml:id="id6"][preceding-sibling::*[position() = 3]]//alpha[@title][@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:lang="en-GB"> + <tau attribute="attribute" xml:id="id1"/> + <epsilon desciption="attribute value" xml:lang="no"> + <pi class="true" xml:lang="en" xml:id="id2"> + <sigma att="solid 1px green"> + <sigma string="false"> + <phi desciption="100%" xml:lang="en-GB"> + <zeta xml:id="id3"> + <pi class="another attribute value" xml:id="id4"/> + <pi attribute="attribute value" xml:lang="en-GB"/> + <theta xml:lang="en-US" xml:id="id5"/> + <lambda false="attribute" xml:lang="en" xml:id="id6"> + <alpha title="this.nodeValue" xml:lang="nb"> + <green>This text must be green</green> + </alpha> + </lambda> + </zeta> + </phi> + </sigma> + </sigma> + </pi> + </epsilon> + </pi> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="no"][@xml:id="id1"]//chi[@xml:id="id2"][not(preceding-sibling::*)]//lambda[@xml:id="id3"][not(child::node())][following-sibling::beta[preceding-sibling::*[position() = 1]]//psi[contains(@true,"0%")][@xml:lang="no"][@xml:id="id4"]/nu[@attrib][@xml:lang="no"][following-sibling::*[position()=2]][following-sibling::omega[contains(concat(@abort,"$"),"-is-att-value$")][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::iota[@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]//psi[contains(concat(@desciption,"$"),"ue$")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::iota[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::xi[@attr][@xml:id="id8"][following-sibling::*[position()=5]][following-sibling::chi[contains(concat(@att,"$"),"nk$")][following-sibling::*[position()=4]][not(child::node())][following-sibling::chi[@xml:lang="en-GB"][@xml:id="id9"][not(child::node())][following-sibling::kappa[@desciption="solid 1px green"][@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 5]][following-sibling::eta[contains(concat(@desciption,"$"),"te$")][following-sibling::eta[@xml:lang="nb"][not(following-sibling::*)]/eta[@true="123456789"][@xml:lang="nb"][not(preceding-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="no" xml:id="id1"> + <chi xml:id="id2"> + <lambda xml:id="id3"/> + <beta> + <psi true="100%" xml:lang="no" xml:id="id4"> + <nu attrib="123456789" xml:lang="no"/> + <omega abort="this-is-att-value"/> + <iota xml:lang="nb" xml:id="id5"> + <psi desciption="this-is-att-value" xml:lang="en-US" xml:id="id6"/> + <iota xml:id="id7"/> + <xi attr="false" xml:id="id8"/> + <chi att="_blank"/> + <chi xml:lang="en-GB" xml:id="id9"/> + <kappa desciption="solid 1px green" xml:lang="no" xml:id="id10"/> + <eta desciption="attribute"/> + <eta xml:lang="nb"> + <eta true="123456789" xml:lang="nb"> + <green>This text must be green</green> + </eta> + </eta> + </iota> + </psi> + </beta> + </chi> + </nu> + </tree> + </test> + <test> + <xpath>//theta[@att="false"][@xml:id="id1"]//epsilon[contains(concat(@false,"$"),"bute value$")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[starts-with(@or,"con")][@xml:lang="en-GB"][@xml:id="id3"][not(child::node())][following-sibling::mu[starts-with(concat(@att,"-"),"attribute-")][@xml:lang="no-nb"][@xml:id="id4"]/theta[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::omicron[following-sibling::tau[starts-with(@attrib,"attri")][@xml:lang="nb"][preceding-sibling::*[position() = 2]]//rho[@xml:lang="en-GB"][@xml:id="id6"][not(child::node())][following-sibling::tau[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/lambda[@xml:id="id8"]/rho[starts-with(@desciption,"attrib")][@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::upsilon[@xml:lang="no"][preceding-sibling::*[position() = 1]]//delta[@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::upsilon[contains(concat(@attrib,"$"),"56789$")][@xml:id="id10"]/alpha[starts-with(@attrib,"th")][@xml:lang="no"][not(preceding-sibling::*)][not(preceding-sibling::alpha)][following-sibling::gamma[contains(@delete,"4567")]/upsilon[@xml:lang="no-nb"][@xml:id="id11"][not(following-sibling::*)]//epsilon[@attr][@xml:lang="en-GB"][not(following-sibling::*)]/sigma[@xml:id="id12"]/epsilon[@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:id="id13"][following-sibling::omega[preceding-sibling::*[position() = 2]]/phi[@desciption][@xml:id="id14"][not(preceding-sibling::*)][not(following-sibling::*)]/pi[@content="false"][@xml:lang="en-US"][@xml:id="id15"][not(preceding-sibling::*)]]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <theta att="false" xml:id="id1"> + <epsilon false="attribute value" xml:id="id2"> + <beta or="content" xml:lang="en-GB" xml:id="id3"/> + <mu att="attribute-value" xml:lang="no-nb" xml:id="id4"> + <theta xml:lang="en" xml:id="id5"/> + <omicron/> + <tau attrib="attribute" xml:lang="nb"> + <rho xml:lang="en-GB" xml:id="id6"/> + <tau xml:id="id7"> + <lambda xml:id="id8"> + <rho desciption="attribute" xml:lang="no"/> + <upsilon xml:lang="no"> + <delta xml:id="id9"/> + <upsilon attrib="123456789" xml:id="id10"> + <alpha attrib="this-is-att-value" xml:lang="no"/> + <gamma delete="123456789"> + <upsilon xml:lang="no-nb" xml:id="id11"> + <epsilon attr="100%" xml:lang="en-GB"> + <sigma xml:id="id12"> + <epsilon xml:lang="en"/> + <omega xml:id="id13"/> + <omega> + <phi desciption="false" xml:id="id14"> + <pi content="false" xml:lang="en-US" xml:id="id15"> + <green>This text must be green</green> + </pi> + </phi> + </omega> + </sigma> + </epsilon> + </upsilon> + </gamma> + </upsilon> + </upsilon> + </lambda> + </tau> + </tau> + </mu> + </epsilon> + </theta> + </tree> + </test> + <test> + <xpath>//kappa[contains(@number,"e")][@xml:id="id1"]/upsilon[contains(concat(@title,"$"),"ue$")][@xml:lang="en"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:id="id2"]/nu[@delete="123456789"][@xml:lang="en-US"][@xml:id="id3"][following-sibling::*[position()=1]][not(child::node())][following-sibling::beta[@desciption][@xml:id="id4"]//alpha[@desciption][@xml:lang="en"][not(parent::*/*[position()=2])]//omicron[contains(concat(@name,"$"),"tent$")][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@xml:lang="nb"][@xml:id="id6"][not(preceding-sibling::*)][not(following-sibling::*)]/xi[@attr][@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::pi/upsilon[starts-with(@object,"_b")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::kappa[@abort][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[starts-with(concat(@class,"-"),"content-")][@xml:lang="en-US"][not(preceding-sibling::*)]//rho[@abort][not(following-sibling::*)]//kappa[@false][@xml:lang="en-GB"]/upsilon[@xml:id="id7"][not(following-sibling::*)]//eta[@attribute="this.nodeValue"]/theta[@xml:lang="en-GB"][@xml:id="id8"][not(child::node())][following-sibling::nu[preceding-sibling::*[position() = 1]]//xi[@string][@xml:lang="en-GB"][@xml:id="id9"]/eta[starts-with(@object,"1")][not(following-sibling::*)][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <kappa number="true" xml:id="id1"> + <upsilon title="true" xml:lang="en"/> + <sigma xml:id="id2"> + <nu delete="123456789" xml:lang="en-US" xml:id="id3"/> + <beta desciption="this.nodeValue" xml:id="id4"> + <alpha desciption="this.nodeValue" xml:lang="en"> + <omicron name="content" xml:id="id5"> + <upsilon xml:lang="nb" xml:id="id6"> + <xi attr="attribute value" xml:lang="no"/> + <pi> + <upsilon object="_blank" xml:lang="nb"/> + <kappa abort="false"> + <phi class="content" xml:lang="en-US"> + <rho abort="content"> + <kappa false="attribute" xml:lang="en-GB"> + <upsilon xml:id="id7"> + <eta attribute="this.nodeValue"> + <theta xml:lang="en-GB" xml:id="id8"/> + <nu> + <xi string="false" xml:lang="en-GB" xml:id="id9"> + <eta object="123456789"> + <green>This text must be green</green> + </eta> + </xi> + </nu> + </eta> + </upsilon> + </kappa> + </rho> + </phi> + </kappa> + </pi> + </upsilon> + </omicron> + </alpha> + </beta> + </sigma> + </kappa> + </tree> + </test> + <test> + <xpath>//zeta[@false]/mu[contains(@abort,"56789")][@xml:lang="en-US"][not(child::node())][following-sibling::mu[not(following-sibling::*)]//epsilon[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[contains(concat(@string,"$"),"ue$")][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[@attr="_blank"][not(preceding-sibling::*)]//phi[not(child::node())][following-sibling::theta[@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::chi[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]]/sigma[@xml:lang="nb"][not(child::node())][following-sibling::alpha[@desciption][@xml:id="id5"][preceding-sibling::*[position() = 1]]//xi[contains(concat(@desciption,"$"),"blank$")][@xml:id="id6"][following-sibling::chi[contains(@object,"er")][@xml:lang="en"][@xml:id="id7"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//*[@content][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[contains(@title,"a")][@xml:id="id9"][not(preceding-sibling::*)][not(preceding-sibling::pi)]//nu[@xml:lang="en-GB"][not(preceding-sibling::*)]//xi[@xml:lang="no"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::*[position()=2]][not(child::node())][following-sibling::kappa[@xml:id="id11"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::chi/alpha[@number][@xml:lang="en"][@xml:id="id12"][not(following-sibling::*)]//tau[not(preceding-sibling::*)][not(following-sibling::*)]/theta[@attr="_blank"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <zeta false="content"> + <mu abort="123456789" xml:lang="en-US"/> + <mu> + <epsilon xml:id="id1"/> + <tau string="true" xml:id="id2"> + <eta attr="_blank"> + <phi/> + <theta xml:lang="en" xml:id="id3"/> + <chi xml:lang="no-nb" xml:id="id4"> + <sigma xml:lang="nb"/> + <alpha desciption="this-is-att-value" xml:id="id5"> + <xi desciption="_blank" xml:id="id6"/> + <chi object="another attribute value" xml:lang="en" xml:id="id7"> + <any content="100%" xml:id="id8"> + <pi title="attribute" xml:id="id9"> + <nu xml:lang="en-GB"> + <xi xml:lang="no" xml:id="id10"/> + <kappa xml:id="id11"/> + <chi> + <alpha number="solid 1px green" xml:lang="en" xml:id="id12"> + <tau> + <theta attr="_blank"> + <green>This text must be green</green> + </theta> + </tau> + </alpha> + </chi> + </nu> + </pi> + </any> + </chi> + </alpha> + </chi> + </eta> + </tau> + </mu> + </zeta> + </tree> + </test> + <test> + <xpath>//lambda/chi[@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]//delta[not(preceding-sibling::delta or following-sibling::delta)][not(child::node())][following-sibling::omicron[contains(@data,"e")][@xml:lang="en-US"]/gamma/tau[@xml:lang="nb"][@xml:id="id2"]//eta[@number="this-is-att-value"][@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]/zeta[following-sibling::*[position()=2]][not(child::node())][following-sibling::theta[@xml:id="id4"][preceding-sibling::*[position() = 1]][following-sibling::delta[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <lambda> + <chi xml:lang="en-US" xml:id="id1"> + <delta/> + <omicron data="attribute-value" xml:lang="en-US"> + <gamma> + <tau xml:lang="nb" xml:id="id2"> + <eta number="this-is-att-value" xml:lang="nb" xml:id="id3"> + <zeta/> + <theta xml:id="id4"/> + <delta xml:lang="no-nb"> + <green>This text must be green</green> + </delta> + </eta> + </tau> + </gamma> + </omicron> + </chi> + </lambda> + </tree> + </test> + <test> + <xpath>//rho[@xml:id="id1"]/xi[contains(@object,"4")][@xml:lang="no-nb"][not(following-sibling::*)]//chi[@xml:id="id2"]/omega[@xml:lang="nb"][not(following-sibling::*)]//omega[not(child::node())][following-sibling::omicron[contains(concat(@title,"$"),"e$")][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//rho[contains(concat(@string,"$"),"ibute$")][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/iota[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)]/zeta[@xml:lang="no"][@xml:id="id5"]//kappa[@or="true"][@xml:lang="en-US"][not(preceding-sibling::*)]/*[starts-with(concat(@token,"-"),"another attribute value-")][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::gamma[@att="content"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[@xml:id="id6"][not(preceding-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>1</nth> + </result> + <tree> + <rho xml:id="id1"> + <xi object="123456789" xml:lang="no-nb"> + <chi xml:id="id2"> + <omega xml:lang="nb"> + <omega/> + <omicron title="true"> + <rho string="attribute" xml:id="id3"> + <iota xml:lang="en-US" xml:id="id4"> + <zeta xml:lang="no" xml:id="id5"> + <kappa or="true" xml:lang="en-US"> + <any token="another attribute value" xml:lang="en-GB"/> + <gamma att="content"> + <beta xml:id="id6"> + <green>This text must be green</green> + </beta> + </gamma> + </kappa> + </zeta> + </iota> + </rho> + </omicron> + </omega> + </chi> + </xi> + </rho> + </tree> + </test> + <test> + <xpath>//eta[@xml:lang="no"]//kappa[@xml:id="id1"][not(following-sibling::*)]/pi[@object][not(following-sibling::*)]//*[@and="true"][@xml:id="id2"]//omega[@title][following-sibling::*[position()=2]][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::lambda[@xml:lang="no"][@xml:id="id3"]//chi[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <eta xml:lang="no"> + <kappa xml:id="id1"> + <pi object="_blank"> + <any and="true" xml:id="id2"> + <omega title="attribute value"/> + <iota/> + <lambda xml:lang="no" xml:id="id3"> + <chi xml:lang="nb"> + <green>This text must be green</green> + </chi> + </lambda> + </any> + </pi> + </kappa> + </eta> + </tree> + </test> + <test> + <xpath>//*[@xml:id="id1"]//tau[starts-with(concat(@src,"-"),"this-")][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//pi[contains(@delete,"en")][@xml:lang="no-nb"][@xml:id="id3"]/theta[@title="attribute-value"][@xml:id="id4"][not(child::node())][following-sibling::iota[@desciption="another attribute value"][@xml:lang="en-GB"][@xml:id="id5"]//tau[@xml:lang="no"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(preceding-sibling::tau)][following-sibling::omega[@xml:lang="en-GB"]/tau[starts-with(@desciption,"attrib")][@xml:id="id7"]//beta[not(preceding-sibling::*)][not(child::node())][following-sibling::iota[preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][following-sibling::alpha[@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//xi[starts-with(concat(@delete,"-"),"true-")][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id10"][preceding-sibling::*[position() = 1]][following-sibling::alpha[@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[contains(concat(@string,"$"),"nodeValue$")]/tau[@xml:lang="en-US"][@xml:id="id12"][not(following-sibling::*)]//mu[contains(@true,"t")][@xml:id="id13"][not(preceding-sibling::*)]/upsilon[starts-with(concat(@or,"-"),"123456789-")][following-sibling::zeta[@and][@xml:id="id14"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::zeta[@xml:id="id15"]/mu[@xml:lang="en-US"][not(preceding-sibling::*)]/alpha[@true][not(following-sibling::*)]//sigma[@xml:id="id16"][not(preceding-sibling::*)][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <any xml:id="id1"> + <tau src="this-is-att-value" xml:lang="en" xml:id="id2"> + <pi delete="solid 1px green" xml:lang="no-nb" xml:id="id3"> + <theta title="attribute-value" xml:id="id4"/> + <iota desciption="another attribute value" xml:lang="en-GB" xml:id="id5"> + <tau xml:lang="no" xml:id="id6"/> + <omega xml:lang="en-GB"> + <tau desciption="attribute" xml:id="id7"> + <beta/> + <iota/> + <alpha xml:lang="nb" xml:id="id8"> + <xi delete="true" xml:id="id9"/> + <upsilon xml:id="id10"/> + <alpha xml:lang="nb" xml:id="id11"/> + <epsilon string="this.nodeValue"> + <tau xml:lang="en-US" xml:id="id12"> + <mu true="attribute value" xml:id="id13"> + <upsilon or="123456789"/> + <zeta and="attribute value" xml:id="id14"/> + <zeta xml:id="id15"> + <mu xml:lang="en-US"> + <alpha true="100%"> + <sigma xml:id="id16"> + <green>This text must be green</green> + </sigma> + </alpha> + </mu> + </zeta> + </mu> + </tau> + </epsilon> + </alpha> + </tau> + </omega> + </iota> + </pi> + </tau> + </any> + </tree> + </test> + <test> + <xpath>//chi[contains(concat(@number,"$"),"-value$")][@xml:lang="nb"]/rho[@name="100%"][@xml:id="id1"][not(preceding-sibling::rho)]//mu[@attrib][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::upsilon[@xml:id="id3"][preceding-sibling::*[position() = 1]]/pi[starts-with(concat(@false,"-"),"false-")][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[@name="100%"][@xml:lang="en-US"][not(following-sibling::*)]/pi[contains(concat(@attribute,"$"),"value$")][@xml:lang="en-GB"][following-sibling::sigma[contains(concat(@name,"$"),"lid 1px green$")][@xml:lang="en-GB"][@xml:id="id5"][not(following-sibling::*)]/lambda[starts-with(concat(@object,"-"),"123456789-")][@xml:id="id6"][not(preceding-sibling::*)][not(child::node())][following-sibling::phi[@xml:id="id7"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::upsilon[preceding-sibling::*[position() = 2]][following-sibling::lambda[@xml:lang="en-US"][preceding-sibling::*[position() = 3]][following-sibling::nu[contains(@attr,"_blan")][@xml:lang="en"][not(following-sibling::*)]/sigma[contains(concat(@true,"$"),"789$")][@xml:lang="no"][@xml:id="id8"][following-sibling::omega[starts-with(concat(@data,"-"),"attribute value-")][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::omicron[@token="another attribute value"][@xml:id="id9"][not(following-sibling::*)]/mu[@xml:id="id10"][not(preceding-sibling::*)]//beta[@object][@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::*[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//epsilon[starts-with(@and,"another attribute v")][@xml:id="id11"][position() = 1]]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>mu</localname> + <nth>0</nth> + </result> + <tree> + <chi number="attribute-value" xml:lang="nb"> + <rho name="100%" xml:id="id1"> + <mu attrib="true" xml:lang="en" xml:id="id2"/> + <upsilon xml:id="id3"> + <pi false="false" xml:id="id4"/> + <any name="100%" xml:lang="en-US"> + <pi attribute="this-is-att-value" xml:lang="en-GB"/> + <sigma name="solid 1px green" xml:lang="en-GB" xml:id="id5"> + <lambda object="123456789" xml:id="id6"/> + <phi xml:id="id7"/> + <upsilon/> + <lambda xml:lang="en-US"/> + <nu attr="_blank" xml:lang="en"> + <sigma true="123456789" xml:lang="no" xml:id="id8"/> + <omega data="attribute value"/> + <omicron token="another attribute value" xml:id="id9"> + <mu xml:id="id10"> + <beta object="true" xml:lang="en-GB"/> + <any> + <epsilon and="another attribute value" xml:id="id11"> + <green>This text must be green</green> + </epsilon> + </any> + </mu> + </omicron> + </nu> + </sigma> + </any> + </upsilon> + </rho> + </chi> + </tree> + </test> + <test> + <xpath>//chi[@xml:id="id1"]//eta[@xml:lang="en-GB"][@xml:id="id2"][not(following-sibling::*)]/omega[@desciption]/pi/omicron[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[contains(@true,"ttribute ")][@xml:lang="en"][not(child::node())][following-sibling::psi[@xml:lang="no"][preceding-sibling::*[position() = 2]]//*[following-sibling::mu[contains(@data,"alse")][@xml:lang="no-nb"][@xml:id="id4"][not(child::node())][following-sibling::psi[starts-with(@att,"this.nodeVa")][preceding-sibling::*[position() = 2]]//delta[starts-with(@att,"this-is-att")][not(child::node())][following-sibling::mu[@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@xml:lang="en-US"][@xml:id="id6"][not(preceding-sibling::*)]/xi[@desciption][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//tau[contains(concat(@attr,"$"),"ue$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::mu[@xml:lang="no-nb"][@xml:id="id8"]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omicron</localname> + <nth>0</nth> + </result> + <tree> + <chi xml:id="id1"> + <eta xml:lang="en-GB" xml:id="id2"> + <omega desciption="attribute"> + <pi> + <omicron xml:id="id3"/> + <kappa true="another attribute value" xml:lang="en"/> + <psi xml:lang="no"> + <any/> + <mu data="false" xml:lang="no-nb" xml:id="id4"/> + <psi att="this.nodeValue"> + <delta att="this-is-att-value"/> + <mu xml:id="id5"> + <phi xml:lang="en-US" xml:id="id6"> + <xi desciption="123456789" xml:id="id7"> + <tau attr="this-is-att-value" xml:lang="no-nb"/> + <mu xml:lang="no-nb" xml:id="id8"> + <green>This text must be green</green> + </mu> + </xi> + </phi> + </mu> + </psi> + </psi> + </pi> + </omega> + </eta> + </chi> + </tree> + </test> + <test> + <xpath>//chi[@xml:lang="nb"]//chi[not(child::node())][following-sibling::lambda[contains(concat(@desciption,"$"),"00%$")][@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::iota[starts-with(@desciption,"att")][@xml:lang="en-GB"][@xml:id="id3"]//rho[@abort="attribute value"][@xml:id="id4"][not(preceding-sibling::*)]/psi[following-sibling::*[position()=1]][following-sibling::upsilon[@data][@xml:id="id5"][preceding-sibling::*[position() = 1]]//sigma[contains(@false,"n")][@xml:id="id6"][following-sibling::theta[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/theta[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::eta[contains(@and,"nt")][@xml:id="id8"][preceding-sibling::*[position() = 1]][following-sibling::alpha[starts-with(concat(@src,"-"),"attribute-")][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::tau[contains(concat(@and,"$"),"blank$")][preceding-sibling::*[position() = 3]]/nu[@xml:lang="en"][@xml:id="id9"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::iota[@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::nu[@insert="attribute value"][@xml:id="id11"][preceding-sibling::*[position() = 2]]//psi[starts-with(@false,"c")][@xml:lang="no"][@xml:id="id12"]][position() = 1]]][position() = 1]]]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>1</nth> + </result> + <tree> + <chi xml:lang="nb"> + <chi/> + <lambda desciption="100%" xml:lang="en-GB" xml:id="id1"/> + <tau xml:id="id2"/> + <iota desciption="attribute-value" xml:lang="en-GB" xml:id="id3"> + <rho abort="attribute value" xml:id="id4"> + <psi/> + <upsilon data="this-is-att-value" xml:id="id5"> + <sigma false="_blank" xml:id="id6"/> + <theta> + <theta xml:lang="no" xml:id="id7"/> + <eta and="content" xml:id="id8"/> + <alpha src="attribute" xml:lang="no"/> + <tau and="_blank"> + <nu xml:lang="en" xml:id="id9"/> + <iota xml:lang="en-US" xml:id="id10"/> + <nu insert="attribute value" xml:id="id11"> + <psi false="content" xml:lang="no" xml:id="id12"> + <green>This text must be green</green> + </psi> + </nu> + </tau> + </theta> + </upsilon> + </rho> + </iota> + </chi> + </tree> + </test> + <test> + <xpath>//epsilon[contains(@desciption,"te-valu")][@xml:lang="no"][@xml:id="id1"]/alpha[@xml:lang="en-US"][not(child::node())][following-sibling::alpha[starts-with(concat(@insert,"-"),"content-")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@attribute="attribute-value"][@xml:id="id2"][following-sibling::*[position()=1]][not(child::node())][following-sibling::epsilon[starts-with(@insert,"another attribute va")][@xml:id="id3"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//sigma[@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/tau[following-sibling::upsilon[@delete="this.nodeValue"][@xml:lang="en-US"][@xml:id="id4"]//nu[not(preceding-sibling::nu)]//pi[starts-with(concat(@object,"-"),"attribute value-")][@xml:lang="en-GB"]//*[not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="nb"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <epsilon desciption="attribute-value" xml:lang="no" xml:id="id1"> + <alpha xml:lang="en-US"/> + <alpha insert="content" xml:lang="nb"/> + <pi attribute="attribute-value" xml:id="id2"/> + <epsilon insert="another attribute value" xml:id="id3"> + <sigma xml:lang="en-US"> + <tau/> + <upsilon delete="this.nodeValue" xml:lang="en-US" xml:id="id4"> + <nu> + <pi object="attribute value" xml:lang="en-GB"> + <any> + <rho xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </rho> + </any> + </pi> + </nu> + </upsilon> + </sigma> + </epsilon> + </epsilon> + </tree> + </test> + <test> + <xpath>//beta[@xml:lang="no-nb"][@xml:id="id1"]//beta[starts-with(concat(@true,"-"),"this-")][@xml:lang="en-US"][@xml:id="id2"][following-sibling::zeta[@xml:id="id3"][preceding-sibling::*[position() = 1]]//eta[@xml:lang="no"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::tau[@attribute="true"][@xml:lang="en-GB"][@xml:id="id4"][preceding-sibling::*[position() = 1]]//alpha[@data][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::tau[@xml:id="id6"][following-sibling::*[starts-with(concat(@insert,"-"),"this.nodeValue-")][not(child::node())][following-sibling::eta[starts-with(@desciption,"true")][@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::chi[starts-with(@false,"fa")][@xml:lang="en-US"][@xml:id="id8"][not(following-sibling::*)]/eta[@xml:lang="no"][@xml:id="id9"][not(following-sibling::*)]//pi[@string][@xml:lang="en"][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@xml:lang="en-US"][@xml:id="id10"]/delta[@xml:lang="no-nb"]/phi[following-sibling::iota[starts-with(concat(@insert,"-"),"123456789-")][@xml:lang="en"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::pi[contains(@string,"lse")][@xml:lang="no"][not(child::node())][following-sibling::nu[contains(@string,"ribute-value")][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::upsilon[@true][@xml:id="id11"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]//zeta[starts-with(concat(@string,"-"),"this.nodeValue-")][not(preceding-sibling::*)]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>1</nth> + </result> + <tree> + <beta xml:lang="no-nb" xml:id="id1"> + <beta true="this-is-att-value" xml:lang="en-US" xml:id="id2"/> + <zeta xml:id="id3"> + <eta xml:lang="no"/> + <tau attribute="true" xml:lang="en-GB" xml:id="id4"> + <alpha data="attribute value" xml:id="id5"/> + <tau xml:id="id6"/> + <any insert="this.nodeValue"/> + <eta desciption="true" xml:id="id7"/> + <chi false="false" xml:lang="en-US" xml:id="id8"> + <eta xml:lang="no" xml:id="id9"> + <pi string="another attribute value" xml:lang="en"/> + <pi xml:lang="en-US" xml:id="id10"> + <delta xml:lang="no-nb"> + <phi/> + <iota insert="123456789" xml:lang="en"/> + <pi string="false" xml:lang="no"/> + <nu string="attribute-value"/> + <upsilon true="this.nodeValue" xml:id="id11"> + <zeta string="this.nodeValue"> + <green>This text must be green</green> + </zeta> + </upsilon> + </delta> + </pi> + </eta> + </chi> + </tau> + </zeta> + </beta> + </tree> + </test> + <test> + <xpath>//tau[@xml:lang="nb"]//gamma[contains(concat(@string,"$"),"_blank$")][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/sigma[following-sibling::pi[following-sibling::*[position()=3]][not(child::node())][following-sibling::tau[@xml:id="id2"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=2]][following-sibling::lambda[@xml:id="id3"][following-sibling::rho[@name][@xml:lang="en"]/iota[@or="content"][@xml:lang="nb"][@xml:id="id4"][not(following-sibling::*)]//iota[@xml:id="id5"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::nu[@src][@xml:lang="no-nb"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>sigma</localname> + <nth>0</nth> + </result> + <tree> + <tau xml:lang="nb"> + <gamma string="_blank" xml:id="id1"> + <sigma/> + <pi/> + <tau xml:id="id2"/> + <lambda xml:id="id3"/> + <rho name="100%" xml:lang="en"> + <iota or="content" xml:lang="nb" xml:id="id4"> + <iota xml:id="id5"/> + <nu src="false" xml:lang="no-nb" xml:id="id6"> + <green>This text must be green</green> + </nu> + </iota> + </rho> + </gamma> + </tau> + </tree> + </test> + <test> + <xpath>//nu[@desciption]//chi[@xml:id="id1"][not(preceding-sibling::*)][not(child::node())][following-sibling::omega[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/mu[@xml:lang="no-nb"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]/beta[starts-with(@att,"another attribute v")][not(child::node())][following-sibling::sigma[not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>chi</localname> + <nth>0</nth> + </result> + <tree> + <nu desciption="attribute value"> + <chi xml:id="id1"/> + <omega xml:id="id2"> + <mu xml:lang="no-nb" xml:id="id3"> + <beta att="another attribute value"/> + <sigma> + <green>This text must be green</green> + </sigma> + </mu> + </omega> + </nu> + </tree> + </test> + <test> + <xpath>//iota/eta[@class="attribute-value"][@xml:lang="nb"][@xml:id="id1"]/alpha[@class="true"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[contains(@desciption,"%")][@xml:id="id3"][not(preceding-sibling::*)]/rho[@title][@xml:lang="nb"][not(child::node())][following-sibling::chi[@and="false"][@xml:id="id4"][not(child::node())][following-sibling::rho[@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/*[@content][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:lang="nb"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/tau[starts-with(@class,"c")][not(child::node())][following-sibling::tau[@name="this-is-att-value"][not(child::node())][following-sibling::delta[@xml:lang="nb"][@xml:id="id6"][following-sibling::alpha[@xml:lang="nb"][@xml:id="id7"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]//omega[@xml:id="id8"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[contains(@false,"ue")][@xml:lang="en-US"][@xml:id="id9"]/lambda[@insert][@xml:id="id10"]/*[@desciption="true"][@xml:lang="en-US"][@xml:id="id11"][not(following-sibling::*)]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <iota> + <eta class="attribute-value" xml:lang="nb" xml:id="id1"> + <alpha class="true" xml:id="id2"/> + <tau> + <chi desciption="100%" xml:id="id3"> + <rho title="attribute" xml:lang="nb"/> + <chi and="false" xml:id="id4"/> + <rho xml:lang="no"> + <any content="true"/> + <eta xml:lang="nb" xml:id="id5"> + <tau class="content"/> + <tau name="this-is-att-value"/> + <delta xml:lang="nb" xml:id="id6"/> + <alpha xml:lang="nb" xml:id="id7"> + <omega xml:id="id8"/> + <eta false="this-is-att-value" xml:lang="en-US" xml:id="id9"> + <lambda insert="true" xml:id="id10"> + <any desciption="true" xml:lang="en-US" xml:id="id11"> + <green>This text must be green</green> + </any> + </lambda> + </eta> + </alpha> + </eta> + </rho> + </chi> + </tau> + </eta> + </iota> + </tree> + </test> + <test> + <xpath>//gamma/rho[following-sibling::*[position()=1]][not(child::node())][following-sibling::psi/mu[@xml:lang="en"][@xml:id="id1"][not(preceding-sibling::*)]/omicron[@xml:id="id2"][not(following-sibling::*)]//pi[@class][@xml:lang="en"][not(following-sibling::pi)][following-sibling::eta[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=2]][following-sibling::lambda[not(child::node())][following-sibling::chi[@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][not(following-sibling::*)][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>rho</localname> + <nth>0</nth> + </result> + <tree> + <gamma> + <rho/> + <psi> + <mu xml:lang="en" xml:id="id1"> + <omicron xml:id="id2"> + <pi class="true" xml:lang="en"/> + <eta xml:id="id3"/> + <lambda/> + <chi xml:lang="no-nb"> + <green>This text must be green</green> + </chi> + </omicron> + </mu> + </psi> + </gamma> + </tree> + </test> + <test> + <xpath>//theta//beta[@xml:lang="en"][not(child::node())][following-sibling::iota[@number][not(preceding-sibling::iota)][following-sibling::chi[@src][@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]/rho[not(preceding-sibling::*)][following-sibling::delta[@xml:lang="no"][@xml:id="id2"][preceding-sibling::*[position() = 1]][following-sibling::mu[contains(concat(@data,"$"),"ank$")][@xml:lang="en"][@xml:id="id3"][not(child::node())][following-sibling::pi[@xml:lang="en"][following-sibling::theta[@abort="_blank"][@xml:lang="en-US"][@xml:id="id4"][preceding-sibling::*[position() = 4]][not(following-sibling::*)]/omicron[starts-with(@title,"fals")][not(preceding-sibling::*)][following-sibling::alpha[starts-with(@title,"attribute-v")][not(following-sibling::*)]/sigma[@attribute][@xml:id="id5"][following-sibling::pi[@xml:lang="en-GB"][not(child::node())][following-sibling::kappa[@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::kappa[not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 4]][following-sibling::*[position()=1]][following-sibling::*[@xml:id="id6"][preceding-sibling::*[position() = 5]]/lambda[contains(concat(@false,"$"),"alue$")][@xml:lang="nb"][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::delta[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/alpha[@xml:id="id8"][not(parent::*/*[position()=2])]//lambda[@xml:lang="no-nb"][@xml:id="id9"][not(child::node())][following-sibling::tau[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/phi[position() = 1]]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>beta</localname> + <nth>0</nth> + </result> + <tree> + <theta> + <beta xml:lang="en"/> + <iota number="this.nodeValue"/> + <chi src="_blank" xml:lang="en-US" xml:id="id1"> + <rho/> + <delta xml:lang="no" xml:id="id2"/> + <mu data="_blank" xml:lang="en" xml:id="id3"/> + <pi xml:lang="en"/> + <theta abort="_blank" xml:lang="en-US" xml:id="id4"> + <omicron title="false"/> + <alpha title="attribute-value"> + <sigma attribute="attribute-value" xml:id="id5"/> + <pi xml:lang="en-GB"/> + <kappa xml:lang="no-nb"/> + <kappa/> + <sigma xml:lang="en-GB"/> + <any xml:id="id6"> + <lambda false="attribute-value" xml:lang="nb" xml:id="id7"/> + <delta xml:lang="en-GB"> + <alpha xml:id="id8"> + <lambda xml:lang="no-nb" xml:id="id9"/> + <tau xml:lang="no-nb"> + <phi> + <green>This text must be green</green> + </phi> + </tau> + </alpha> + </delta> + </any> + </alpha> + </theta> + </chi> + </theta> + </tree> + </test> + <test> + <xpath>//mu[starts-with(@data,"attribut")]/epsilon[@xml:lang="nb"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::eta[contains(@attr,"ank")][not(child::node())][following-sibling::gamma[starts-with(concat(@string,"-"),"attribute-")][@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/eta[@delete][@xml:lang="en"][@xml:id="id3"][following-sibling::*[@content][@xml:lang="nb"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=3]][following-sibling::beta[@desciption][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::epsilon[contains(concat(@token,"$"),"een$")][@xml:lang="en"][preceding-sibling::*[position() = 3]][following-sibling::alpha[@att][@xml:lang="no-nb"][@xml:id="id5"][not(following-sibling::*)][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>epsilon</localname> + <nth>0</nth> + </result> + <tree> + <mu data="attribute value"> + <epsilon xml:lang="nb" xml:id="id1"/> + <eta attr="_blank"/> + <gamma string="attribute-value" xml:lang="en-US" xml:id="id2"> + <eta delete="this.nodeValue" xml:lang="en" xml:id="id3"/> + <any content="false" xml:lang="nb"/> + <beta desciption="another attribute value" xml:id="id4"/> + <epsilon token="solid 1px green" xml:lang="en"/> + <alpha att="content" xml:lang="no-nb" xml:id="id5"> + <green>This text must be green</green> + </alpha> + </gamma> + </mu> + </tree> + </test> + <test> + <xpath>//kappa[@delete][@xml:lang="en-GB"]//epsilon[@xml:lang="no"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/eta[@xml:lang="en-GB"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::*[@false][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/nu[@desciption="false"][not(preceding-sibling::*)]/pi[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::beta//theta[starts-with(concat(@content,"-"),"attribute-")][@xml:lang="no"][@xml:id="id5"][not(child::node())][following-sibling::sigma[starts-with(concat(@desciption,"-"),"this-")][@xml:lang="nb"][@xml:id="id6"][not(following-sibling::*)]/nu[@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)][not(preceding-sibling::nu)]//gamma[starts-with(concat(@attrib,"-"),"this.nodeValue-")][@xml:id="id8"]//theta[contains(@title,"ue")][@xml:id="id9"][following-sibling::*[position()=1]][following-sibling::kappa[preceding-sibling::*[position() = 1]][not(following-sibling::*)]//sigma[@xml:lang="no-nb"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::omicron[starts-with(@token,"soli")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::rho[@xml:lang="no"][preceding-sibling::*[position() = 2]]/mu[contains(@src,"e")][@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]]]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <kappa delete="100%" xml:lang="en-GB"> + <epsilon xml:lang="no" xml:id="id1"> + <eta xml:lang="en-GB" xml:id="id2"/> + <any false="false" xml:id="id3"> + <nu desciption="false"> + <pi xml:lang="en-GB" xml:id="id4"/> + <beta> + <theta content="attribute-value" xml:lang="no" xml:id="id5"/> + <sigma desciption="this-is-att-value" xml:lang="nb" xml:id="id6"> + <nu xml:lang="en" xml:id="id7"> + <gamma attrib="this.nodeValue" xml:id="id8"> + <theta title="this.nodeValue" xml:id="id9"/> + <kappa> + <sigma xml:lang="no-nb" xml:id="id10"/> + <omicron token="solid 1px green" xml:lang="no-nb"/> + <rho xml:lang="no"> + <mu src="attribute" xml:lang="en"> + <rho xml:lang="nb"> + <green>This text must be green</green> + </rho> + </mu> + </rho> + </kappa> + </gamma> + </nu> + </sigma> + </beta> + </nu> + </any> + </epsilon> + </kappa> + </tree> + </test> + <test> + <xpath>//nu[@xml:lang="nb"]/eta[@xml:id="id1"]/*[@object][@xml:lang="en-US"][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[contains(concat(@abort,"$"),"bute value$")][@xml:lang="nb"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omicron[@xml:lang="no"][@xml:id="id2"][following-sibling::*[position()=1]][following-sibling::epsilon[contains(@object,"t")][preceding-sibling::*[position() = 2]]//upsilon[@xml:lang="en-US"][@xml:id="id3"]//mu[@xml:lang="nb"][following-sibling::epsilon[preceding-sibling::*[position() = 1]][not(following-sibling::*)]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:lang="nb"> + <eta xml:id="id1"> + <any object="solid 1px green" xml:lang="en-US"> + <zeta abort="attribute value" xml:lang="nb"/> + <omicron xml:lang="no" xml:id="id2"/> + <epsilon object="content"> + <upsilon xml:lang="en-US" xml:id="id3"> + <mu xml:lang="nb"/> + <epsilon> + <green>This text must be green</green> + </epsilon> + </upsilon> + </epsilon> + </any> + </eta> + </nu> + </tree> + </test> + <test> + <xpath>//phi[contains(concat(@string,"$"),"e$")][@xml:lang="en"][@xml:id="id1"]//iota[@xml:lang="en-US"]//upsilon[contains(concat(@string,"$"),"bute value$")][@xml:lang="en-US"][@xml:id="id2"]//nu[@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::omicron[contains(concat(@insert,"$"),"content$")][@xml:lang="en"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//chi[@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <phi string="false" xml:lang="en" xml:id="id1"> + <iota xml:lang="en-US"> + <upsilon string="attribute value" xml:lang="en-US" xml:id="id2"> + <nu xml:id="id3"/> + <omicron insert="content" xml:lang="en"> + <chi xml:lang="no" xml:id="id4"/> + <sigma xml:lang="en-GB"> + <green>This text must be green</green> + </sigma> + </omicron> + </upsilon> + </iota> + </phi> + </tree> + </test> + <test> + <xpath>//xi[@delete]//theta[@xml:id="id1"][following-sibling::beta[@xml:lang="en-GB"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/upsilon[@content][following-sibling::omega[@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::*[position()=1]][not(child::node())][following-sibling::pi[@token][@xml:id="id4"][not(following-sibling::*)]/gamma[@xml:lang="en"][not(preceding-sibling::*)]/gamma[@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[@xml:lang="en"]/rho[@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::beta[contains(@src,"-is")][@xml:id="id6"][preceding-sibling::*[position() = 1]]//*[starts-with(concat(@src,"-"),"another attribute value-")][@xml:id="id7"][not(following-sibling::*)]//rho[not(following-sibling::*)]/mu[contains(@attribute,"tr")][@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]/theta[starts-with(concat(@title,"-"),"_blank-")][@xml:id="id9"][not(child::node())][following-sibling::rho[@xml:id="id10"][preceding-sibling::*[position() = 1]]//xi[starts-with(concat(@and,"-"),"true-")][not(preceding-sibling::*)][following-sibling::omicron[@content][not(child::node())][following-sibling::theta[@xml:lang="nb"][@xml:id="id11"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//upsilon[@class="attribute"][following-sibling::zeta//eta[@name="true"][@xml:lang="en-GB"][@xml:id="id12"][following-sibling::beta[starts-with(@abort,"attribu")][@xml:id="id13"][not(child::node())][following-sibling::gamma[starts-with(concat(@title,"-"),"solid 1px green-")][@xml:lang="no-nb"][@xml:id="id14"][preceding-sibling::*[position() = 2]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>theta</localname> + <nth>0</nth> + </result> + <tree> + <xi delete="attribute-value"> + <theta xml:id="id1"/> + <beta xml:lang="en-GB" xml:id="id2"> + <upsilon content="100%"/> + <omega xml:id="id3"/> + <pi token="attribute-value" xml:id="id4"> + <gamma xml:lang="en"> + <gamma xml:lang="en-US"/> + <alpha xml:lang="en"> + <rho xml:id="id5"/> + <beta src="this-is-att-value" xml:id="id6"> + <any src="another attribute value" xml:id="id7"> + <rho> + <mu attribute="attribute" xml:id="id8"> + <theta title="_blank" xml:id="id9"/> + <rho xml:id="id10"> + <xi and="true"/> + <omicron content="attribute-value"/> + <theta xml:lang="nb" xml:id="id11"> + <upsilon class="attribute"/> + <zeta> + <eta name="true" xml:lang="en-GB" xml:id="id12"/> + <beta abort="attribute" xml:id="id13"/> + <gamma title="solid 1px green" xml:lang="no-nb" xml:id="id14"> + <green>This text must be green</green> + </gamma> + </zeta> + </theta> + </rho> + </mu> + </rho> + </any> + </beta> + </alpha> + </gamma> + </pi> + </beta> + </xi> + </tree> + </test> + <test> + <xpath>//lambda[starts-with(concat(@content,"-"),"this.nodeValue-")]//psi[@xml:lang="no"]/kappa[following-sibling::*[position()=3]][not(child::node())][following-sibling::omega[@xml:lang="en-GB"][@xml:id="id1"][preceding-sibling::*[position() = 1]][following-sibling::pi[@attrib="another attribute value"][@xml:id="id2"][following-sibling::iota[@xml:lang="nb"][@xml:id="id3"][not(following-sibling::*)]//mu[contains(concat(@content,"$"),"reen$")][@xml:lang="en-US"][@xml:id="id4"][following-sibling::gamma[@false]/rho[@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 1]][following-sibling::kappa[@xml:id="id6"][following-sibling::eta[@content="another attribute value"][@xml:lang="nb"][@xml:id="id7"][not(following-sibling::*)]/upsilon[@token="attribute value"][@xml:lang="nb"][not(child::node())][following-sibling::lambda[@true][@xml:id="id8"][not(following-sibling::*)]//theta[starts-with(@or,"_blan")]//psi[@xml:lang="en-US"][not(following-sibling::*)]//upsilon[@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::upsilon[starts-with(@object,"1234567")][@xml:lang="en-US"][@xml:id="id9"][not(following-sibling::*)]//mu[@xml:id="id10"][not(following-sibling::*)]/omega[@xml:id="id11"]]][position() = 1]]]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <lambda content="this.nodeValue"> + <psi xml:lang="no"> + <kappa/> + <omega xml:lang="en-GB" xml:id="id1"/> + <pi attrib="another attribute value" xml:id="id2"/> + <iota xml:lang="nb" xml:id="id3"> + <mu content="solid 1px green" xml:lang="en-US" xml:id="id4"/> + <gamma false="another attribute value"> + <rho xml:lang="en-GB" xml:id="id5"/> + <alpha/> + <kappa xml:id="id6"/> + <eta content="another attribute value" xml:lang="nb" xml:id="id7"> + <upsilon token="attribute value" xml:lang="nb"/> + <lambda true="this-is-att-value" xml:id="id8"> + <theta or="_blank"> + <psi xml:lang="en-US"> + <upsilon xml:lang="en-US"/> + <upsilon object="123456789" xml:lang="en-US" xml:id="id9"> + <mu xml:id="id10"> + <omega xml:id="id11"> + <green>This text must be green</green> + </omega> + </mu> + </upsilon> + </psi> + </theta> + </lambda> + </eta> + </gamma> + </iota> + </psi> + </lambda> + </tree> + </test> + <test> + <xpath>//upsilon[@xml:lang="en-US"][@xml:id="id1"]//nu[not(child::node())][following-sibling::psi[@xml:id="id2"][not(following-sibling::*)]/nu[@abort="_blank"][not(preceding-sibling::*)][following-sibling::iota[@delete][@xml:id="id3"][following-sibling::*[position()=2]][not(child::node())][following-sibling::phi[@xml:lang="nb"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::xi[@false][@xml:lang="no"]//upsilon[contains(concat(@src,"$"),"attribute-value$")][@xml:lang="en-US"][not(preceding-sibling::*)]//eta[@true][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:lang="en-GB"][not(preceding-sibling::*)][not(following-sibling::*)]//alpha[@false][@xml:id="id4"]//*[@string][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@insert,"$"),"rue$")][@xml:lang="nb"][not(child::node())][following-sibling::rho//nu[@xml:lang="nb"][not(preceding-sibling::*)]//delta[starts-with(concat(@attrib,"-"),"true-")][@xml:id="id5"][following-sibling::*[position()=1]][following-sibling::phi[@xml:lang="en-US"][@xml:id="id6"]//nu[starts-with(concat(@src,"-"),"attribute-")][@xml:lang="en-GB"][following-sibling::*[position()=1]][not(child::node())][following-sibling::gamma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[@xml:lang="en"][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][@xml:id="id7"][not(following-sibling::*)]/omicron[contains(concat(@attribute,"$"),"ribute-value$")][@xml:lang="no-nb"][not(preceding-sibling::*)][not(following-sibling::*)]]]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>nu</localname> + <nth>0</nth> + </result> + <tree> + <upsilon xml:lang="en-US" xml:id="id1"> + <nu/> + <psi xml:id="id2"> + <nu abort="_blank"/> + <iota delete="another attribute value" xml:id="id3"/> + <phi xml:lang="nb"/> + <xi false="another attribute value" xml:lang="no"> + <upsilon src="attribute-value" xml:lang="en-US"> + <eta true="solid 1px green"> + <epsilon xml:lang="en-GB"> + <alpha false="this-is-att-value" xml:id="id4"> + <any string="_blank"/> + <sigma insert="true" xml:lang="nb"/> + <rho> + <nu xml:lang="nb"> + <delta attrib="true" xml:id="id5"/> + <phi xml:lang="en-US" xml:id="id6"> + <nu src="attribute-value" xml:lang="en-GB"/> + <gamma> + <delta xml:lang="en"/> + <xi xml:lang="en-GB" xml:id="id7"> + <omicron attribute="attribute-value" xml:lang="no-nb"> + <green>This text must be green</green> + </omicron> + </xi> + </gamma> + </phi> + </nu> + </rho> + </alpha> + </epsilon> + </eta> + </upsilon> + </xi> + </psi> + </upsilon> + </tree> + </test> + <test> + <xpath>//tau[@insert][@xml:id="id1"]/delta[@xml:lang="no"][not(preceding-sibling::*)][not(child::node())][following-sibling::tau[starts-with(@token,"_bla")][@xml:id="id2"][not(following-sibling::*)]//kappa[@xml:lang="no"][not(preceding-sibling::*)]//gamma[following-sibling::*[position()=2]][not(preceding-sibling::gamma)][not(child::node())][following-sibling::chi[@delete][@xml:id="id3"][preceding-sibling::*[position() = 1]][following-sibling::chi[@delete][@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/pi[@xml:lang="en-US"][@xml:id="id5"][not(following-sibling::*)]//xi[@data][not(preceding-sibling::*)]/lambda[@att][@xml:lang="no"][@xml:id="id6"][not(following-sibling::*)]/theta[@object][@xml:lang="en-GB"]//sigma[starts-with(concat(@string,"-"),"another attribute value-")][not(following-sibling::*)]/upsilon[@xml:id="id7"][not(following-sibling::*)][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <tau insert="this-is-att-value" xml:id="id1"> + <delta xml:lang="no"/> + <tau token="_blank" xml:id="id2"> + <kappa xml:lang="no"> + <gamma/> + <chi delete="true" xml:id="id3"/> + <chi delete="attribute value" xml:id="id4"> + <pi xml:lang="en-US" xml:id="id5"> + <xi data="123456789"> + <lambda att="another attribute value" xml:lang="no" xml:id="id6"> + <theta object="this.nodeValue" xml:lang="en-GB"> + <sigma string="another attribute value"> + <upsilon xml:id="id7"> + <green>This text must be green</green> + </upsilon> + </sigma> + </theta> + </lambda> + </xi> + </pi> + </chi> + </kappa> + </tau> + </tau> + </tree> + </test> + <test> + <xpath>//iota[@xml:id="id1"]//nu[contains(@abort,"v")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)]/delta[@xml:lang="no-nb"]//epsilon[@src="123456789"][@xml:lang="en-GB"][@xml:id="id3"]//iota[@xml:lang="en-US"][@xml:id="id4"]/pi[starts-with(@abort,"fa")][@xml:lang="no-nb"]/upsilon</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <iota xml:id="id1"> + <nu abort="attribute-value" xml:lang="no-nb" xml:id="id2"> + <delta xml:lang="no-nb"> + <epsilon src="123456789" xml:lang="en-GB" xml:id="id3"> + <iota xml:lang="en-US" xml:id="id4"> + <pi abort="false" xml:lang="no-nb"> + <upsilon> + <green>This text must be green</green> + </upsilon> + </pi> + </iota> + </epsilon> + </delta> + </nu> + </iota> + </tree> + </test> + <test> + <xpath>//sigma[@xml:lang="en-US"]/epsilon[@src][@xml:lang="en-GB"][@xml:id="id1"][not(preceding-sibling::*)][not(following-sibling::*)]/psi[@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//upsilon[@desciption][@xml:id="id3"][not(preceding-sibling::*)]//gamma[@xml:lang="no"][following-sibling::pi[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::beta[@xml:lang="no-nb"][@xml:id="id4"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=3]][not(child::node())][following-sibling::sigma[contains(concat(@name,"$"),"3456789$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 3]][following-sibling::mu[starts-with(@attribute,"attribute v")][@xml:lang="en"][@xml:id="id5"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::theta[@xml:id="id6"][not(following-sibling::*)]/alpha[@number][@xml:id="id7"][following-sibling::*[position()=1]][following-sibling::rho[@xml:lang="no"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/psi[@xml:id="id8"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@xml:lang="en"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@xml:id="id9"][not(following-sibling::*)]/phi[@xml:lang="nb"]/phi[@xml:lang="en"][not(following-sibling::*)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <sigma xml:lang="en-US"> + <epsilon src="false" xml:lang="en-GB" xml:id="id1"> + <psi xml:id="id2"> + <upsilon desciption="content" xml:id="id3"> + <gamma xml:lang="no"/> + <pi/> + <beta xml:lang="no-nb" xml:id="id4"/> + <sigma name="123456789" xml:lang="no-nb"/> + <mu attribute="attribute value" xml:lang="en" xml:id="id5"/> + <theta xml:id="id6"> + <alpha number="attribute value" xml:id="id7"/> + <rho xml:lang="no"> + <psi xml:id="id8"> + <xi xml:lang="en"> + <epsilon xml:id="id9"> + <phi xml:lang="nb"> + <phi xml:lang="en"> + <green>This text must be green</green> + </phi> + </phi> + </epsilon> + </xi> + </psi> + </rho> + </theta> + </upsilon> + </psi> + </epsilon> + </sigma> + </tree> + </test> + <test> + <xpath>//beta[starts-with(concat(@class,"-"),"100%-")][@xml:lang="en-GB"][@xml:id="id1"]/alpha[@xml:id="id2"][not(preceding-sibling::*)]/gamma[contains(@attrib,"t")][following-sibling::*[position()=1]][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]//*[@xml:id="id3"]/nu[@xml:id="id4"][following-sibling::*[position()=5]][following-sibling::rho[@content][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@xml:lang="nb"][following-sibling::*[position()=3]][not(child::node())][following-sibling::iota[starts-with(@desciption,"fal")][@xml:id="id6"][preceding-sibling::*[position() = 3]][following-sibling::tau[@attribute][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::kappa[starts-with(@or,"anothe")][@xml:lang="no"][preceding-sibling::*[position() = 5]]//chi[contains(@attr,"0")][@xml:lang="en-US"]/eta[starts-with(concat(@attr,"-"),"this.nodeValue-")][not(preceding-sibling::*)][not(following-sibling::*)]/zeta[not(following-sibling::*)]/gamma[@xml:lang="no-nb"][@xml:id="id7"][following-sibling::upsilon[preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/iota[starts-with(@insert,"attr")][@xml:lang="nb"][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@xml:lang="no"][@xml:id="id10"][following-sibling::psi[@xml:lang="no"][@xml:id="id11"][preceding-sibling::*[position() = 1]]//nu[@abort][@xml:id="id12"][not(preceding-sibling::*)][not(child::node())][following-sibling::rho[@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::pi[@src][@xml:lang="nb"][position() = 1]][position() = 1]]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <beta class="100%" xml:lang="en-GB" xml:id="id1"> + <alpha xml:id="id2"> + <gamma attrib="content"/> + <xi xml:lang="en-GB"> + <any xml:id="id3"> + <nu xml:id="id4"/> + <rho content="_blank" xml:id="id5"/> + <pi xml:lang="nb"/> + <iota desciption="false" xml:id="id6"/> + <tau attribute="attribute value"/> + <kappa or="another attribute value" xml:lang="no"> + <chi attr="100%" xml:lang="en-US"> + <eta attr="this.nodeValue"> + <zeta> + <gamma xml:lang="no-nb" xml:id="id7"/> + <upsilon/> + <tau xml:lang="en-GB" xml:id="id8"> + <iota insert="attribute value" xml:lang="nb" xml:id="id9"> + <mu xml:lang="no" xml:id="id10"/> + <psi xml:lang="no" xml:id="id11"> + <nu abort="attribute-value" xml:id="id12"/> + <rho xml:lang="no-nb"/> + <pi src="_blank" xml:lang="nb"> + <green>This text must be green</green> + </pi> + </psi> + </iota> + </tau> + </zeta> + </eta> + </chi> + </kappa> + </any> + </xi> + </alpha> + </beta> + </tree> + </test> + <test> + <xpath>//zeta[@attribute][@xml:lang="en-GB"][@xml:id="id1"]/lambda[@token][@xml:lang="no-nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::*[@xml:lang="no-nb"][not(child::node())][following-sibling::delta[contains(concat(@class,"$"),"56789$")][@xml:lang="en-GB"]//zeta[@xml:lang="en-US"][@xml:id="id2"][following-sibling::eta[not(child::node())][following-sibling::lambda[starts-with(concat(@data,"-"),"solid 1px green-")][@xml:lang="no-nb"][preceding-sibling::*[position() = 2]][following-sibling::omicron[starts-with(concat(@desciption,"-"),"123456789-")][following-sibling::omicron[@false][@xml:id="id3"][not(child::node())][following-sibling::omega[@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::zeta[@xml:lang="en-GB"][@xml:id="id5"][not(child::node())][following-sibling::zeta[@xml:lang="no-nb"]/omega[@xml:lang="no-nb"][not(child::node())][following-sibling::chi[not(following-sibling::*)]]][position() = 1]]][position() = 1]]]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>lambda</localname> + <nth>0</nth> + </result> + <tree> + <zeta attribute="100%" xml:lang="en-GB" xml:id="id1"> + <lambda token="attribute value" xml:lang="no-nb"/> + <any xml:lang="no-nb"/> + <delta class="123456789" xml:lang="en-GB"> + <zeta xml:lang="en-US" xml:id="id2"/> + <eta/> + <lambda data="solid 1px green" xml:lang="no-nb"/> + <omicron desciption="123456789"/> + <omicron false="solid 1px green" xml:id="id3"/> + <omega xml:id="id4"/> + <zeta xml:lang="en-GB" xml:id="id5"/> + <zeta xml:lang="no-nb"> + <omega xml:lang="no-nb"/> + <chi> + <green>This text must be green</green> + </chi> + </zeta> + </delta> + </zeta> + </tree> + </test> + <test> + <xpath>//theta[@xml:lang="nb"][@xml:id="id1"]/zeta[@xml:lang="no-nb"][@xml:id="id2"]/beta[@object][not(following-sibling::beta)]//phi[@desciption][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//kappa[@xml:lang="en-US"][@xml:id="id4"][not(preceding-sibling::*)][not(child::node())][following-sibling::delta[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::mu[@xml:lang="en"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]/upsilon[@xml:lang="no-nb"][@xml:id="id6"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::sigma[contains(concat(@token,"$"),"olid 1px green$")][@xml:id="id7"]//omega[@content="this.nodeValue"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[starts-with(@insert,"fa")][@xml:lang="no"][following-sibling::pi[contains(@src,"nk")][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <theta xml:lang="nb" xml:id="id1"> + <zeta xml:lang="no-nb" xml:id="id2"> + <beta object="123456789"> + <phi desciption="attribute" xml:lang="no-nb" xml:id="id3"> + <kappa xml:lang="en-US" xml:id="id4"/> + <delta xml:id="id5"/> + <mu xml:lang="en"> + <upsilon xml:lang="no-nb" xml:id="id6"/> + <sigma token="solid 1px green" xml:id="id7"> + <omega content="this.nodeValue"> + <omega insert="false" xml:lang="no"/> + <pi src="_blank"> + <green>This text must be green</green> + </pi> + </omega> + </sigma> + </mu> + </phi> + </beta> + </zeta> + </theta> + </tree> + </test> + <test> + <xpath>//omega//kappa[not(preceding-sibling::*)][not(child::node())][following-sibling::iota[@xml:id="id1"][not(child::node())][following-sibling::upsilon[@xml:lang="en-GB"][not(following-sibling::*)]/zeta[@xml:lang="en-GB"][@xml:id="id2"][not(child::node())][following-sibling::phi[starts-with(@name,"12345")][@xml:lang="no-nb"][@xml:id="id3"][not(following-sibling::*)]//xi[@xml:lang="en-GB"][@xml:id="id4"][not(child::node())][following-sibling::lambda[@xml:id="id5"]//kappa[contains(concat(@abort,"$"),"e$")][@xml:lang="no-nb"][not(preceding-sibling::kappa)][following-sibling::xi[@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/delta[@xml:id="id7"][following-sibling::lambda[@attrib][@xml:id="id8"][preceding-sibling::*[position() = 1]]//psi[@xml:id="id9"]//tau[starts-with(@delete,"1234")][@xml:lang="en"][@xml:id="id10"][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="no-nb"][@xml:id="id11"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//kappa[@src][not(preceding-sibling::*)]//rho[@xml:id="id12"][not(preceding-sibling::*)]]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <kappa/> + <iota xml:id="id1"/> + <upsilon xml:lang="en-GB"> + <zeta xml:lang="en-GB" xml:id="id2"/> + <phi name="123456789" xml:lang="no-nb" xml:id="id3"> + <xi xml:lang="en-GB" xml:id="id4"/> + <lambda xml:id="id5"> + <kappa abort="attribute" xml:lang="no-nb"/> + <xi xml:id="id6"> + <delta xml:id="id7"/> + <lambda attrib="attribute value" xml:id="id8"> + <psi xml:id="id9"> + <tau delete="123456789" xml:lang="en" xml:id="id10"/> + <xi xml:lang="no-nb" xml:id="id11"> + <kappa src="another attribute value"> + <rho xml:id="id12"> + <green>This text must be green</green> + </rho> + </kappa> + </xi> + </psi> + </lambda> + </xi> + </lambda> + </phi> + </upsilon> + </omega> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="nb"]//zeta[@object="content"][@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::tau[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/rho[@xml:id="id2"][not(preceding-sibling::*)]/omicron[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::lambda[not(following-sibling::*)]/eta[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="no"][@xml:id="id4"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::rho[@xml:lang="en-US"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>zeta</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="nb"> + <zeta object="content" xml:id="id1"/> + <tau> + <rho xml:id="id2"> + <omicron xml:lang="en-US" xml:id="id3"/> + <lambda> + <eta token="attribute" xml:lang="no" xml:id="id4"/> + <rho xml:lang="en-US"> + <green>This text must be green</green> + </rho> + </lambda> + </rho> + </tau> + </epsilon> + </tree> + </test> + <test> + <xpath>//*[@xml:id="id1"]//xi[starts-with(concat(@insert,"-"),"content-")][@xml:lang="en"][not(preceding-sibling::*)]/iota[contains(concat(@true,"$"),"blank$")][@xml:id="id2"][not(child::node())][following-sibling::mu[@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::mu)]//sigma[@xml:lang="en-US"][@xml:id="id4"][not(following-sibling::*)]/epsilon[@xml:lang="no-nb"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::pi[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <any xml:id="id1"> + <xi insert="content" xml:lang="en"> + <iota true="_blank" xml:id="id2"/> + <mu xml:lang="en-US" xml:id="id3"> + <sigma xml:lang="en-US" xml:id="id4"> + <epsilon xml:lang="no-nb" xml:id="id5"/> + <pi xml:lang="en-US" xml:id="id6"> + <green>This text must be green</green> + </pi> + </sigma> + </mu> + </xi> + </any> + </tree> + </test> + <test> + <xpath>//kappa[@xml:lang="en-US"]//lambda[contains(@att,"k")][@xml:lang="en-US"][not(preceding-sibling::*)]//gamma[not(preceding-sibling::*)][not(child::node())][following-sibling::theta[contains(@class,"ue")][@xml:lang="en-US"][@xml:id="id1"][not(following-sibling::*)]//iota[contains(@data,"00%")][@xml:id="id2"][not(preceding-sibling::*)][not(following-sibling::*)]//omega[contains(@src,"nk")][@xml:id="id3"]/beta[@attribute="solid 1px green"][not(following-sibling::*)]//phi[@desciption][@xml:id="id4"][not(preceding-sibling::*)][not(following-sibling::*)]//psi[@xml:lang="nb"][not(preceding-sibling::*)][not(child::node())][following-sibling::sigma[contains(concat(@false,"$"),"te-value$")][@xml:lang="en-US"][following-sibling::theta[@att][not(following-sibling::*)]//iota[contains(concat(@false,"$"),"e$")][@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>gamma</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:lang="en-US"> + <lambda att="_blank" xml:lang="en-US"> + <gamma/> + <theta class="true" xml:lang="en-US" xml:id="id1"> + <iota data="100%" xml:id="id2"> + <omega src="_blank" xml:id="id3"> + <beta attribute="solid 1px green"> + <phi desciption="attribute" xml:id="id4"> + <psi xml:lang="nb"/> + <sigma false="attribute-value" xml:lang="en-US"/> + <theta att="this.nodeValue"> + <iota false="true" xml:lang="nb" xml:id="id5"> + <green>This text must be green</green> + </iota> + </theta> + </phi> + </beta> + </omega> + </iota> + </theta> + </lambda> + </kappa> + </tree> + </test> + <test> + <xpath>//xi[contains(concat(@att,"$"),"rue$")][@xml:lang="en-US"][@xml:id="id1"]//omega[@xml:id="id2"][not(preceding-sibling::*)][following-sibling::lambda[@and][preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][not(child::node())][following-sibling::sigma[@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::phi[starts-with(concat(@attr,"-"),"attribute-")][@xml:id="id4"][following-sibling::*[position()=3]][not(child::node())][following-sibling::nu[@xml:lang="en"][following-sibling::*[position()=2]][following-sibling::zeta[@desciption="attribute value"][@xml:id="id5"][not(child::node())][following-sibling::zeta[@token][@xml:lang="no-nb"][@xml:id="id6"][not(following-sibling::*)]//mu[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][following-sibling::tau[@xml:lang="en-GB"][@xml:id="id8"][following-sibling::*[position()=1]][following-sibling::omega[@xml:lang="nb"][@xml:id="id9"][preceding-sibling::*[position() = 2]]//xi[contains(@or,"true")][@xml:id="id10"][following-sibling::*[position()=1]][following-sibling::upsilon[@att][@xml:lang="no"][@xml:id="id11"][not(following-sibling::*)][position() = 1]][position() = 1]][position() = 1]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <xi att="true" xml:lang="en-US" xml:id="id1"> + <omega xml:id="id2"/> + <lambda and="another attribute value"/> + <sigma xml:id="id3"/> + <phi attr="attribute-value" xml:id="id4"/> + <nu xml:lang="en"/> + <zeta desciption="attribute value" xml:id="id5"/> + <zeta token="_blank" xml:lang="no-nb" xml:id="id6"> + <mu xml:lang="en-GB" xml:id="id7"/> + <tau xml:lang="en-GB" xml:id="id8"/> + <omega xml:lang="nb" xml:id="id9"> + <xi or="true" xml:id="id10"/> + <upsilon att="attribute" xml:lang="no" xml:id="id11"> + <green>This text must be green</green> + </upsilon> + </omega> + </zeta> + </xi> + </tree> + </test> + <test> + <xpath>//omega[@xml:id="id1"]//pi[contains(concat(@true,"$"),"ribute value$")][@xml:id="id2"][following-sibling::*[position()=2]][following-sibling::nu[@xml:lang="en-US"][@xml:id="id3"][not(child::node())][following-sibling::omicron[starts-with(@true,"attribute")][@xml:lang="en-GB"][not(following-sibling::*)]//psi[contains(@title,"e")][@xml:lang="en"][@xml:id="id4"][not(child::node())][following-sibling::lambda[@attribute][@xml:id="id5"][preceding-sibling::*[position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>pi</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:id="id1"> + <pi true="attribute value" xml:id="id2"/> + <nu xml:lang="en-US" xml:id="id3"/> + <omicron true="attribute value" xml:lang="en-GB"> + <psi title="true" xml:lang="en" xml:id="id4"/> + <lambda attribute="this-is-att-value" xml:id="id5"> + <green>This text must be green</green> + </lambda> + </omicron> + </omega> + </tree> + </test> + <test> + <xpath>//kappa[@xml:id="id1"]//beta[@attribute][@xml:lang="en"][@xml:id="id2"][not(preceding-sibling::*)]//mu[starts-with(concat(@desciption,"-"),"true-")][not(preceding-sibling::*)][not(following-sibling::*)]/alpha[starts-with(concat(@insert,"-"),"true-")][@xml:lang="no"][@xml:id="id3"][following-sibling::upsilon[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]/zeta[@data="_blank"][@xml:lang="no-nb"][@xml:id="id5"]/psi[contains(concat(@attribute,"$"),"bute$")][@xml:lang="en-US"][@xml:id="id6"][following-sibling::omega[not(following-sibling::*)]//*[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::iota/zeta[@number="true"][@xml:lang="no"][@xml:id="id8"][not(following-sibling::*)]/xi[@xml:lang="no-nb"][@xml:id="id9"][not(child::node())][following-sibling::eta[@token][@xml:lang="en-US"][@xml:id="id10"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][position() = 1]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <kappa xml:id="id1"> + <beta attribute="attribute value" xml:lang="en" xml:id="id2"> + <mu desciption="true"> + <alpha insert="true" xml:lang="no" xml:id="id3"/> + <upsilon xml:id="id4"> + <zeta data="_blank" xml:lang="no-nb" xml:id="id5"> + <psi attribute="attribute" xml:lang="en-US" xml:id="id6"/> + <omega> + <any xml:id="id7"/> + <iota> + <zeta number="true" xml:lang="no" xml:id="id8"> + <xi xml:lang="no-nb" xml:id="id9"/> + <eta token="another attribute value" xml:lang="en-US" xml:id="id10"> + <green>This text must be green</green> + </eta> + </zeta> + </iota> + </omega> + </zeta> + </upsilon> + </mu> + </beta> + </kappa> + </tree> + </test> + <test> + <xpath>//nu[@xml:id="id1"]//tau[@class][@xml:lang="en"][not(preceding-sibling::*)]//alpha[following-sibling::alpha[contains(concat(@true,"$"),"tribute value$")][@xml:id="id2"][not(child::node())][following-sibling::alpha[@insert][preceding-sibling::*[position() = 2]][following-sibling::mu[not(following-sibling::*)]/*[starts-with(concat(@title,"-"),"true-")][@xml:lang="en"][not(following-sibling::*)]/theta[starts-with(concat(@object,"-"),"attribute-")][not(preceding-sibling::*)]/psi[not(child::node())][following-sibling::xi[@false][@xml:lang="en"][@xml:id="id3"][preceding-sibling::*[position() = 1]]//zeta[@or][@xml:lang="en-US"]//tau[@and="true"][not(following-sibling::*)]/gamma[starts-with(@token,"f")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::sigma[contains(@false,"9")][following-sibling::kappa[@xml:lang="nb"][not(following-sibling::*)]/eta[@xml:lang="no"][@xml:id="id4"]/delta[@xml:lang="no"][@xml:id="id5"][not(preceding-sibling::*)]//tau[contains(@insert,"bute value")][@xml:lang="en-GB"][not(following-sibling::*)]/eta[@content][@xml:lang="en"][@xml:id="id6"]][position() = 1]][position() = 1]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>alpha</localname> + <nth>0</nth> + </result> + <tree> + <nu xml:id="id1"> + <tau class="attribute-value" xml:lang="en"> + <alpha/> + <alpha true="attribute value" xml:id="id2"/> + <alpha insert="100%"/> + <mu> + <any title="true" xml:lang="en"> + <theta object="attribute"> + <psi/> + <xi false="solid 1px green" xml:lang="en" xml:id="id3"> + <zeta or="this-is-att-value" xml:lang="en-US"> + <tau and="true"> + <gamma token="false" xml:lang="en-US"/> + <sigma false="123456789"/> + <kappa xml:lang="nb"> + <eta xml:lang="no" xml:id="id4"> + <delta xml:lang="no" xml:id="id5"> + <tau insert="another attribute value" xml:lang="en-GB"> + <eta content="this.nodeValue" xml:lang="en" xml:id="id6"> + <green>This text must be green</green> + </eta> + </tau> + </delta> + </eta> + </kappa> + </tau> + </zeta> + </xi> + </theta> + </any> + </mu> + </tau> + </nu> + </tree> + </test> + <test> + <xpath>//kappa/kappa[not(preceding-sibling::*)]//iota[contains(@src,"od")][@xml:id="id1"][not(preceding-sibling::*)]//omicron[@false][@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)]/omega[@src="attribute value"][@xml:id="id3"][not(preceding-sibling::*)][not(following-sibling::*)]//beta[@content="this-is-att-value"][@xml:lang="en"][@xml:id="id4"][not(preceding-sibling::*)]/beta[contains(concat(@attrib,"$"),"e$")][@xml:lang="nb"][not(following-sibling::*)]//nu[not(following-sibling::*)]/alpha[@xml:lang="nb"][@xml:id="id5"][not(following-sibling::*)]/*[@att][@xml:id="id6"][not(preceding-sibling::*)]//delta[@xml:lang="en-GB"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]//xi[@object][@xml:lang="en-US"][not(preceding-sibling::*)][not(child::node())][following-sibling::psi[@name="solid 1px green"][@xml:lang="nb"]//chi[@xml:id="id8"][not(following-sibling::*)]//delta[@xml:lang="en"][@xml:id="id9"][following-sibling::gamma[contains(concat(@att,"$"),"attribute$")][@xml:lang="no-nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//alpha[contains(concat(@insert,"$"),"nk$")][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <kappa> + <kappa> + <iota src="this.nodeValue" xml:id="id1"> + <omicron false="content" xml:lang="en-US" xml:id="id2"> + <omega src="attribute value" xml:id="id3"> + <beta content="this-is-att-value" xml:lang="en" xml:id="id4"> + <beta attrib="true" xml:lang="nb"> + <nu> + <alpha xml:lang="nb" xml:id="id5"> + <any att="false" xml:id="id6"> + <delta xml:lang="en-GB" xml:id="id7"> + <xi object="attribute" xml:lang="en-US"/> + <psi name="solid 1px green" xml:lang="nb"> + <chi xml:id="id8"> + <delta xml:lang="en" xml:id="id9"/> + <gamma att="attribute" xml:lang="no-nb"> + <alpha insert="_blank"> + <green>This text must be green</green> + </alpha> + </gamma> + </chi> + </psi> + </delta> + </any> + </alpha> + </nu> + </beta> + </beta> + </omega> + </omicron> + </iota> + </kappa> + </kappa> + </tree> + </test> + <test> + <xpath>//epsilon[@xml:lang="no"][@xml:id="id1"]/*[contains(concat(@attrib,"$"),"rue$")][not(following-sibling::*)]//psi//xi[@xml:lang="no"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=1]][following-sibling::zeta[@insert="attribute"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//eta[@xml:id="id4"][not(preceding-sibling::*)][following-sibling::pi[@xml:lang="en"]/*[starts-with(@attrib,"this.nodeValue")][@xml:lang="en-GB"][@xml:id="id5"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <epsilon xml:lang="no" xml:id="id1"> + <any attrib="true"> + <psi> + <xi xml:lang="no" xml:id="id2"/> + <zeta insert="attribute" xml:id="id3"> + <eta xml:id="id4"/> + <pi xml:lang="en"> + <any attrib="this.nodeValue" xml:lang="en-GB" xml:id="id5"> + <green>This text must be green</green> + </any> + </pi> + </zeta> + </psi> + </any> + </epsilon> + </tree> + </test> + <test> + <xpath>//omicron[contains(concat(@content,"$"),"tribute value$")][@xml:id="id1"]/lambda[@xml:id="id2"][not(preceding-sibling::*)]/mu[@xml:lang="nb"][not(following-sibling::*)]//theta[@xml:lang="nb"][not(preceding-sibling::*)][not(following-sibling::*)]//kappa[@delete][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::kappa[@xml:id="id4"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <omicron content="another attribute value" xml:id="id1"> + <lambda xml:id="id2"> + <mu xml:lang="nb"> + <theta xml:lang="nb"> + <kappa delete="this-is-att-value" xml:id="id3"/> + <kappa xml:id="id4"> + <green>This text must be green</green> + </kappa> + </theta> + </mu> + </lambda> + </omicron> + </tree> + </test> + <test> + <xpath>//zeta[@desciption][@xml:lang="no-nb"][@xml:id="id1"]/tau[@xml:lang="en-US"][@xml:id="id2"][not(preceding-sibling::*)][not(child::node())][following-sibling::eta[@xml:lang="no"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::tau[contains(@data,"lank")]//upsilon[@xml:id="id4"][not(following-sibling::*)]/omega[@xml:lang="en"][@xml:id="id5"][not(preceding-sibling::*)][following-sibling::alpha[@xml:lang="en-US"][@xml:id="id6"][following-sibling::*[position()=2]][following-sibling::phi[@xml:id="id7"][preceding-sibling::*[position() = 2]][following-sibling::*[position()=1]][following-sibling::omega[contains(concat(@title,"$"),"3456789$")][@xml:lang="no"][@xml:id="id8"][preceding-sibling::*[position() = 3]][not(following-sibling::*)]/alpha[@xml:id="id9"][not(following-sibling::*)]/psi[@delete="this-is-att-value"][@xml:lang="no"][not(preceding-sibling::*)]//chi[@attrib="123456789"][not(child::node())][following-sibling::epsilon[@xml:lang="no-nb"][@xml:id="id10"][preceding-sibling::*[position() = 1]]//omicron[contains(@attr,"e")][not(preceding-sibling::*)][not(following-sibling::*)]//chi[contains(@token,"89")]/psi[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::delta[@xml:lang="en-GB"][@xml:id="id11"]//alpha[@attr]/epsilon[@attr][@xml:id="id12"][not(following-sibling::*)]//omega[starts-with(concat(@content,"-"),"123456789-")][@xml:id="id13"][following-sibling::*[position()=2]][following-sibling::gamma[@xml:lang="no"][not(child::node())][following-sibling::iota[@xml:lang="no-nb"][not(following-sibling::*)]/xi[@att="_blank"][@xml:lang="en-GB"][@xml:id="id14"][not(preceding-sibling::*)]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>tau</localname> + <nth>0</nth> + </result> + <tree> + <zeta desciption="solid 1px green" xml:lang="no-nb" xml:id="id1"> + <tau xml:lang="en-US" xml:id="id2"/> + <eta xml:lang="no" xml:id="id3"/> + <tau data="_blank"> + <upsilon xml:id="id4"> + <omega xml:lang="en" xml:id="id5"/> + <alpha xml:lang="en-US" xml:id="id6"/> + <phi xml:id="id7"/> + <omega title="123456789" xml:lang="no" xml:id="id8"> + <alpha xml:id="id9"> + <psi delete="this-is-att-value" xml:lang="no"> + <chi attrib="123456789"/> + <epsilon xml:lang="no-nb" xml:id="id10"> + <omicron attr="false"> + <chi token="123456789"> + <psi xml:lang="en-GB"/> + <delta xml:lang="en-GB" xml:id="id11"> + <alpha attr="100%"> + <epsilon attr="true" xml:id="id12"> + <omega content="123456789" xml:id="id13"/> + <gamma xml:lang="no"/> + <iota xml:lang="no-nb"> + <xi att="_blank" xml:lang="en-GB" xml:id="id14"> + <green>This text must be green</green> + </xi> + </iota> + </epsilon> + </alpha> + </delta> + </chi> + </omicron> + </epsilon> + </psi> + </alpha> + </omega> + </upsilon> + </tau> + </zeta> + </tree> + </test> + <test> + <xpath>//mu[@abort]/eta[@xml:id="id1"][not(preceding-sibling::*)][following-sibling::*[position()=2]][following-sibling::omega[@data][following-sibling::*[position()=1]][not(child::node())][following-sibling::*[@xml:id="id2"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//tau[@class="attribute-value"][@xml:lang="en-US"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::pi[@delete="123456789"][@xml:lang="nb"][@xml:id="id4"][preceding-sibling::*[position() = 1]]/tau[@xml:lang="en-US"][@xml:id="id5"]/delta[@xml:lang="nb"][@xml:id="id6"]/beta[@xml:lang="no"][@xml:id="id7"][not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[preceding-sibling::*[position() = 1]]/xi[@xml:id="id8"][not(preceding-sibling::*)]//xi[contains(concat(@abort,"$"),"solid 1px green$")][@xml:lang="no"][@xml:id="id9"][following-sibling::*[position()=4]][not(preceding-sibling::xi)][not(child::node())][following-sibling::psi[@insert][following-sibling::*[position()=3]][not(child::node())][following-sibling::nu[@string][not(child::node())][following-sibling::gamma[starts-with(concat(@number,"-"),"_blank-")][@xml:lang="en-US"][@xml:id="id10"][not(child::node())][following-sibling::phi[preceding-sibling::*[position() = 4]][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>eta</localname> + <nth>0</nth> + </result> + <tree> + <mu abort="_blank"> + <eta xml:id="id1"/> + <omega data="attribute value"/> + <any xml:id="id2"> + <tau class="attribute-value" xml:lang="en-US" xml:id="id3"/> + <pi delete="123456789" xml:lang="nb" xml:id="id4"> + <tau xml:lang="en-US" xml:id="id5"> + <delta xml:lang="nb" xml:id="id6"> + <beta xml:lang="no" xml:id="id7"/> + <alpha> + <xi xml:id="id8"> + <xi abort="solid 1px green" xml:lang="no" xml:id="id9"/> + <psi insert="123456789"/> + <nu string="100%"/> + <gamma number="_blank" xml:lang="en-US" xml:id="id10"/> + <phi> + <green>This text must be green</green> + </phi> + </xi> + </alpha> + </delta> + </tau> + </pi> + </any> + </mu> + </tree> + </test> + <test> + <xpath>//omega/xi[@attrib][@xml:lang="nb"][@xml:id="id1"][not(following-sibling::*)]/mu[not(preceding-sibling::*)][not(following-sibling::*)]//pi[starts-with(@attr,"_b")][@xml:id="id2"][not(following-sibling::*)]/upsilon[starts-with(concat(@attr,"-"),"attribute-")][@xml:lang="en-US"][not(preceding-sibling::*)][following-sibling::tau[@false="content"][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//phi[@xml:lang="en"][@xml:id="id4"][following-sibling::*[position()=1]][following-sibling::mu[@xml:id="id5"][preceding-sibling::*[position() = 1]]//sigma[@xml:lang="no"][@xml:id="id6"]//pi[@token][@xml:id="id7"][following-sibling::iota[starts-with(concat(@attrib,"-"),"false-")][@xml:lang="en"][@xml:id="id8"][following-sibling::zeta/kappa[@name][@xml:lang="nb"][not(child::node())][following-sibling::mu[@title][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)][not(following-sibling::mu)]]]][position() = 1]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <omega> + <xi attrib="solid 1px green" xml:lang="nb" xml:id="id1"> + <mu> + <pi attr="_blank" xml:id="id2"> + <upsilon attr="attribute-value" xml:lang="en-US"/> + <tau false="content" xml:id="id3"> + <phi xml:lang="en" xml:id="id4"/> + <mu xml:id="id5"> + <sigma xml:lang="no" xml:id="id6"> + <pi token="true" xml:id="id7"/> + <iota attrib="false" xml:lang="en" xml:id="id8"/> + <zeta> + <kappa name="true" xml:lang="nb"/> + <mu title="this.nodeValue" xml:id="id9"> + <green>This text must be green</green> + </mu> + </zeta> + </sigma> + </mu> + </tau> + </pi> + </mu> + </xi> + </omega> + </tree> + </test> + <test> + <xpath>//alpha[@xml:lang="en-US"][@xml:id="id1"]/delta[contains(@abort,"lue")][@xml:lang="no-nb"][following-sibling::*[position()=4]][not(child::node())][following-sibling::sigma[@abort][@xml:lang="en-GB"][not(child::node())][following-sibling::epsilon[following-sibling::*[position()=2]][following-sibling::eta[@xml:lang="en-GB"][following-sibling::*[position()=1]][following-sibling::rho[@xml:id="id2"]//eta[@xml:lang="nb"][@xml:id="id3"][not(preceding-sibling::*)][not(child::node())][following-sibling::beta[@xml:lang="nb"][preceding-sibling::*[position() = 1]]/tau[contains(concat(@desciption,"$"),"e$")][@xml:lang="no-nb"][@xml:id="id4"][following-sibling::*[position()=1]][not(child::node())][following-sibling::sigma[preceding-sibling::*[position() = 1]][not(following-sibling::*)]/chi[@abort][@xml:lang="en-US"]/*[following-sibling::chi[@content][@xml:id="id5"][preceding-sibling::*[position() = 1]][following-sibling::theta[@xml:id="id6"][preceding-sibling::*[position() = 2]][not(following-sibling::*)][not(preceding-sibling::theta or following-sibling::theta)]/omicron[@name][@xml:lang="en"][@xml:id="id7"][not(preceding-sibling::*)][not(following-sibling::*)]/nu[contains(@delete,"ribute value")][@xml:lang="en"]/sigma[@xml:lang="en-GB"]/alpha[not(preceding-sibling::*)][not(child::node())][following-sibling::alpha[following-sibling::*[position()=1]][following-sibling::beta[@xml:lang="en"][preceding-sibling::*[position() = 2]]//kappa[@attr][@xml:lang="en-GB"][@xml:id="id8"][not(preceding-sibling::*)][following-sibling::xi[starts-with(concat(@false,"-"),"true-")][@xml:lang="no-nb"][not(following-sibling::*)]/*[contains(concat(@class,"$"),"lse$")][@xml:id="id9"][not(following-sibling::*)][not(preceding-sibling::any)][position() = 1]]][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>delta</localname> + <nth>0</nth> + </result> + <tree> + <alpha xml:lang="en-US" xml:id="id1"> + <delta abort="this-is-att-value" xml:lang="no-nb"/> + <sigma abort="this-is-att-value" xml:lang="en-GB"/> + <epsilon/> + <eta xml:lang="en-GB"/> + <rho xml:id="id2"> + <eta xml:lang="nb" xml:id="id3"/> + <beta xml:lang="nb"> + <tau desciption="false" xml:lang="no-nb" xml:id="id4"/> + <sigma> + <chi abort="this.nodeValue" xml:lang="en-US"> + <any/> + <chi content="attribute" xml:id="id5"/> + <theta xml:id="id6"> + <omicron name="attribute" xml:lang="en" xml:id="id7"> + <nu delete="attribute value" xml:lang="en"> + <sigma xml:lang="en-GB"> + <alpha/> + <alpha/> + <beta xml:lang="en"> + <kappa attr="another attribute value" xml:lang="en-GB" xml:id="id8"/> + <xi false="true" xml:lang="no-nb"> + <any class="false" xml:id="id9"> + <green>This text must be green</green> + </any> + </xi> + </beta> + </sigma> + </nu> + </omicron> + </theta> + </chi> + </sigma> + </beta> + </rho> + </alpha> + </tree> + </test> + <test> + <xpath>//sigma/theta[contains(concat(@data,"$"),"is.nodeValue$")][@xml:lang="nb"]//omega[@xml:lang="no"][@xml:id="id1"][following-sibling::eta[@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::kappa[@xml:lang="en-US"][@xml:id="id3"][not(following-sibling::*)]/beta[not(child::node())][following-sibling::epsilon[@xml:id="id4"][following-sibling::delta[@false][@xml:lang="no"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//epsilon[@xml:lang="no-nb"][not(following-sibling::*)][not(parent::*/*[position()=2])]//phi[contains(@name,"lue")][not(following-sibling::*)]/alpha[@xml:lang="en-GB"][not(child::node())][following-sibling::beta[@xml:lang="no"][@xml:id="id5"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::sigma[starts-with(@abort,"attrib")][@xml:lang="en"][@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::rho[preceding-sibling::*[position() = 3]][not(following-sibling::*)]/phi[starts-with(@attribute,"100%")][@xml:lang="en-US"][@xml:id="id7"][not(child::node())][following-sibling::pi[starts-with(@title,"tr")][@xml:lang="nb"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//lambda[@content][not(following-sibling::*)]/gamma[@attrib="this-is-att-value"][@xml:lang="en-US"][@xml:id="id8"][following-sibling::kappa[@xml:lang="en-GB"][@xml:id="id9"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//beta[starts-with(@and,"this.nodeV")][@xml:id="id10"][not(following-sibling::*)]]][position() = 1]][position() = 1]][position() = 1]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>omega</localname> + <nth>0</nth> + </result> + <tree> + <sigma> + <theta data="this.nodeValue" xml:lang="nb"> + <omega xml:lang="no" xml:id="id1"/> + <eta xml:id="id2"/> + <kappa xml:lang="en-US" xml:id="id3"> + <beta/> + <epsilon xml:id="id4"/> + <delta false="123456789" xml:lang="no"> + <epsilon xml:lang="no-nb"> + <phi name="this-is-att-value"> + <alpha xml:lang="en-GB"/> + <beta xml:lang="no" xml:id="id5"/> + <sigma abort="attribute" xml:lang="en" xml:id="id6"/> + <rho> + <phi attribute="100%" xml:lang="en-US" xml:id="id7"/> + <pi title="true" xml:lang="nb"> + <lambda content="solid 1px green"> + <gamma attrib="this-is-att-value" xml:lang="en-US" xml:id="id8"/> + <kappa xml:lang="en-GB" xml:id="id9"> + <beta and="this.nodeValue" xml:id="id10"> + <green>This text must be green</green> + </beta> + </kappa> + </lambda> + </pi> + </rho> + </phi> + </epsilon> + </delta> + </kappa> + </theta> + </sigma> + </tree> + </test> + <test> + <xpath>//delta[@xml:lang="nb"]//iota[starts-with(concat(@object,"-"),"attribute value-")][@xml:lang="en"]/xi[@xml:id="id1"][not(child::node())][following-sibling::sigma[@false][@xml:lang="en-GB"][preceding-sibling::*[position() = 1]]/pi[not(preceding-sibling::*)]//kappa[contains(@name,"100")][@xml:lang="en"][@xml:id="id2"][following-sibling::*[position()=2]][not(child::node())][following-sibling::chi[@xml:lang="no"][@xml:id="id3"][following-sibling::*[position()=1]][following-sibling::eta[@xml:id="id4"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//alpha[@class="123456789"][not(preceding-sibling::*)][not(child::node())][following-sibling::xi[@xml:lang="en-GB"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::gamma[@xml:id="id5"][following-sibling::*[position()=1]][not(child::node())][following-sibling::rho[contains(concat(@string,"$"),"alse$")][@xml:id="id6"][preceding-sibling::*[position() = 3]]/lambda[contains(concat(@or,"$"),"k$")][not(preceding-sibling::*)][following-sibling::xi[@xml:lang="no-nb"]/psi[@xml:id="id7"][not(preceding-sibling::*)][following-sibling::*[position()=6]][not(preceding-sibling::psi)][not(child::node())][following-sibling::chi[preceding-sibling::*[position() = 1]][following-sibling::*[position()=5]][following-sibling::nu[contains(@token,"e")][@xml:lang="nb"][@xml:id="id8"][preceding-sibling::*[position() = 2]][following-sibling::theta[@xml:lang="nb"][@xml:id="id9"][following-sibling::*[position()=3]][following-sibling::mu[@xml:lang="no"][@xml:id="id10"][preceding-sibling::*[position() = 4]][not(child::node())][following-sibling::delta[contains(@src,"ribute")][@xml:lang="nb"][@xml:id="id11"][following-sibling::eta[@xml:lang="en-US"]/upsilon[@xml:id="id12"]//mu[not(preceding-sibling::*)][not(following-sibling::*)]]]]]]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>xi</localname> + <nth>0</nth> + </result> + <tree> + <delta xml:lang="nb"> + <iota object="attribute value" xml:lang="en"> + <xi xml:id="id1"/> + <sigma false="this-is-att-value" xml:lang="en-GB"> + <pi> + <kappa name="100%" xml:lang="en" xml:id="id2"/> + <chi xml:lang="no" xml:id="id3"/> + <eta xml:id="id4"> + <alpha class="123456789"/> + <xi xml:lang="en-GB"/> + <gamma xml:id="id5"/> + <rho string="false" xml:id="id6"> + <lambda or="_blank"/> + <xi xml:lang="no-nb"> + <psi xml:id="id7"/> + <chi/> + <nu token="another attribute value" xml:lang="nb" xml:id="id8"/> + <theta xml:lang="nb" xml:id="id9"/> + <mu xml:lang="no" xml:id="id10"/> + <delta src="attribute" xml:lang="nb" xml:id="id11"/> + <eta xml:lang="en-US"> + <upsilon xml:id="id12"> + <mu> + <green>This text must be green</green> + </mu> + </upsilon> + </eta> + </xi> + </rho> + </eta> + </pi> + </sigma> + </iota> + </delta> + </tree> + </test> + <test> + <xpath>//omega[@xml:id="id1"]/iota[starts-with(concat(@token,"-"),"attribute-")][@xml:lang="nb"][@xml:id="id2"][following-sibling::mu[@att][@xml:id="id3"][preceding-sibling::*[position() = 1]][not(following-sibling::*)]//upsilon[@number="123456789"][not(preceding-sibling::*)][not(following-sibling::*)]//rho[not(child::node())][following-sibling::xi[starts-with(concat(@title,"-"),"true-")][@xml:id="id4"][following-sibling::*[position()=4]][not(child::node())][following-sibling::gamma[@false="true"][@xml:lang="nb"][@xml:id="id5"][following-sibling::chi[@xml:lang="en-US"][@xml:id="id6"][preceding-sibling::*[position() = 3]][not(child::node())][following-sibling::theta[@title][preceding-sibling::*[position() = 4]][following-sibling::alpha[starts-with(@token,"10")][@xml:lang="nb"][@xml:id="id7"]/delta/rho[@src="true"]//gamma[@xml:id="id8"][not(preceding-sibling::*)]/beta[@xml:lang="en-GB"]/alpha[@att][@xml:id="id9"]/upsilon[contains(@and,"tru")][not(preceding-sibling::*)]//chi[@xml:id="id10"][not(preceding-sibling::*)][not(following-sibling::*)]//epsilon[@data="_blank"][not(preceding-sibling::*)][following-sibling::*[position()=1]][not(child::node())][following-sibling::xi[@xml:id="id11"][not(following-sibling::*)][not(preceding-sibling::xi)]//chi[@false="this-is-att-value"][@xml:id="id12"][position() = 1]][position() = 1]][position() = 1]]][position() = 1]]]]</xpath> + <result> + <namespace/> + <localname>iota</localname> + <nth>0</nth> + </result> + <tree> + <omega xml:id="id1"> + <iota token="attribute-value" xml:lang="nb" xml:id="id2"/> + <mu att="false" xml:id="id3"> + <upsilon number="123456789"> + <rho/> + <xi title="true" xml:id="id4"/> + <gamma false="true" xml:lang="nb" xml:id="id5"/> + <chi xml:lang="en-US" xml:id="id6"/> + <theta title="100%"/> + <alpha token="100%" xml:lang="nb" xml:id="id7"> + <delta> + <rho src="true"> + <gamma xml:id="id8"> + <beta xml:lang="en-GB"> + <alpha att="this.nodeValue" xml:id="id9"> + <upsilon and="true"> + <chi xml:id="id10"> + <epsilon data="_blank"/> + <xi xml:id="id11"> + <chi false="this-is-att-value" xml:id="id12"> + <green>This text must be green</green> + </chi> + </xi> + </chi> + </upsilon> + </alpha> + </beta> + </gamma> + </rho> + </delta> + </alpha> + </upsilon> + </mu> + </omega> + </tree> + </test> + <test> + <xpath>//omicron[@src="attribute value"][@xml:lang="en-US"]//kappa[@xml:lang="en-US"][@xml:id="id1"][following-sibling::*[position()=3]][not(child::node())][following-sibling::beta[@xml:lang="en-US"][@xml:id="id2"][preceding-sibling::*[position() = 1]][not(child::node())][following-sibling::omega[starts-with(@false,"attribute val")][@xml:lang="no"][@xml:id="id3"][preceding-sibling::*[position() = 2]][not(child::node())][following-sibling::beta/mu[@xml:lang="no-nb"][@xml:id="id4"][not(preceding-sibling::*)]//chi[starts-with(@string,"so")][not(child::node())][following-sibling::phi[@xml:lang="en-US"]/*[@xml:id="id5"][not(preceding-sibling::*)]/nu[@xml:id="id6"][following-sibling::*[position()=1]][following-sibling::lambda[@xml:lang="en-GB"]/xi[@xml:lang="en-GB"][not(preceding-sibling::*)][following-sibling::epsilon[@xml:id="id7"][following-sibling::*[position()=1]][not(child::node())][following-sibling::omega[contains(@attribute,"00%")][@xml:id="id8"][preceding-sibling::*[position() = 2]][not(following-sibling::*)]//nu[starts-with(@name,"a")][not(preceding-sibling::*)][not(following-sibling::*)]/mu[@false][@xml:id="id9"][not(preceding-sibling::*)][not(following-sibling::*)]][position() = 1]]]]]][position() = 1]]</xpath> + <result> + <namespace/> + <localname>kappa</localname> + <nth>0</nth> + </result> + <tree> + <omicron src="attribute value" xml:lang="en-US"> + <kappa xml:lang="en-US" xml:id="id1"/> + <beta xml:lang="en-US" xml:id="id2"/> + <omega false="attribute value" xml:lang="no" xml:id="id3"/> + <beta> + <mu xml:lang="no-nb" xml:id="id4"> + <chi string="solid 1px green"/> + <phi xml:lang="en-US"> + <any xml:id="id5"> + <nu xml:id="id6"/> + <lambda xml:lang="en-GB"> + <xi xml:lang="en-GB"/> + <epsilon xml:id="id7"/> + <omega attribute="100%" xml:id="id8"> + <nu name="attribute value"> + <mu false="attribute value" xml:id="id9"> + <green>This text must be green</green> + </mu> + </nu> + </omega> + </lambda> + </any> + </phi> + </mu> + </beta> + </omicron> + </tree> + </test> + <test> + <xpath>//pi[@xml:id="id1"]/upsilon[contains(concat(@insert,"$"),"23456789$")][@xml:lang="no-nb"][@xml:id="id2"][not(preceding-sibling::*)][following-sibling::*[position()=6]][following-sibling::lambda[contains(concat(@abort,"$"),"9$")][following-sibling::tau[@insert][following-sibling::omicron[@xml:lang="en-US"][following-sibling::lambda[@number="100%"][@xml:lang="en-US"][@xml:id="id3"][preceding-sibling::*[position() = 4]][not(following-sibling::lambda)][not(child::node())][following-sibling::chi[@xml:id="id4"][preceding-sibling::*[position() = 5]][following-sibling::*[position()=1]][not(child::node())][following-sibling::psi[@xml:id="id5"][not(following-sibling::*)]//mu[not(child::node())][following-sibling::epsilon[starts-with(concat(@attr,"-"),"attribute-")]][position() = 1]]][position() = 1]]][position() = 1]]]</xpath> + <result> + <namespace/> + <localname>upsilon</localname> + <nth>0</nth> + </result> + <tree> + <pi xml:id="id1"> + <upsilon insert="123456789" xml:lang="no-nb" xml:id="id2"/> + <lambda abort="123456789"/> + <tau insert="this.nodeValue"/> + <omicron xml:lang="en-US"/> + <lambda number="100%" xml:lang="en-US" xml:id="id3"/> + <chi xml:id="id4"/> + <psi xml:id="id5"> + <mu/> + <epsilon attr="attribute-value"> + <green>This text must be green</green> + </epsilon> + </psi> + </pi> + </tree> + </test> +</tests> diff --git a/testing/web-platform/tests/domxpath/xpath-evaluate-crash.html b/testing/web-platform/tests/domxpath/xpath-evaluate-crash.html new file mode 100644 index 0000000000..5303d85ad3 --- /dev/null +++ b/testing/web-platform/tests/domxpath/xpath-evaluate-crash.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Evaluating XPath expressions with orhpaned Attr as context node doesn't crash</title> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1236967"> +<script src="/resources/testharnessreport.js"></script> +<body> +<script> +for (const expression of [ + "..", + "parent", + "ancestor::*", + "ancestor-or-self::*", + "following::*", + "preceding::*", +]) { + const orphanedAttr = document.createAttribute("foo"); + new XPathEvaluator().evaluate(expression, orphanedAttr, null, 2); +} +</script> |