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 a9aa9d84 Misc fixes (#170)
a9aa9d84 is described below
commit a9aa9d84539c00be3b2fab684434e1c1ccfdef13
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu Sep 24 11:18:20 2026 +0100
Misc fixes (#170)
---
.../schema/docpath/XmlSchemaElementValidator.java | 8 ++
.../ws/commons/schema/walker/XmlSchemaScope.java | 23 +++-
.../schema/docpath/TestPathFinderFailureTypes.java | 11 ++
.../walker/ComplexContentExtensionWalkerTest.java | 129 +++++++++++++++++++++
4 files changed, 168 insertions(+), 3 deletions(-)
diff --git
a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaElementValidator.java
b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaElementValidator.java
index 11e2c836..3efeaa57 100644
---
a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaElementValidator.java
+++
b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/docpath/XmlSchemaElementValidator.java
@@ -144,6 +144,14 @@ final class XmlSchemaElementValidator {
continue;
}
+ /*
+ * An attribute declared without a type is an xs:anySimpleType,
+ * which accepts any value; the walker leaves its type unset.
+ */
+ if (attribute.getType() == null) {
+ continue;
+ }
+
if
(attribute.getType().getType().equals(XmlSchemaTypeInfo.Type.COMPLEX)) {
throw new ValidationException("Attribute " + attrQName + " of
element " + elemQName
diff --git
a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
index 1fcb5592..08be6e43 100644
---
a/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
+++
b/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
@@ -403,6 +403,14 @@ final class XmlSchemaScope {
child = baseParticle;
} else if (baseParticle == null) {
child = ext.getParticle();
+ } else if (!(baseParticle instanceof XmlSchemaSequenceMember)
+ || !(ext.getParticle() instanceof
XmlSchemaSequenceMember)) {
+ // Only an xs:all is not a sequence member, and XML Schema 1.0
+ // does not allow one to be combined with any other particle.
+ throw new XmlSchemaException("An extension of " +
ext.getBaseTypeName()
+ + " adds content to it, but one
of the two content"
+ + " models is an xs:all group,
which cannot be"
+ + " combined with other
particles.");
} else {
XmlSchemaSequence seq = new XmlSchemaSequence();
seq.getItems().add((XmlSchemaSequenceMember)baseParticle);
@@ -420,8 +428,13 @@ final class XmlSchemaScope {
} else if (ext.getAnyAttribute() == null) {
anyAttr = baseAnyAttr;
} else {
- String[] baseNamespaces = baseAnyAttr.getNamespace().split("
");
- String[] childNamespaces =
ext.getAnyAttribute().getNamespace().split(" ");
+ // An absent namespace attribute means ##any, and a union with
+ // ##any is ##any.
+ final String baseNamespace = baseAnyAttr.getNamespace();
+ final String childNamespace =
ext.getAnyAttribute().getNamespace();
+ final boolean unionIsAny = isAnyNamespace(baseNamespace) ||
isAnyNamespace(childNamespace);
+ String[] baseNamespaces = unionIsAny ? new String[0] :
baseNamespace.split(" ");
+ String[] childNamespaces = unionIsAny ? new String[0] :
childNamespace.split(" ");
HashSet<String> namespaces = new HashSet<String>();
for (String baseNs : baseNamespaces) {
@@ -441,7 +454,7 @@ final class XmlSchemaScope {
}
anyAttr = new XmlSchemaAnyAttribute();
- anyAttr.setNamespace(nsAsString.toString());
+ anyAttr.setNamespace(unionIsAny ? "##any" :
nsAsString.toString());
anyAttr.setProcessContent(ext.getAnyAttribute().getProcessContent());
anyAttr.setAnnotation(ext.getAnyAttribute().getAnnotation());
anyAttr.setId(ext.getAnyAttribute().getId());
@@ -825,6 +838,10 @@ final class XmlSchemaScope {
return (parent == null) ? null : parent.getUserRecognizedType();
}
+ private static boolean isAnyNamespace(String namespace) {
+ return (namespace == null) || "##any".equals(namespace.trim());
+ }
+
private static String getName(XmlSchemaNamed name, String defaultName) {
if (name.isAnonymous()) {
return defaultName;
diff --git
a/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/TestPathFinderFailureTypes.java
b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/TestPathFinderFailureTypes.java
index 7aaec5c0..06a96cda 100644
---
a/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/TestPathFinderFailureTypes.java
+++
b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/TestPathFinderFailureTypes.java
@@ -136,6 +136,17 @@ public class TestPathFinderFailureTypes extends Assert {
}
}
+ /**
+ * An attribute declared without a type is an xs:anySimpleType and accepts
any value.
+ */
+ @Test
+ public void testUntypedAttributeAcceptsAnyValue() throws Exception {
+ walk("<xs:element name=\"root\"><xs:complexType>"
+ + "<xs:attribute name=\"x\"/>"
+ + "</xs:complexType></xs:element>",
+ "<root xmlns=\"urn:t\" x=\"1\"/>");
+ }
+
@Test
public void testValidDocumentStillWalks() throws Exception {
walk("<xs:simpleType name=\"s\"><xs:restriction base=\"xs:string\">"
diff --git
a/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/ComplexContentExtensionWalkerTest.java
b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/ComplexContentExtensionWalkerTest.java
new file mode 100644
index 00000000..2d9faecf
--- /dev/null
+++
b/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/walker/ComplexContentExtensionWalkerTest.java
@@ -0,0 +1,129 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ws.commons.schema.walker;
+
+import java.io.StringReader;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
+import org.apache.ws.commons.schema.XmlSchemaCollection;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * A complex content extension combines the content model and attribute
wildcard of its base
+ * with its own. Doing so must not escape as a ClassCastException or
NullPointerException.
+ */
+public class ComplexContentExtensionWalkerTest extends Assert {
+
+ private static List<String> walkRoot(String body) {
+ XmlSchemaCollection collection = new XmlSchemaCollection();
+ collection.read(new StringReader(
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"
xmlns:tns=\"urn:ext\""
+ + " targetNamespace=\"urn:ext\" elementFormDefault=\"qualified\">"
+ + body
+ + "</xs:schema>"));
+ XmlSchemaElement root = collection.getElementByQName(new
QName("urn:ext", "root"));
+ assertNotNull("the schema under test must declare a 'root' element",
root);
+
+ // Records the namespace of every attribute wildcard visited.
+ final List<String> anyAttributeNamespaces = new ArrayList<String>();
+ XmlSchemaVisitor visitor = (XmlSchemaVisitor)Proxy.newProxyInstance(
+ XmlSchemaVisitor.class.getClassLoader(), new Class<?>[]
{XmlSchemaVisitor.class},
+ (proxy, method, args) -> {
+ if ("onVisitAnyAttribute".equals(method.getName())) {
+
anyAttributeNamespaces.add(((XmlSchemaAnyAttribute)args[1]).getNamespace());
+ }
+ return null;
+ });
+ new XmlSchemaWalker(collection, visitor).walk(root);
+ return anyAttributeNamespaces;
+ }
+
+ @Test
+ public void testExtendingAnAllGroupWithMoreContentIsRejected() {
+ try {
+ walkRoot("<xs:complexType name=\"base\"><xs:all>"
+ + "<xs:element name=\"a\" type=\"xs:string\"/>"
+ + "</xs:all></xs:complexType>"
+ + "<xs:complexType name=\"derived\"><xs:complexContent>"
+ + "<xs:extension base=\"tns:base\"><xs:sequence>"
+ + "<xs:element name=\"b\" type=\"xs:string\"/>"
+ +
"</xs:sequence></xs:extension></xs:complexContent></xs:complexType>"
+ + "<xs:element name=\"root\" type=\"tns:derived\"/>");
+ fail("expected an xs:all combined with other content to be
rejected");
+ } catch (XmlSchemaException expected) {
+ assertTrue(expected.getMessage(),
expected.getMessage().contains("xs:all"));
+ }
+ }
+
+ @Test
+ public void testExtendingASequenceWithASequenceStillWalks() {
+ walkRoot("<xs:complexType name=\"base\"><xs:sequence>"
+ + "<xs:element name=\"a\" type=\"xs:string\"/>"
+ + "</xs:sequence></xs:complexType>"
+ + "<xs:complexType name=\"derived\"><xs:complexContent>"
+ + "<xs:extension base=\"tns:base\"><xs:sequence>"
+ + "<xs:element name=\"b\" type=\"xs:string\"/>"
+ +
"</xs:sequence></xs:extension></xs:complexContent></xs:complexType>"
+ + "<xs:element name=\"root\" type=\"tns:derived\"/>");
+ }
+
+ /**
+ * An xs:anyAttribute with no namespace attribute allows any namespace,
and so does its union
+ * with any other wildcard.
+ */
+ @Test
+ public void testAnyAttributeWithoutANamespaceIsAnyNamespace() {
+ List<String> namespaces =
+ walkRoot("<xs:complexType name=\"base\"><xs:sequence/>"
+ + "<xs:anyAttribute/></xs:complexType>"
+ + "<xs:complexType name=\"derived\"><xs:complexContent>"
+ + "<xs:extension base=\"tns:base\">"
+ + "<xs:anyAttribute namespace=\"urn:other\"
processContents=\"lax\"/>"
+ + "</xs:extension></xs:complexContent></xs:complexType>"
+ + "<xs:element name=\"root\" type=\"tns:derived\"/>");
+ assertEquals(1, namespaces.size());
+ assertEquals("##any", namespaces.get(0));
+ }
+
+ @Test
+ public void testAnyAttributeNamespacesAreStillUnited() {
+ List<String> namespaces =
+ walkRoot("<xs:complexType name=\"base\"><xs:sequence/>"
+ + "<xs:anyAttribute
namespace=\"urn:a\"/></xs:complexType>"
+ + "<xs:complexType name=\"derived\"><xs:complexContent>"
+ + "<xs:extension base=\"tns:base\">"
+ + "<xs:anyAttribute namespace=\"urn:b\"/>"
+ + "</xs:extension></xs:complexContent></xs:complexType>"
+ + "<xs:element name=\"root\" type=\"tns:derived\"/>");
+ assertEquals(1, namespaces.size());
+ String[] united = namespaces.get(0).trim().split(" ");
+ Arrays.sort(united);
+ assertArrayEquals(new String[] {"urn:a", "urn:b"}, united);
+ }
+}