This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-xmlschema.git


The following commit(s) were added to refs/heads/master by this push:
     new c3c458f3 Collect ancestor prefix declarations without recursion (#169)
c3c458f3 is described below

commit c3c458f394c574dcd7dac941ecbad5ead2cde197
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu Sep 24 11:07:00 2026 +0100

    Collect ancestor prefix declarations without recursion (#169)
---
 .../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 {

Reply via email to