This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/ancestor-prefix in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git
commit efc9b9c63b5e88d18dd8fd528c6196ffc9e523d1 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Thu Sep 24 11:00:52 2026 +0100 Collect ancestor prefix declarations without recursion --- .../ws/commons/schema/utils/PrefixCollector.java | 17 ++++++--- .../src/test/java/tests/NestingDepthLimitTest.java | 40 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/utils/PrefixCollector.java b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/utils/PrefixCollector.java index f5bec260..3320b23c 100644 --- a/xmlschema-core/src/main/java/org/apache/ws/commons/schema/utils/PrefixCollector.java +++ b/xmlschema-core/src/main/java/org/apache/ws/commons/schema/utils/PrefixCollector.java @@ -19,6 +19,9 @@ package org.apache.ws.commons.schema.utils; +import java.util.ArrayDeque; +import java.util.Deque; + import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -59,12 +62,18 @@ public abstract class PrefixCollector { * Searches for namespace prefix declarations in the given node. For any prefix declaration, it invokes * {@link #declare(String, String)}. This method works recursively: The parent nodes prefix declarations * are collected before the current nodes. + * <p> + * The ancestors are walked with a loop rather than by recursion, as a schema element embedded + * deep in a larger document would otherwise take one stack frame per ancestor. + * </p> */ public void searchAllPrefixDeclarations(Node pNode) { - Node parent = pNode.getParentNode(); - if (parent != null) { - searchAllPrefixDeclarations(parent); + Deque<Node> ancestry = new ArrayDeque<Node>(); + for (Node node = pNode; node != null; node = node.getParentNode()) { + ancestry.push(node); + } + while (!ancestry.isEmpty()) { + searchLocalPrefixDeclarations(ancestry.pop()); } - searchLocalPrefixDeclarations(pNode); } } diff --git a/xmlschema-core/src/test/java/tests/NestingDepthLimitTest.java b/xmlschema-core/src/test/java/tests/NestingDepthLimitTest.java index e9c70811..de91c742 100644 --- a/xmlschema-core/src/test/java/tests/NestingDepthLimitTest.java +++ b/xmlschema-core/src/test/java/tests/NestingDepthLimitTest.java @@ -24,6 +24,9 @@ import java.io.FileWriter; import java.io.StringReader; import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; + import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.apache.ws.commons.schema.XmlSchemaException; @@ -33,6 +36,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import org.xml.sax.InputSource; /** @@ -153,6 +158,41 @@ public class NestingDepthLimitTest extends Assert { assertNotNull(schema); } + /** + * read(Element) collects the namespace declarations of every ancestor of the + * schema element, which must not take a stack frame per ancestor when the + * schema is embedded deep in a larger document such as a WSDL. The prefix + * declared on the outermost wrapper must still be seen. + */ + @Test + public void testSchemaEmbeddedDeepInADocumentStillParses() throws Exception { + int depth = 20000; + StringBuilder doc = new StringBuilder(); + doc.append("<w xmlns:tns=\"urn:embedded\">"); + for (int i = 1; i < depth; i++) { + doc.append("<w>"); + } + doc.append("<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"") + .append(" targetNamespace=\"urn:embedded\">") + .append("<xs:complexType name=\"t\"/>") + .append("<xs:element name=\"e\" type=\"tns:t\"/>") + .append("</xs:schema>"); + for (int i = 0; i < depth; i++) { + doc.append("</w>"); + } + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + Document document = factory.newDocumentBuilder() + .parse(new InputSource(new StringReader(doc.toString()))); + Element schemaElement = (Element)document + .getElementsByTagNameNS("http://www.w3.org/2001/XMLSchema", "schema").item(0); + + XmlSchema schema = new XmlSchemaCollection().read(schemaElement); + assertEquals(new QName("urn:embedded", "t"), + schema.getElementByName("e").getSchemaTypeName()); + } + private void assertMarkupRejected(String kind) { XmlSchemaCollection collection = new XmlSchemaCollection(); try {
