" +
+ "modify insert node into $data " +
+ "return let $w := $data/w let $x := $w/x let $y := $x/y let $z := $y/z " +
+ "return " +
+ " {namespace-uri-for-prefix('a', $w), namespace-uri-for-prefix('b',$w)} " +
+ " {namespace-uri-for-prefix('a', $x), namespace-uri-for-prefix('b',$x)} " +
+ " {namespace-uri-for-prefix('a', $y), namespace-uri-for-prefix('b',$y)} " +
+ " {namespace-uri-for-prefix('a', $z), namespace-uri-for-prefix('b',$z)} " +
+ "";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ System.err.println("propagateNS04 (no-preserve,no-inherit): " + xml);
+ // Expected: all empty
+ assertTrue("w should be empty", xml.contains(""));
+ assertTrue("x should be empty", xml.contains("") || xml.contains(""));
+ assertTrue("y should be empty", xml.contains("") || xml.contains(""));
+ assertTrue("z should be empty", xml.contains("") || xml.contains(""));
+ }
+
+ /**
+ * XQTS attribute-errors-q14: Simultaneous attribute replacements
+ * where one replaces @name with @salary and another replaces @gender with @name.
+ */
+ @Test
+ public void attributeReplaceSwap() throws XMLDBException {
+ final String query =
+ "copy $in := " +
+ " E1P1" +
+ " " +
+ "modify (" +
+ " replace node $in/@name with attribute {'salary'} {'10'}," +
+ " replace node $in/@gender with attribute {'name'} {'Blodwyn Jones'}" +
+ ") " +
+ "return $in";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ System.err.println("attrReplaceSwap: " + xml);
+ assertTrue("Should have salary attr", xml.contains("salary=\"10\""));
+ assertTrue("Should have name attr with new value", xml.contains("name=\"Blodwyn Jones\""));
+ assertFalse("Should NOT have gender attr", xml.contains("gender="));
+ }
+
+ // ======================== FullAxis tests ========================
+
+ /**
+ * Baseline: following axis from document element (no updates).
+ */
+ @Test
+ public void followingAxisFromDocElementBaseline() throws XMLDBException {
+ final String query =
+ "let $doc := document { " +
+ " , , " +
+ " , " +
+ " , " +
+ "} " +
+ "return let $a := $doc/*/following::node() " +
+ "return {$a}";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ assertTrue("Should have count 2, got: " + xml, xml.contains("count=\"2\""));
+ }
+
+ /**
+ * Following axis from document element after deleting trailing comments.
+ * Based on XQTS upd-FullAxis/complex-deletes-q2.
+ */
+ @Test
+ public void followingAxisAfterDeleteTrailingComments() throws XMLDBException {
+ final String query =
+ "let $doc := document { " +
+ " , , , " +
+ " , " +
+ " , , " +
+ "} " +
+ "return copy $d := $doc " +
+ "modify delete nodes $d/comment()[. >> $d/*] " +
+ "return let $a := $d/*/following::node() " +
+ "return {$a}";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ // After deleting trailing comments, only PI-2 should remain as following
+ assertTrue("Should have count 1, got: " + xml, xml.contains("count=\"1\""));
+ assertTrue("Should contain the PI", xml.contains("pi-2"));
+ }
+
+ /**
+ * Following axis from document element after replacing trailing comment values.
+ * Based on XQTS upd-FullAxis/complex-replacevalues-q2.
+ */
+ @Test
+ public void followingAxisAfterReplaceTrailingCommentValues() throws XMLDBException {
+ final String query =
+ "let $doc := document { " +
+ " , , , " +
+ " , " +
+ " , , " +
+ "} " +
+ "return copy $d := $doc " +
+ "modify ( " +
+ " for $c in $d/comment()[. >> $d/*] " +
+ " return replace value of node $c with 'Replaced' " +
+ ") " +
+ "return let $a := $d/*/following::node() " +
+ "return {$a}";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ // Trailing comments replaced + PI = 3 following nodes
+ assertTrue("Should have count 3", xml.contains("count=\"3\""));
+ assertTrue("Should contain replaced comment", xml.contains("Replaced"));
+ assertTrue("Should contain the PI", xml.contains("pi-2"));
+ }
+
+ /**
+ * Preceding axis after replacing text nodes with empty strings.
+ * Based on XQTS upd-FullAxis/complex-replacevalues-q7.
+ * Verifies that soft-deleted nodes from mergeAdjacentTextNodes don't crash selectPreceding.
+ */
+ @Test
+ public void precedingAxisAfterReplaceTextWithEmpty() throws XMLDBException {
+ final String query =
+ "let $doc := document { " +
+ " " +
+ " text-a" +
+ " " +
+ " text-after-comment" +
+ " " +
+ " text-c" +
+ " " +
+ " text-after-pi" +
+ " " +
+ " " +
+ " " +
+ "} " +
+ "return copy $d := $doc " +
+ "modify ( " +
+ " for $t in $d//text()[preceding-sibling::node()[1]/(self::comment() | self::processing-instruction())] " +
+ " return replace value of node $t with '' " +
+ ") " +
+ "return let $a := $d//target/preceding::text() " +
+ "return {for $t in $a return {$t}}";
+ final ResourceSet result = existEmbeddedServer.executeQuery(query);
+ assertEquals(1L, result.getSize());
+ final String xml = result.getResource(0).getContent().toString();
+ // Should not crash with "node not found"
+ assertTrue("Should have text-a in preceding", xml.contains("text-a"));
+ assertTrue("Should have text-c in preceding", xml.contains("text-c"));
+ }
+
+}
diff --git a/exist-core/src/test/java/org/exist/xquery/xquf/XQUFBenchmark.java b/exist-core/src/test/java/org/exist/xquery/xquf/XQUFBenchmark.java
new file mode 100644
index 00000000000..48be03d1c10
--- /dev/null
+++ b/exist-core/src/test/java/org/exist/xquery/xquf/XQUFBenchmark.java
@@ -0,0 +1,444 @@
+/*
+ * eXist-db Open Source Native XML Database
+ * Copyright (C) 2001 The eXist-db Authors
+ *
+ * info@exist-db.org
+ * http://www.exist-db.org
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package org.exist.xquery.xquf;
+
+import org.exist.test.ExistXmldbEmbeddedServer;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import static org.junit.Assert.assertTrue;
+import org.xmldb.api.base.Collection;
+import org.xmldb.api.base.ResourceSet;
+import org.xmldb.api.base.XMLDBException;
+import org.xmldb.api.modules.CollectionManagementService;
+import org.xmldb.api.modules.XMLResource;
+import org.xmldb.api.modules.XQueryService;
+
+/**
+ * Performance benchmark for W3C XQuery Update Facility 3.0 operations.
+ *
+ * Measures wall-clock time for W3C XQUF persistent update operations (insert,
+ * delete, replace node, replace value, rename), their legacy eXist-db equivalents
+ * (update insert, update delete, etc.), and in-memory copy-modify (transform)
+ * expressions at various data sizes.
+ *
+ * This class intentionally does not end in {@code *Test} so that
+ * Surefire will not discover it during normal {@code mvn test} runs.
+ * Run explicitly with:
+ *
+ * mvn test -pl exist-core -Dtest=XQUFBenchmark \
+ * -Dexist.run.benchmarks=true -Ddependency-check.skip=true
+ *
+ */
+@SuppressWarnings("PMD.ClassNamingConventions") // benchmark, not a test class; gated by -Dexist.run.benchmarks=true
+public class XQUFBenchmark {
+
+ @ClassRule
+ public static final ExistXmldbEmbeddedServer server =
+ new ExistXmldbEmbeddedServer(false, true, true);
+
+ private static final String COLLECTION_NAME = "benchmark-xquf";
+ private static final String COLLECTION_PATH = "/db/" + COLLECTION_NAME;
+
+ private static final int WARMUP_ITERATIONS = 3;
+ private static final int MEASURE_ITERATIONS = 5;
+ private static final int[] DATA_SIZES = {10, 50, 200};
+
+ @BeforeClass
+ public static void assumeBenchmarks() {
+ Assume.assumeTrue("Benchmarks are disabled. Set -Dexist.run.benchmarks=true to enable.",
+ Boolean.getBoolean("exist.run.benchmarks"));
+ }
+
+ @BeforeClass
+ public static void setUp() throws XMLDBException {
+ if (!Boolean.getBoolean("exist.run.benchmarks")) {
+ return;
+ }
+
+ final CollectionManagementService cms =
+ server.getRoot().getService(CollectionManagementService.class);
+ cms.createCollection(COLLECTION_NAME);
+ }
+
+ @AfterClass
+ public static void tearDown() throws XMLDBException {
+ if (!Boolean.getBoolean("exist.run.benchmarks")) {
+ return;
+ }
+
+ final CollectionManagementService cms =
+ server.getRoot().getService(CollectionManagementService.class);
+ cms.removeCollection(COLLECTION_NAME);
+ }
+
+ // ---- Persistent update benchmarks ----
+
+ @Test
+ public void insertInto() throws XMLDBException {
+ System.out.println("\n=== insert node ... into (persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("insert-into", size, (queryService, docPath) -> {
+ // Reset document with N items
+ storeDocument(size);
+
+ // Insert a new child into each item
+ final String update = String.format(
+ "for $item in doc('%s/bench.xml')//item " +
+ "return insert node into $item",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("insert-into benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void deleteNode() throws XMLDBException {
+ System.out.println("\n=== delete node (persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("delete-node", size, (queryService, docPath) -> {
+ // Reset document with N items, each having a child
+ storeDocument(size);
+
+ // Delete the child from each item
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return delete node $v",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("delete-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void replaceValue() throws XMLDBException {
+ System.out.println("\n=== replace value of node (persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("replace-value", size, (queryService, docPath) -> {
+ // Reset document
+ storeDocument(size);
+
+ // Replace value of each item's @id attribute
+ final String update = String.format(
+ "for $item in doc('%s/bench.xml')//item " +
+ "return replace value of node $item/@id with concat('new-', $item/@id)",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("replace-value benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void renameNode() throws XMLDBException {
+ System.out.println("\n=== rename node (persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("rename-node", size, (queryService, docPath) -> {
+ // Reset document
+ storeDocument(size);
+
+ // Rename each element to
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return rename node $v as 'renamed'",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("rename-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void replaceNode() throws XMLDBException {
+ System.out.println("\n=== replace node (persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("replace-node", size, (queryService, docPath) -> {
+ // Reset document
+ storeDocument(size);
+
+ // Replace each with a
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return replace node $v with {string($v)}",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("replace-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ // ---- Legacy persistent update benchmarks (DEPRECATED syntax) ----
+
+ @Test
+ public void legacyInsertInto() throws XMLDBException {
+ System.out.println("\n=== update insert ... into (legacy persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("legacy-insert-into", size, (queryService, docPath) -> {
+ storeDocument(size);
+ final String update = String.format(
+ "for $item in doc('%s/bench.xml')//item " +
+ "return update insert into $item",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("legacy-insert-into benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void legacyDeleteNode() throws XMLDBException {
+ System.out.println("\n=== update delete (legacy persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("legacy-delete-node", size, (queryService, docPath) -> {
+ storeDocument(size);
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return update delete $v",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("legacy-delete-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void legacyReplaceValue() throws XMLDBException {
+ System.out.println("\n=== update value (legacy persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("legacy-replace-value", size, (queryService, docPath) -> {
+ storeDocument(size);
+ final String update = String.format(
+ "for $item in doc('%s/bench.xml')//item " +
+ "return update value $item/@id with concat('new-', $item/@id)",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("legacy-replace-value benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void legacyRenameNode() throws XMLDBException {
+ System.out.println("\n=== update rename (legacy persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("legacy-rename-node", size, (queryService, docPath) -> {
+ storeDocument(size);
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return update rename $v as 'renamed'",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("legacy-rename-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void legacyReplaceNode() throws XMLDBException {
+ System.out.println("\n=== update replace (legacy persistent) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final double avgMs = runPersistentBenchmark("legacy-replace-node", size, (queryService, docPath) -> {
+ storeDocument(size);
+ final String update = String.format(
+ "for $v in doc('%s/bench.xml')//item/value " +
+ "return update replace $v with {string($v)}",
+ COLLECTION_PATH);
+ queryService.query(update);
+ });
+ assertTrue("legacy-replace-node benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ // ---- In-memory copy-modify benchmarks ----
+
+ @Test
+ public void copyModifySingle() throws XMLDBException {
+ System.out.println("\n=== copy-modify single node (in-memory) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final String query = String.format(
+ "let $doc := { for $i in 1 to %d return - {$i}
} " +
+ "return copy $c := $doc modify ( replace value of node $c//item[@id = '1']/value with 'modified' ) return $c//item[@id = '1']/value/string()",
+ size);
+ final double avgMs = runInMemoryBenchmark("copy-modify-single", size, query);
+ assertTrue("copy-modify-single benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void copyModifyMultiple() throws XMLDBException {
+ System.out.println("\n=== copy-modify multiple replaceValue (in-memory) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final String query = String.format(
+ "let $doc := { for $i in 1 to %d return - {$i}
} " +
+ "return copy $c := $doc modify ( " +
+ " for $v in $c//item/value return replace value of node $v with concat('m-', $v) " +
+ ") return count($c//item)",
+ size);
+ final double avgMs = runInMemoryBenchmark("copy-modify-multi", size, query);
+ assertTrue("copy-modify-multi benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void copyModifyInsertDelete() throws XMLDBException {
+ System.out.println("\n=== copy-modify insert + delete (in-memory) ===");
+ printHeader();
+
+ for (final int size : DATA_SIZES) {
+ final String query = String.format(
+ "let $doc := { for $i in 1 to %d return - {$i}
} " +
+ "return copy $c := $doc modify ( " +
+ " insert node into $c, " +
+ " for $v in $c//item[@id = ('1','2','3')]/value return delete node $v " +
+ ") return count($c//item)",
+ size);
+ final double avgMs = runInMemoryBenchmark("copy-modify-ins-del", size, query);
+ assertTrue("copy-modify-ins-del benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ @Test
+ public void copyModifyDeepTree() throws XMLDBException {
+ System.out.println("\n=== copy-modify deep tree (in-memory) ===");
+ printHeader();
+
+ // Nested structure: root > section > subsection > item (depth=4)
+ for (final int size : DATA_SIZES) {
+ final String query = String.format(
+ "let $doc := { " +
+ " for $s in 1 to %d " +
+ " return { " +
+ " for $ss in 1 to 3 " +
+ " return - data
" +
+ " } " +
+ "} " +
+ "return copy $c := $doc modify ( " +
+ " for $item in $c//item return replace value of node $item with 'updated' " +
+ ") return count($c//item[. = 'updated'])",
+ size);
+ final double avgMs = runInMemoryBenchmark("copy-modify-deep", size, query);
+ assertTrue("copy-modify-deep benchmark should complete in positive time", avgMs >= 0);
+ }
+ }
+
+ // ---- Helpers ----
+
+ private void storeDocument(final int numItems) throws XMLDBException {
+ final Collection col = server.getRoot().getChildCollection(COLLECTION_NAME);
+ final StringBuilder sb = new StringBuilder("\n");
+ for (int i = 1; i <= numItems; i++) {
+ sb.append(String.format(" - val-%d
\n", i, i));
+ }
+ sb.append("");
+
+ final XMLResource res = col.createResource("bench.xml", XMLResource.class);
+ res.setContent(sb.toString());
+ col.storeResource(res);
+ }
+
+ @FunctionalInterface
+ interface PersistentOperation {
+ void execute(XQueryService queryService, String docPath) throws XMLDBException;
+ }
+
+ private double runPersistentBenchmark(final String label, final int size,
+ final PersistentOperation operation) throws XMLDBException {
+ final XQueryService queryService = server.getRoot().getService(XQueryService.class);
+
+ // warmup
+ for (int i = 0; i < WARMUP_ITERATIONS; i++) {
+ operation.execute(queryService, COLLECTION_PATH + "/bench.xml");
+ }
+
+ // measure
+ long totalNs = 0;
+ for (int i = 0; i < MEASURE_ITERATIONS; i++) {
+ final long start = System.nanoTime();
+ operation.execute(queryService, COLLECTION_PATH + "/bench.xml");
+ final long elapsed = System.nanoTime() - start;
+ totalNs += elapsed;
+ }
+
+ final double avgMs = (totalNs / (double) MEASURE_ITERATIONS) / 1_000_000.0;
+ System.out.printf(" %-24s size=%3d avg=%8.2f ms%n", label, size, avgMs);
+ return avgMs;
+ }
+
+ private double runInMemoryBenchmark(final String label, final int size,
+ final String query) throws XMLDBException {
+ final XQueryService queryService = server.getRoot().getService(XQueryService.class);
+
+ // warmup
+ for (int i = 0; i < WARMUP_ITERATIONS; i++) {
+ queryService.query(query);
+ }
+
+ // measure
+ long totalNs = 0;
+ for (int i = 0; i < MEASURE_ITERATIONS; i++) {
+ final long start = System.nanoTime();
+ final ResourceSet result = queryService.query(query);
+ if (result.getSize() != 1) {
+ throw new AssertionError(label + " (size=" + size + "): expected 1 result, got " + result.getSize());
+ }
+ final long elapsed = System.nanoTime() - start;
+ totalNs += elapsed;
+ }
+
+ final double avgMs = (totalNs / (double) MEASURE_ITERATIONS) / 1_000_000.0;
+ System.out.printf(" %-24s size=%3d avg=%8.2f ms%n", label, size, avgMs);
+ return avgMs;
+ }
+
+ private static void printHeader() {
+ System.out.printf(" %-24s %8s %12s%n", "Operation", "Size", "Avg (ms)");
+ System.out.println(" " + "-".repeat(50));
+ }
+}
diff --git a/exist-core/src/test/xquery/xquery3/bindingConflict.xqm b/exist-core/src/test/xquery/xquery3/bindingConflict.xqm
index b9133d010fc..b2ea5d7f8f7 100644
--- a/exist-core/src/test/xquery/xquery3/bindingConflict.xqm
+++ b/exist-core/src/test/xquery/xquery3/bindingConflict.xqm
@@ -29,6 +29,8 @@ declare namespace xmldb="http://exist-db.org/xquery/xmldb";
declare namespace myns="http://www.foo.com";
declare namespace myns2="http://www.foo.net";
+(: ===== Legacy update tests (persistent documents) ===== :)
+
(: insert node into a ns with a conflicting ns in parent tree :)
declare %test:assertError("XUDY0023")
function ut:insert-child-namespaced-attr-conflicted() {
diff --git a/exist-core/src/test/xquery/xquery3/bindingConflictXQUF.xqm b/exist-core/src/test/xquery/xquery3/bindingConflictXQUF.xqm
new file mode 100644
index 00000000000..097d19d180b
--- /dev/null
+++ b/exist-core/src/test/xquery/xquery3/bindingConflictXQUF.xqm
@@ -0,0 +1,90 @@
+(:
+ : eXist-db Open Source Native XML Database
+ : Copyright (C) 2001 The eXist-db Authors
+ :
+ : info@exist-db.org
+ : http://www.exist-db.org
+ :
+ : This library is free software; you can redistribute it and/or
+ : modify it under the terms of the GNU Lesser General Public
+ : License as published by the Free Software Foundation; either
+ : version 2.1 of the License, or (at your option) any later version.
+ :
+ : This library is distributed in the hope that it will be useful,
+ : but WITHOUT ANY WARRANTY; without even the implied warranty of
+ : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ : Lesser General Public License for more details.
+ :
+ : You should have received a copy of the GNU Lesser General Public
+ : License along with this library; if not, write to the Free Software
+ : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ :)
+xquery version "3.1";
+
+(: W3C XQUF 3.0 versions of the namespace binding conflict tests.
+ : These use copy/modify/return (in-memory) instead of the legacy
+ : update syntax (persistent). Separated into its own module because
+ : legacy and XQUF syntax cannot be mixed in the same module.
+ :)
+
+module namespace utx="http://exist-db.org/xquery/update/xquf-test";
+
+declare namespace test="http://exist-db.org/xquery/xqsuite";
+
+declare namespace myns="http://www.foo.com";
+declare namespace myns2="http://www.foo.net";
+
+(: insert node into a ns with a conflicting ns in parent tree :)
+declare %test:assertError("XUDY0023")
+function utx:xquf-insert-child-namespaced-attr-conflicted() {
+ copy $data :=
+ modify insert node into $data/z
+ return $data
+};
+
+(: insert attr into a ns, but nothing contradictory in the tree - should add ns node :)
+declare %test:assertEquals("")
+function utx:xquf-insert-child-namespaced-attr() {
+ copy $data :=
+ modify insert node into $data/z
+ return $data/z
+};
+
+(: insert attr into a ns, but nothing contradictory in the tree - should add ns node :)
+declare %test:assertEquals("")
+function utx:xquf-insert-namespaced-child() {
+ copy $data :=
+ modify insert node into $data/z
+ return $data/z
+};
+
+declare %test:assertEquals("")
+function utx:xquf-insert-namespaced-child-deep() {
+ copy $data :=
+ modify insert node into $data/z
+ return fn:serialize($data/z)
+};
+
+(: insert attr into a ns, but nothing contradictory in the tree - should add ns node :)
+declare %test:assertError("XUDY0023")
+function utx:xquf-insert-namespaced-child-conflicted() {
+ copy $data :=
+ modify insert node into $data/z
+ return $data/z
+};
+
+(: insert attr into a ns with a conflicting ns in parent tree :)
+declare %test:assertError("XUDY0023")
+function utx:xquf-insert-namespaced-attr-conflicted() {
+ copy $data :=
+ modify insert node attribute myns:baz { "qux" } into $data/z
+ return $data
+};
+
+(: insert attr into a ns, but nothing contradictory in the tree - should add ns node :)
+declare %test:assertEquals("")
+function utx:xquf-insert-namespaced-attr() {
+ copy $data :=
+ modify insert node attribute myns:baz { "qux" } into $data/z
+ return $data/z
+};