From 0294331ebbfc851bb621108ab1eb5cf5c4b840c2 Mon Sep 17 00:00:00 2001 From: Adam Retter Date: Sat, 28 Jun 2025 15:02:44 +0200 Subject: [PATCH 1/3] [bugfix] Add missing tests for fn:parse-xml-fragment --- exist-core/pom.xml | 2 + .../src/test/xquery/xquery3/parse-xml.xq | 40 ----- .../src/test/xquery/xquery3/parse-xml.xqm | 147 ++++++++++++++++++ 3 files changed, 149 insertions(+), 40 deletions(-) delete mode 100644 exist-core/src/test/xquery/xquery3/parse-xml.xq create mode 100644 exist-core/src/test/xquery/xquery3/parse-xml.xqm diff --git a/exist-core/pom.xml b/exist-core/pom.xml index 3e7e580829..99f8596aac 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -781,6 +781,7 @@ src/test/resources/standalone-webapp/WEB-INF/web.xml src/test/xquery/maps/maps.xqm src/test/xquery/util/util.xml + src/test/xquery/xquery3/parse-xml.xqm src/test/xquery/xquery3/serialize.xql src/main/java/org/exist/Indexer.java src/main/resources-filtered/org/exist/system.properties @@ -1007,6 +1008,7 @@ src/test/xquery/xqsuite/xqsuite-assertions-inline.xqm src/test/xquery/xqsuite/xqsuite-assertions.resources.xqm.ignore src/test/xquery/xquery3/function-reference.xqm + src/test/xquery/xquery3/parse-xml.xqm src/test/xquery/xquery3/postfix-expr.xqm src/test/xquery/xquery3/serialize.xql src/main/java/org/exist/Indexer.java diff --git a/exist-core/src/test/xquery/xquery3/parse-xml.xq b/exist-core/src/test/xquery/xquery3/parse-xml.xq deleted file mode 100644 index ab920bef04..0000000000 --- a/exist-core/src/test/xquery/xquery3/parse-xml.xq +++ /dev/null @@ -1,40 +0,0 @@ -(: - : 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.0"; - -(:~ Additional tests for the fn:parse-xml and fn:parse-xml-fragment functions :) -module namespace px="http://exist-db.org/xquery/test/parse-xml"; - -declare namespace test="http://exist-db.org/xquery/xqsuite"; - -declare - %test:assertTrue -function px:fragment-type() { - fn:parse-xml-fragment("He was so kind") instance of document-node() -}; - - -declare - %test:assertEquals(3) -function px:fragment-count() { - count(parse-xml-fragment("He was so kind")/node()) -}; diff --git a/exist-core/src/test/xquery/xquery3/parse-xml.xqm b/exist-core/src/test/xquery/xquery3/parse-xml.xqm new file mode 100644 index 0000000000..3e39320490 --- /dev/null +++ b/exist-core/src/test/xquery/xquery3/parse-xml.xqm @@ -0,0 +1,147 @@ +(: + : Elemental + : Copyright (C) 2024, Evolved Binary Ltd + : + : admin@evolvedbinary.com + : https://www.evolvedbinary.com | https://www.elemental.xyz + : + : 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; version 2.1. + : + : 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 + : + : NOTE: Parts of this file contain code from 'The eXist-db Authors'. + : The original license header is included below. + : + : ===================================================================== + : + : 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.0"; + +(:~ Additional tests for the fn:parse-xml and fn:parse-xml-fragment functions :) +module namespace px="http://exist-db.org/xquery/test/parse-xml"; + +declare namespace test="http://exist-db.org/xquery/xqsuite"; + +declare + %test:assertEmpty +function px:fragment-type-1() { + fn:parse-xml-fragment(()) +}; + +declare + %test:assertTrue +function px:fragment-type-2() { + fn:parse-xml-fragment("") instance of document-node() +}; + +declare + %test:assertEmpty +function px:fragment-children-1() { + fn:parse-xml-fragment("")/node() +}; + +declare + %test:assertTrue +function px:fragment-type-3() { + fn:parse-xml-fragment(" ") instance of document-node() +}; + +declare + %test:assertTrue(" ") +function px:fragment-children-2() { + fn:parse-xml-fragment(" ")/node() +}; + +declare + %test:assertTrue +function px:fragment-type-4() { + fn:parse-xml-fragment("abcdabcd") instance of document-node() +}; + +declare + %test:assertEquals("abcd", "abcd") +function px:fragment-children-3() { + fn:parse-xml-fragment("abcdabcd")/node() +}; + +declare + %test:assertTrue +function px:fragment-type-5() { + fn:parse-xml-fragment("He was so kind") instance of document-node() +}; + +declare + %test:assertEquals(1) +function px:fragment-count() { + count(parse-xml-fragment("He was so kind")) +}; + +declare + %test:assertEquals(3) +function px:fragment-node-count() { + count(parse-xml-fragment("He was so kind")/node()) +}; + +declare + %test:assertTrue +function px:fragment-xml-decl() { + fn:parse-xml-fragment('') instance of document-node() +}; + +declare + %test:assertError("FODC0006") +function px:fragment-xml-decl-standalone-yes() { + fn:parse-xml-fragment('') +}; + +declare + %test:assertError("FODC0006") +function px:fragment-xml-decl-standalone-no() { + fn:parse-xml-fragment('') +}; + +declare + %test:assertTrue +function px:fragment-xml-decl-encoding() { + fn:parse-xml-fragment('') instance of document-node() +}; + +declare + %test:assertError("FODC0006") +function px:fragment-xml-decl-encoding-standalone-yes() { + fn:parse-xml-fragment('') +}; + +declare + %test:assertError("FODC0006") +function px:fragment-xml-decl-encoding-standalone-no() { + fn:parse-xml-fragment('') +}; From 0ff8f693dbd7ed174026641dc3cc2b36ac29ee6f Mon Sep 17 00:00:00 2001 From: Adam Retter Date: Sat, 28 Jun 2025 15:28:44 +0200 Subject: [PATCH 2/3] [bugfix] fn:parse-xml-fragment#1 should return a document-node() when there is an XML document that has a XML declaration --- .../xquery/functions/fn/ParsingFunctions.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java index 2c475c027d..90240217ac 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java @@ -64,7 +64,6 @@ import java.io.IOException; import java.io.StringReader; -import java.nio.charset.StandardCharsets; import static org.exist.util.ByteOrderMark.stripXmlBom; @@ -134,7 +133,27 @@ private ValidationReport validate(String xmlContent, final SAXAdapter saxAdapter xmlContent = stripXmlBom(xmlContent); final String xml; if (isCalledAs("parse-xml-fragment")) { - xml = "<" + FRAGMENT_WRAPPER_NAME + ">" + xmlContent + ""; + String declStr = xmlContent.toLowerCase(); + final int startIdx = declStr.indexOf(" -1) { + + // NOTE(AR) for parsing fragments the input must be an external entity, so validate that the declaration is a TextDecl (https://www.w3.org/TR/REC-xml/#NT-TextDecl) and not a full XMLDecl (https://www.w3.org/TR/REC-xml/#NT-XMLDecl) with standalone attribute + + declStr = declStr.substring(startIdx); + int endIdx = declStr.indexOf("?>"); + if (endIdx > -1) { + endIdx += 2; + } + declStr = declStr.substring(0, endIdx); + if (declStr.contains("standalone=")) { + throw new XPathException(this, ErrorCodes.FODC0006, "Input to fn:parse-xml-fragment must be a valid external entity, but 'standalone' attribute was detected in the declaration"); + } + + xml = xmlContent; + + } else { + xml = "<" + FRAGMENT_WRAPPER_NAME + ">" + xmlContent + ""; + } } else { xml = xmlContent; } From fc8cc000c0cfff74e0f51ffa4582ae194c512dfb Mon Sep 17 00:00:00 2001 From: Adam Retter Date: Sat, 28 Jun 2025 15:34:23 +0200 Subject: [PATCH 3/3] [bugfix] fn:parse-xml-fragment('') should return an empty document --- .../java/org/exist/xquery/functions/fn/ParsingFunctions.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java b/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java index 90240217ac..b8096a6742 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/fn/ParsingFunctions.java @@ -103,10 +103,6 @@ public Sequence eval(final Sequence[] args, final Sequence contextSequence) thro return Sequence.EMPTY_SEQUENCE; } final String xmlContent = args[0].itemAt(0).getStringValue(); - if (xmlContent.isEmpty()) { - return Sequence.EMPTY_SEQUENCE; - } - return parse(xmlContent, args); }