You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by dk...@apache.org on 2014/09/17 17:32:46 UTC

svn commit: r1625632 [4/9] - in /webservices/xmlschema/trunk: ./ xmlschema-walker/ xmlschema-walker/src/ xmlschema-walker/src/main/ xmlschema-walker/src/main/java/ xmlschema-walker/src/main/java/org/ xmlschema-walker/src/main/java/org/apache/ xmlschema...

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,821 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ws.commons.schema.XmlSchema;
+import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
+import org.apache.ws.commons.schema.XmlSchemaAttribute;
+import org.apache.ws.commons.schema.XmlSchemaAttributeGroup;
+import org.apache.ws.commons.schema.XmlSchemaAttributeGroupMember;
+import org.apache.ws.commons.schema.XmlSchemaAttributeGroupRef;
+import org.apache.ws.commons.schema.XmlSchemaAttributeOrGroupRef;
+import org.apache.ws.commons.schema.XmlSchemaComplexContent;
+import org.apache.ws.commons.schema.XmlSchemaComplexContentExtension;
+import org.apache.ws.commons.schema.XmlSchemaComplexContentRestriction;
+import org.apache.ws.commons.schema.XmlSchemaComplexType;
+import org.apache.ws.commons.schema.XmlSchemaContent;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaFacet;
+import org.apache.ws.commons.schema.XmlSchemaParticle;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.XmlSchemaSequenceMember;
+import org.apache.ws.commons.schema.XmlSchemaSimpleContentExtension;
+import org.apache.ws.commons.schema.XmlSchemaSimpleContentRestriction;
+import org.apache.ws.commons.schema.XmlSchemaSimpleType;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeContent;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeRestriction;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeUnion;
+import org.apache.ws.commons.schema.XmlSchemaType;
+import org.apache.ws.commons.schema.XmlSchemaUse;
+import org.apache.ws.commons.schema.utils.XmlSchemaNamed;
+
+/**
+ * The scope represents the set of types, attributes, and child groups &
+ * elements that the current type represents.
+ */
+final class XmlSchemaScope {
+
+    private Map<String, XmlSchema> schemasByNamespace;
+    private Map<QName, XmlSchemaScope> scopeCache;
+
+    private XmlSchemaTypeInfo typeInfo;
+    private HashMap<QName, XmlSchemaAttrInfo> attributes;
+    private XmlSchemaParticle child;
+    private XmlSchemaAnyAttribute anyAttr;
+    private Set<QName> userRecognizedTypes;
+
+    /**
+     * Initialization of members to be filled in during the walk.
+     */
+    private XmlSchemaScope() {
+        typeInfo = null;
+        attributes = null;
+        child = null;
+        anyAttr = null;
+    }
+
+    private XmlSchemaScope(XmlSchemaScope child, XmlSchemaType type) {
+        this();
+        this.schemasByNamespace = child.schemasByNamespace;
+        this.scopeCache = child.scopeCache;
+        this.userRecognizedTypes = child.userRecognizedTypes;
+
+        walk(type);
+    }
+
+    /**
+     * Initializes a new {@link XmlSchemaScope} with a base
+     * {@link XmlSchemaElement}. The element type and attributes will be
+     * traversed, and attribute lists and element children will be retrieved.
+     *
+     * @param element The base element to build the scope from.
+     * @param substitutions The master list of substitution groups to pull from.
+     * @param userRecognizedTypes The set of types recognized by the caller.
+     */
+    XmlSchemaScope(XmlSchemaType type, Map<String, XmlSchema> xmlSchemasByNamespace,
+                   Map<QName, XmlSchemaScope> scopeCache, Set<QName> userRecognizedTypes) {
+
+        this();
+
+        schemasByNamespace = xmlSchemasByNamespace;
+        this.scopeCache = scopeCache;
+        this.userRecognizedTypes = userRecognizedTypes;
+
+        walk(type);
+    }
+
+    /**
+     * The type information of the value in scope.
+     */
+    XmlSchemaTypeInfo getTypeInfo() {
+        return typeInfo;
+    }
+
+    /**
+     * The attributes visible in the current scope.
+     */
+    Collection<XmlSchemaAttrInfo> getAttributesInScope() {
+        if (attributes == null) {
+            return null;
+        }
+        return attributes.values();
+    }
+
+    /**
+     * If the value is represented by a particle, returns that particle.
+     * Otherwise returns <code>null</code>.
+     */
+    XmlSchemaParticle getParticle() {
+        return child;
+    }
+
+    /**
+     * The wildcard attribute, if any.
+     */
+    XmlSchemaAnyAttribute getAnyAttribute() {
+        return anyAttr;
+    }
+
+    private void walk(XmlSchemaType type) {
+        if (type instanceof XmlSchemaSimpleType) {
+            walk((XmlSchemaSimpleType)type);
+        } else if (type instanceof XmlSchemaComplexType) {
+            walk((XmlSchemaComplexType)type);
+        } else {
+            throw new IllegalArgumentException("Unrecognized XmlSchemaType of type "
+                                               + type.getClass().getName());
+        }
+    }
+
+    private void walk(XmlSchemaSimpleType simpleType) {
+        XmlSchemaSimpleTypeContent content = simpleType.getContent();
+
+        if (content == null) {
+            /*
+             * Only anyType contains no content. We reached the root of the type
+             * hierarchy.
+             */
+            typeInfo = new XmlSchemaTypeInfo(XmlSchemaBaseSimpleType.ANYTYPE);
+
+        } else if (content instanceof XmlSchemaSimpleTypeList) {
+            XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)content;
+            XmlSchemaSimpleType listType = list.getItemType();
+            if (listType == null) {
+                XmlSchema schema = schemasByNamespace.get(list.getItemTypeName().getNamespaceURI());
+
+                listType = (XmlSchemaSimpleType)schema.getTypeByName(list.getItemTypeName());
+            }
+            if (listType == null) {
+                throw new IllegalArgumentException("Unrecognized schema type for list "
+                                                   + getName(simpleType, "{Anonymous List Type}"));
+            }
+
+            XmlSchemaScope parentScope = getScope(listType);
+
+            switch (parentScope.getTypeInfo().getType()) {
+            case UNION:
+            case ATOMIC:
+                break;
+            default:
+                throw new IllegalStateException("Attempted to create a list from a "
+                                                + parentScope.getTypeInfo().getType() + " type.");
+            }
+
+            typeInfo = new XmlSchemaTypeInfo(parentScope.getTypeInfo());
+
+        } else if (content instanceof XmlSchemaSimpleTypeUnion) {
+            XmlSchemaSimpleTypeUnion union = (XmlSchemaSimpleTypeUnion)content;
+            QName[] namedBaseTypes = union.getMemberTypesQNames();
+            List<XmlSchemaSimpleType> baseTypes = union.getBaseTypes();
+
+            if (namedBaseTypes != null) {
+                if (baseTypes == null) {
+                    baseTypes = new ArrayList<XmlSchemaSimpleType>(namedBaseTypes.length);
+                }
+
+                for (QName namedBaseType : namedBaseTypes) {
+                    XmlSchema schema = schemasByNamespace.get(namedBaseType.getNamespaceURI());
+                    XmlSchemaSimpleType baseType = (XmlSchemaSimpleType)schema.getTypeByName(namedBaseType);
+                    if (baseType != null) {
+                        baseTypes.add(baseType);
+                    }
+                }
+            }
+
+            /*
+             * baseTypes cannot be null at this point; there must be a union of
+             * types.
+             */
+            if ((baseTypes == null) || baseTypes.isEmpty()) {
+                throw new IllegalArgumentException("Unrecognized base types for union "
+                                                   + getName(simpleType, "{Anonymous Union Type}"));
+            }
+
+            List<XmlSchemaTypeInfo> childTypes = new ArrayList<XmlSchemaTypeInfo>(baseTypes.size());
+
+            for (XmlSchemaSimpleType baseType : baseTypes) {
+                XmlSchemaScope parentScope = getScope(baseType);
+                if (parentScope.getTypeInfo().getType().equals(XmlSchemaTypeInfo.Type.UNION)) {
+                    childTypes.addAll(parentScope.getTypeInfo().getChildTypes());
+                } else {
+                    childTypes.add(parentScope.getTypeInfo());
+                }
+            }
+
+            typeInfo = new XmlSchemaTypeInfo(childTypes);
+
+        } else if (content instanceof XmlSchemaSimpleTypeRestriction) {
+            final XmlSchemaSimpleTypeRestriction restr = (XmlSchemaSimpleTypeRestriction)content;
+
+            final List<XmlSchemaFacet> facets = restr.getFacets();
+
+            XmlSchemaTypeInfo parentTypeInfo = null;
+
+            if (XmlSchemaBaseSimpleType.isBaseSimpleType(simpleType.getQName())) {
+                // If this is a base simple type, use it!
+                typeInfo = new XmlSchemaTypeInfo(XmlSchemaBaseSimpleType.getBaseSimpleTypeFor(simpleType
+                    .getQName()), mergeFacets(null, facets));
+
+            } else {
+                XmlSchemaSimpleType baseType = restr.getBaseType();
+                if (baseType == null) {
+                    XmlSchema schema = schemasByNamespace.get(restr.getBaseTypeName().getNamespaceURI());
+                    baseType = (XmlSchemaSimpleType)schema.getTypeByName(restr.getBaseTypeName());
+                }
+
+                if (baseType != null) {
+                    final XmlSchemaScope parentScope = getScope(baseType);
+
+                    /*
+                     * We need to track the original type as well as the set of
+                     * facets imposed on that type. Once the recursion ends, and
+                     * we make it all the way back to the first scope, the user
+                     * of this type info will know the derived type and all of
+                     * its imposed facets. Unions can restrict unions, lists can
+                     * restrict lists, and atomic types restrict other atomic
+                     * types. We need to follow all of these too.
+                     */
+                    parentTypeInfo = parentScope.getTypeInfo();
+
+                    HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> mergedFacets = mergeFacets(parentTypeInfo
+                                                                                                                  .getFacets(),
+                                                                                                              facets);
+
+                    typeInfo = restrictTypeInfo(parentTypeInfo, mergedFacets);
+
+                } else {
+                    throw new IllegalArgumentException("Unrecognized base type for "
+                                                       + getName(simpleType, "{Anonymous Simple Type}"));
+                }
+            }
+
+            typeInfo.setUserRecognizedType(getUserRecognizedType(simpleType.getQName(), parentTypeInfo));
+
+        } else {
+            throw new IllegalArgumentException("XmlSchemaSimpleType "
+                                               + getName(simpleType, "{Anonymous Simple Type}")
+                                               + "contains unrecognized XmlSchemaSimpleTypeContent "
+                                               + content.getClass().getName());
+        }
+    }
+
+    private void walk(XmlSchemaComplexType complexType) {
+        XmlSchemaContent complexContent = (complexType.getContentModel() != null) ? complexType
+            .getContentModel().getContent() : null;
+
+        /*
+         * Process the complex type extensions and restrictions. If there aren't
+         * any, the content is be defined by the particle.
+         */
+        if (complexContent != null) {
+            boolean isMixed = false;
+            if (complexType.isMixed()) {
+                isMixed = complexType.isMixed();
+            } else if (complexType.getContentModel() instanceof XmlSchemaComplexContent) {
+                isMixed = ((XmlSchemaComplexContent)complexType.getContentModel()).isMixed();
+            }
+
+            walk(isMixed, complexContent);
+
+        } else {
+            child = complexType.getParticle();
+            attributes = createAttributeMap(complexType.getAttributes());
+            anyAttr = complexType.getAnyAttribute();
+            typeInfo = new XmlSchemaTypeInfo(complexType.isMixed());
+        }
+    }
+
+    private void walk(boolean isMixed, XmlSchemaContent content) {
+        if (content instanceof XmlSchemaComplexContentExtension) {
+            XmlSchemaComplexContentExtension ext = (XmlSchemaComplexContentExtension)content;
+
+            XmlSchema schema = schemasByNamespace.get(ext.getBaseTypeName().getNamespaceURI());
+            XmlSchemaType baseType = schema.getTypeByName(ext.getBaseTypeName());
+
+            XmlSchemaParticle baseParticle = null;
+            XmlSchemaAnyAttribute baseAnyAttr = null;
+            XmlSchemaScope parentScope = null;
+
+            if (baseType != null) {
+                /*
+                 * Complex content extensions add attributes and elements in
+                 * addition to what was retrieved from the parent. Since there
+                 * will be no collisions, it is safe to perform a straight add.
+                 */
+                parentScope = getScope(baseType);
+                attributes = createAttributeMap(ext.getAttributes());
+
+                if (attributes == null) {
+                    attributes = parentScope.attributes;
+                } else if (parentScope.attributes != null) {
+                    attributes.putAll(parentScope.attributes);
+                }
+
+                baseParticle = parentScope.getParticle();
+                baseAnyAttr = parentScope.anyAttr;
+            }
+
+            /*
+             * An extension of a complex type is equivalent to creating a
+             * sequence of two particles: the parent particle followed by the
+             * child particle.
+             */
+            if (ext.getParticle() == null) {
+                child = baseParticle;
+            } else if (baseParticle == null) {
+                child = ext.getParticle();
+            } else {
+                XmlSchemaSequence seq = new XmlSchemaSequence();
+                seq.getItems().add((XmlSchemaSequenceMember)baseParticle);
+                seq.getItems().add((XmlSchemaSequenceMember)ext.getParticle());
+                child = seq;
+            }
+
+            /*
+             * An extension of an anyAttribute means the child defines the
+             * processContents field, while a union of all namespaces between
+             * the parent and child is taken.
+             */
+            if (baseAnyAttr == null) {
+                anyAttr = ext.getAnyAttribute();
+            } else if (ext.getAnyAttribute() == null) {
+                anyAttr = baseAnyAttr;
+            } else {
+                String[] baseNamespaces = baseAnyAttr.getNamespace().split(" ");
+                String[] childNamespaces = ext.getAnyAttribute().getNamespace().split(" ");
+
+                HashSet<String> namespaces = new HashSet<String>();
+                for (String baseNs : baseNamespaces) {
+                    if (baseNs.length() > 0) {
+                        namespaces.add(baseNs);
+                    }
+                }
+                for (String childNs : childNamespaces) {
+                    if (childNs.length() > 0) {
+                        namespaces.add(childNs);
+                    }
+                }
+
+                StringBuilder nsAsString = new StringBuilder();
+                for (String namespace : namespaces) {
+                    nsAsString.append(namespace).append(" ");
+                }
+
+                anyAttr = new XmlSchemaAnyAttribute();
+                anyAttr.setNamespace(nsAsString.toString());
+                anyAttr.setProcessContent(ext.getAnyAttribute().getProcessContent());
+                anyAttr.setAnnotation(ext.getAnyAttribute().getAnnotation());
+                anyAttr.setId(ext.getAnyAttribute().getId());
+                anyAttr.setLineNumber(ext.getAnyAttribute().getLineNumber());
+                anyAttr.setLinePosition(ext.getAnyAttribute().getLinePosition());
+                anyAttr.setMetaInfoMap(ext.getAnyAttribute().getMetaInfoMap());
+                anyAttr.setSourceURI(ext.getAnyAttribute().getSourceURI());
+                anyAttr.setUnhandledAttributes(ext.getUnhandledAttributes());
+            }
+
+            final XmlSchemaTypeInfo parentTypeInfo = (parentScope == null) ? null : parentScope.getTypeInfo();
+
+            if ((parentTypeInfo != null) && !parentTypeInfo.getType().equals(XmlSchemaTypeInfo.Type.COMPLEX)) {
+                typeInfo = parentScope.getTypeInfo();
+            } else {
+                typeInfo = new XmlSchemaTypeInfo(isMixed);
+            }
+
+        } else if (content instanceof XmlSchemaComplexContentRestriction) {
+            final XmlSchemaComplexContentRestriction rstr = (XmlSchemaComplexContentRestriction)content;
+
+            final XmlSchema schema = schemasByNamespace.get(rstr.getBaseTypeName().getNamespaceURI());
+
+            final XmlSchemaType baseType = schema.getTypeByName(rstr.getBaseTypeName());
+
+            XmlSchemaScope parentScope = null;
+            if (baseType != null) {
+                parentScope = getScope(baseType);
+
+                attributes = mergeAttributes(parentScope.attributes, createAttributeMap(rstr.getAttributes()));
+
+                child = parentScope.getParticle();
+            }
+
+            /*
+             * There is no inheritance when restricting particles. If the schema
+             * writer wishes to include elements in the parent type, (s)he must
+             * redefine them in the child.
+             */
+            if (rstr.getParticle() != null) {
+                child = rstr.getParticle();
+            }
+
+            /*
+             * There is no inheritance when restricting attribute wildcards. The
+             * only requirement is that the namespaces of the restricted type is
+             * a subset of the namespaces of the base type. This will not be
+             * checked here (all schemas are assumed correct).
+             */
+            anyAttr = rstr.getAnyAttribute();
+
+            final XmlSchemaTypeInfo parentTypeInfo = (parentScope == null) ? null : parentScope.getTypeInfo();
+
+            if ((parentTypeInfo != null) && !parentTypeInfo.getType().equals(XmlSchemaTypeInfo.Type.COMPLEX)) {
+                typeInfo = parentTypeInfo;
+            } else {
+                typeInfo = new XmlSchemaTypeInfo(isMixed);
+            }
+
+        } else if (content instanceof XmlSchemaSimpleContentExtension) {
+            XmlSchemaSimpleContentExtension ext = (XmlSchemaSimpleContentExtension)content;
+            attributes = createAttributeMap(ext.getAttributes());
+
+            XmlSchema schema = schemasByNamespace.get(ext.getBaseTypeName().getNamespaceURI());
+            XmlSchemaType baseType = schema.getTypeByName(ext.getBaseTypeName());
+
+            if (baseType != null) {
+                final XmlSchemaScope parentScope = getScope(baseType);
+                typeInfo = parentScope.getTypeInfo();
+
+                if (attributes == null) {
+                    attributes = parentScope.attributes;
+                } else if (parentScope.attributes != null) {
+                    attributes.putAll(parentScope.attributes);
+                }
+            }
+
+            anyAttr = ext.getAnyAttribute();
+
+        } else if (content instanceof XmlSchemaSimpleContentRestriction) {
+            XmlSchemaSimpleContentRestriction rstr = (XmlSchemaSimpleContentRestriction)content;
+            attributes = createAttributeMap(rstr.getAttributes());
+
+            XmlSchemaType baseType = null;
+            if (rstr.getBaseType() != null) {
+                baseType = rstr.getBaseType();
+            } else {
+                XmlSchema schema = schemasByNamespace.get(rstr.getBaseTypeName().getNamespaceURI());
+                baseType = schema.getTypeByName(rstr.getBaseTypeName());
+            }
+
+            if (baseType != null) {
+                XmlSchemaScope parentScope = getScope(baseType);
+                typeInfo = restrictTypeInfo(parentScope.getTypeInfo(),
+                                            mergeFacets(parentScope.getTypeInfo().getFacets(),
+                                                        rstr.getFacets()));
+
+                attributes = mergeAttributes(parentScope.attributes, attributes);
+            }
+
+            anyAttr = rstr.getAnyAttribute();
+        }
+    }
+
+    private ArrayList<XmlSchemaAttrInfo> getAttributesOf(XmlSchemaAttributeGroupRef groupRef) {
+
+        XmlSchemaAttributeGroup attrGroup = groupRef.getRef().getTarget();
+        if (attrGroup == null) {
+            XmlSchema schema = schemasByNamespace.get(groupRef.getTargetQName().getNamespaceURI());
+            attrGroup = schema.getAttributeGroupByName(groupRef.getTargetQName());
+        }
+        return getAttributesOf(attrGroup);
+    }
+
+    private ArrayList<XmlSchemaAttrInfo> getAttributesOf(XmlSchemaAttributeGroup attrGroup) {
+
+        ArrayList<XmlSchemaAttrInfo> attrs = new ArrayList<XmlSchemaAttrInfo>(attrGroup.getAttributes()
+            .size());
+
+        for (XmlSchemaAttributeGroupMember member : attrGroup.getAttributes()) {
+            if (member instanceof XmlSchemaAttribute) {
+                attrs.add(getAttribute((XmlSchemaAttribute)member, false));
+
+            } else if (member instanceof XmlSchemaAttributeGroup) {
+                attrs.addAll(getAttributesOf((XmlSchemaAttributeGroup)member));
+
+            } else if (member instanceof XmlSchemaAttributeGroupRef) {
+                attrs.addAll(getAttributesOf((XmlSchemaAttributeGroupRef)member));
+
+            } else {
+                throw new IllegalArgumentException("Attribute Group "
+                                                   + getName(attrGroup, "{Anonymous Attribute Group}")
+                                                   + " contains unrecognized attribute group memeber type "
+                                                   + member.getClass().getName());
+            }
+        }
+
+        return attrs;
+    }
+
+    private XmlSchemaAttrInfo getAttribute(XmlSchemaAttribute attribute, boolean forceCopy) {
+
+        if (!attribute.isRef() && (attribute.getSchemaType() != null) && !forceCopy) {
+
+            if (attribute.getUse().equals(XmlSchemaUse.NONE)) {
+                attribute.setUse(XmlSchemaUse.OPTIONAL);
+            }
+
+            return new XmlSchemaAttrInfo(attribute);
+        }
+
+        XmlSchemaAttribute globalAttr = null;
+        QName attrQName = null;
+
+        if (attribute.isRef()) {
+            attrQName = attribute.getRefBase().getTargetQName();
+        } else {
+            attrQName = attribute.getQName();
+        }
+        final XmlSchema schema = schemasByNamespace.get(attrQName.getNamespaceURI());
+
+        if (!attribute.isRef() && (forceCopy || (attribute.getSchemaType() == null))) {
+            // If we are forcing a copy, there is no reference to follow.
+            globalAttr = attribute;
+        } else {
+            if (attribute.getRef().getTarget() != null) {
+                globalAttr = attribute.getRef().getTarget();
+            } else {
+                globalAttr = schema.getAttributeByName(attrQName);
+            }
+        }
+
+        XmlSchemaSimpleType schemaType = globalAttr.getSchemaType();
+        if (schemaType == null) {
+            final QName typeQName = globalAttr.getSchemaTypeName();
+            XmlSchema typeSchema = schemasByNamespace.get(typeQName.getNamespaceURI());
+            schemaType = (XmlSchemaSimpleType)typeSchema.getTypeByName(typeQName);
+        }
+
+        /*
+         * The attribute reference defines the attribute use and overrides the
+         * ID, default, and fixed fields. Everything else is defined by the
+         * global attribute.
+         */
+        String fixedValue = attribute.getFixedValue();
+        if ((fixedValue != null) && (attribute != globalAttr)) {
+            fixedValue = globalAttr.getFixedValue();
+        }
+
+        String defaultValue = attribute.getDefaultValue();
+        if ((defaultValue == null) && (fixedValue == null) && (attribute != globalAttr)) {
+            defaultValue = globalAttr.getDefaultValue();
+        }
+
+        String id = attribute.getId();
+        if ((id == null) && (attribute != globalAttr)) {
+            id = globalAttr.getId();
+        }
+
+        XmlSchemaUse attrUsage = attribute.getUse();
+        if (attrUsage.equals(XmlSchemaUse.NONE)) {
+            attrUsage = XmlSchemaUse.OPTIONAL;
+        }
+
+        final XmlSchemaAttribute copy = new XmlSchemaAttribute(schema, false);
+        copy.setName(globalAttr.getName());
+
+        copy.setAnnotation(globalAttr.getAnnotation());
+        copy.setDefaultValue(defaultValue);
+        copy.setFixedValue(fixedValue);
+        copy.setForm(globalAttr.getForm());
+        copy.setId(id);
+        copy.setLineNumber(attribute.getLineNumber());
+        copy.setLinePosition(attribute.getLinePosition());
+        copy.setMetaInfoMap(globalAttr.getMetaInfoMap());
+        copy.setSchemaType(schemaType);
+        copy.setSchemaTypeName(globalAttr.getSchemaTypeName());
+        copy.setSourceURI(globalAttr.getSourceURI());
+        copy.setUnhandledAttributes(globalAttr.getUnhandledAttributes());
+        copy.setUse(attrUsage);
+
+        return new XmlSchemaAttrInfo(copy, globalAttr.isTopLevel());
+    }
+
+    private HashMap<QName, XmlSchemaAttrInfo> createAttributeMap(Collection<? extends XmlSchemaAttributeOrGroupRef> attrs) {
+
+        if ((attrs == null) || attrs.isEmpty()) {
+            return null;
+        }
+
+        HashMap<QName, XmlSchemaAttrInfo> attributes = new HashMap<QName, XmlSchemaAttrInfo>();
+
+        for (XmlSchemaAttributeOrGroupRef attr : attrs) {
+
+            if (attr instanceof XmlSchemaAttribute) {
+                XmlSchemaAttrInfo attribute = getAttribute((XmlSchemaAttribute)attr, false);
+
+                attributes.put(attribute.getAttribute().getQName(), attribute);
+
+            } else if (attr instanceof XmlSchemaAttributeGroupRef) {
+                final List<XmlSchemaAttrInfo> attrList = getAttributesOf((XmlSchemaAttributeGroupRef)attr);
+
+                for (XmlSchemaAttrInfo attribute : attrList) {
+                    attributes.put(attribute.getAttribute().getQName(), attribute);
+                }
+            }
+        }
+
+        return attributes;
+    }
+
+    private HashMap<QName, XmlSchemaAttrInfo> mergeAttributes(HashMap<QName, XmlSchemaAttrInfo> parentAttrs,
+                                                              HashMap<QName, XmlSchemaAttrInfo> childAttrs) {
+
+        if ((parentAttrs == null) || parentAttrs.isEmpty()) {
+            return childAttrs;
+        } else if ((childAttrs == null) || childAttrs.isEmpty()) {
+            return parentAttrs;
+        }
+
+        HashMap<QName, XmlSchemaAttrInfo> newAttrs = new HashMap<QName, XmlSchemaAttrInfo>(parentAttrs);
+
+        /*
+         * Child attributes inherit all parent attributes, but may change the
+         * type, usage, default value, or fixed value.
+         */
+        for (Map.Entry<QName, XmlSchemaAttrInfo> parentAttrEntry : parentAttrs.entrySet()) {
+
+            XmlSchemaAttrInfo parentAttr = parentAttrEntry.getValue();
+            XmlSchemaAttrInfo childAttr = childAttrs.get(parentAttrEntry.getKey());
+            if (childAttr != null) {
+                XmlSchemaAttrInfo newAttr = getAttribute(parentAttr.getAttribute(), true);
+
+                if (childAttr.getAttribute().getSchemaType() != null) {
+                    newAttr.getAttribute().setSchemaType(childAttr.getAttribute().getSchemaType());
+                }
+
+                if (childAttr.getAttribute().getUse() != XmlSchemaUse.NONE) {
+                    newAttr.getAttribute().setUse(childAttr.getAttribute().getUse());
+                }
+
+                // Attribute values may be defaulted or fixed, but not both.
+                if (childAttr.getAttribute().getDefaultValue() != null) {
+                    newAttr.getAttribute().setDefaultValue(childAttr.getAttribute().getDefaultValue());
+                    newAttr.getAttribute().setFixedValue(null);
+
+                } else if (childAttr.getAttribute().getFixedValue() != null) {
+                    newAttr.getAttribute().setFixedValue(childAttr.getAttribute().getFixedValue());
+                    newAttr.getAttribute().setDefaultValue(null);
+                }
+
+                newAttrs.put(newAttr.getAttribute().getQName(), newAttr);
+            }
+        }
+
+        return newAttrs;
+    }
+
+    private XmlSchemaScope getScope(XmlSchemaType type) {
+        if ((type.getQName() != null) && scopeCache.containsKey(type.getQName())) {
+            return scopeCache.get(type.getQName());
+        } else {
+            XmlSchemaScope scope = new XmlSchemaScope(this, type);
+            if (type.getQName() != null) {
+                scopeCache.put(type.getQName(), scope);
+            }
+            return scope;
+        }
+    }
+
+    private QName getUserRecognizedType(QName simpleType, XmlSchemaTypeInfo parent) {
+
+        if (userRecognizedTypes == null) {
+            return null;
+        } else if (simpleType == null) {
+            return (parent == null) ? null : parent.getUserRecognizedType();
+
+        } else if (userRecognizedTypes.contains(simpleType)) {
+            return simpleType;
+        }
+
+        if (XmlSchemaBaseSimpleType.isBaseSimpleType(simpleType)) {
+
+            boolean checkAnyType = true;
+            boolean checkAnySimpleType = true;
+            switch (XmlSchemaBaseSimpleType.getBaseSimpleTypeFor(simpleType)) {
+            case ANYTYPE:
+                checkAnyType = false;
+            case ANYSIMPLETYPE:
+                checkAnySimpleType = false;
+            default:
+            }
+
+            if (checkAnySimpleType) {
+                final QName anySimpleType = XmlSchemaBaseSimpleType.ANYSIMPLETYPE.getQName();
+                if (userRecognizedTypes.contains(anySimpleType)) {
+                    return anySimpleType;
+                }
+            }
+
+            if (checkAnyType) {
+                final QName anyType = XmlSchemaBaseSimpleType.ANYTYPE.getQName();
+                if (userRecognizedTypes.contains(anyType)) {
+                    return anyType;
+                }
+            }
+        }
+
+        return (parent == null) ? null : parent.getUserRecognizedType();
+    }
+
+    private static String getName(XmlSchemaNamed name, String defaultName) {
+        if (name.isAnonymous()) {
+            return defaultName;
+        } else {
+            return name.getName();
+        }
+    }
+
+    private static HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> mergeFacets(HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> parentFacets,
+                                                                                              List<XmlSchemaFacet> child) {
+
+        if ((child == null) || child.isEmpty()) {
+            return parentFacets;
+        }
+
+        HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> childFacets = new HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>>(
+                                                                                                                                                        child
+                                                                                                                                                            .size());
+
+        for (XmlSchemaFacet facet : child) {
+            XmlSchemaRestriction rstr = new XmlSchemaRestriction(facet);
+            List<XmlSchemaRestriction> rstrList = childFacets.get(rstr.getType());
+            if (rstrList == null) {
+                // Only enumerations may have more than one value.
+                if (rstr.getType() == XmlSchemaRestriction.Type.ENUMERATION) {
+                    rstrList = new ArrayList<XmlSchemaRestriction>(5);
+                } else {
+                    rstrList = new ArrayList<XmlSchemaRestriction>(1);
+                }
+                childFacets.put(rstr.getType(), rstrList);
+            }
+            rstrList.add(rstr);
+        }
+
+        if (parentFacets == null) {
+            return childFacets;
+        }
+
+        HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> mergedFacets 
+            = new HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>>(parentFacets);
+
+        // Child facets override parent facets
+        for (Map.Entry<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> rstrEntry : childFacets
+            .entrySet()) {
+
+            mergedFacets.put(rstrEntry.getKey(), rstrEntry.getValue());
+        }
+
+        return mergedFacets;
+    }
+
+    private static XmlSchemaTypeInfo restrictTypeInfo(XmlSchemaTypeInfo parentTypeInfo,
+                                                      HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> facets) {
+
+        XmlSchemaTypeInfo typeInfo = null;
+
+        switch (parentTypeInfo.getType()) {
+        case LIST:
+            typeInfo = new XmlSchemaTypeInfo(parentTypeInfo.getChildTypes().get(0), facets);
+            break;
+        case UNION:
+            typeInfo = new XmlSchemaTypeInfo(parentTypeInfo.getChildTypes(), facets);
+            break;
+        case ATOMIC:
+            typeInfo = new XmlSchemaTypeInfo(parentTypeInfo.getBaseType(), facets);
+            break;
+        default:
+            throw new IllegalStateException("Cannot restrict on a " + parentTypeInfo.getType() + " type.");
+        }
+
+        if (parentTypeInfo.getUserRecognizedType() != null) {
+            typeInfo.setUserRecognizedType(parentTypeInfo.getUserRecognizedType());
+        }
+
+        return typeInfo;
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaScope.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaTypeInfo.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaTypeInfo.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaTypeInfo.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaTypeInfo.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,254 @@
+/**
+ * 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.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Represents an element's or attribute's type, meaning either a
+ * {@link XmlSchemaBaseSimpleType} with facets, a union or list of them, or a
+ * complex type.
+ * <p>
+ * Also maintains a {@link QName} representing a type the user recognizes. Users
+ * attempting to convert from one schema to another may use this to track which
+ * types in XML Schema map to their own schema types.
+ * </p>
+ */
+public final class XmlSchemaTypeInfo {
+
+    private Type type;
+    private HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> facets;
+    private boolean isMixed;
+    private XmlSchemaBaseSimpleType baseSimpleType;
+    private QName userRecognizedType;
+    private List<XmlSchemaTypeInfo> childTypes;
+
+    /**
+     * What the data in this <code>XmlSchemaTypeInfo</code> represents. It may
+     * be a simple type ({@link XmlSchemaBaseSimpleType}), a list or union of
+     * simple types, or a complex type.
+     * <p>
+     * Complex types are reserved for when an element only contains attributes,
+     * or the element's children are mixed with text.
+     * </p>
+     */
+    public enum Type {
+        LIST, UNION, ATOMIC, COMPLEX;
+    }
+
+    /**
+     * Constructs a new <code>XmlSchemaTypeInfo</code> representing a list of
+     * other <code>XmlSchemaTypeInfo</code>s. Lists are homogeneous, so only one
+     * type is necessary.
+     * <p>
+     * Lists may be either of atomic types or unions of atomic types. Lists of
+     * lists are not allowed.
+     * </p>
+     *
+     * @param listType The list's type.
+     */
+    public XmlSchemaTypeInfo(XmlSchemaTypeInfo listType) {
+        type = Type.LIST;
+        childTypes = new ArrayList<XmlSchemaTypeInfo>(1);
+        childTypes.add(listType);
+
+        isMixed = false;
+        facets = null;
+        userRecognizedType = null;
+    }
+
+    /**
+     * Constructs a list with facets. Lists may be constrained by their length;
+     * meaning they may have a {@link XmlSchemaRestriction.Type#LENGTH} facet, a
+     * {@link XmlSchemaRestriction.Type#LENGTH_MIN} facet, or a
+     * {@link XmlSchemaRestriction.Type#LENGTH_MAX} facet (or both
+     * <code>LENGTH_MIN</code> and <code>LENGTH_MAX</code>).
+     *
+     * @param listType The list type.
+     * @param facets Constraining facets on the list itself.
+     */
+    public XmlSchemaTypeInfo(XmlSchemaTypeInfo listType,
+                             HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> facets) {
+        this(listType);
+        this.facets = facets;
+    }
+
+    /**
+     * Constructs a union with the set of valid types a value adhering to the
+     * union must conform to.
+     * <p>
+     * A union may either be of a set of atomic types or a set of list types,
+     * but not mixed between the two. A union of list types cannot be a type of
+     * a list.
+     * </p>
+     *
+     * @param unionTypes The set of types that a value may adhere to in order to
+     *            conform to the union.
+     */
+    public XmlSchemaTypeInfo(List<XmlSchemaTypeInfo> unionTypes) {
+        type = Type.UNION;
+        childTypes = unionTypes;
+
+        isMixed = false;
+        facets = null;
+        userRecognizedType = null;
+    }
+
+    /**
+     * Constructs a union with the set of valid types the a value adhering to
+     * the union must conform to, along with any constraining facets on the
+     * union itself.
+     *
+     * @param unionTypes The set of types that a value must adhere to.
+     * @param facets Constraining facets on the union.
+     */
+    public XmlSchemaTypeInfo(List<XmlSchemaTypeInfo> unionTypes,
+                             HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> facets) {
+        this(unionTypes);
+        this.facets = facets;
+    }
+
+    /**
+     * Constructs an atomic type with the {@link XmlSchemaBaseSimpleType}
+     * conforming values must adhere to.
+     *
+     * @param baseSimpleType The value type.
+     */
+    public XmlSchemaTypeInfo(XmlSchemaBaseSimpleType baseSimpleType) {
+        if (baseSimpleType.equals(XmlSchemaBaseSimpleType.ANYTYPE)) {
+            type = Type.COMPLEX;
+        } else {
+            type = Type.ATOMIC;
+        }
+
+        this.baseSimpleType = baseSimpleType;
+
+        isMixed = false;
+        facets = null;
+        childTypes = null;
+        userRecognizedType = null;
+    }
+
+    /**
+     * Constructs an atomic type with the {@link XmlSchemaBaseSimpleType}
+     * conforming values must adhere to, along with any additional constraining
+     * facets.
+     *
+     * @param baseSimpleType The value type.
+     * @param facets The constraining facets on the value.
+     */
+    public XmlSchemaTypeInfo(XmlSchemaBaseSimpleType baseSimpleType,
+                             HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> facets) {
+
+        this(baseSimpleType);
+        this.facets = facets;
+    }
+
+    /**
+     * Constructs a complex type whose value may or may not be mixed.
+     *
+     * @param isMixed Whether the element is a mixed type.
+     */
+    public XmlSchemaTypeInfo(boolean isMixed) {
+        type = Type.COMPLEX;
+        baseSimpleType = XmlSchemaBaseSimpleType.ANYTYPE;
+        this.isMixed = isMixed;
+
+        facets = null;
+        childTypes = null;
+        userRecognizedType = null;
+    }
+
+    /**
+     * The set of constraining facets on the value, or <code>null</code> if
+     * none.
+     */
+    public HashMap<XmlSchemaRestriction.Type, List<XmlSchemaRestriction>> getFacets() {
+        return facets;
+    }
+
+    /**
+     * If this represents an atomic type, returns the type. If this is a complex
+     * type, returns {@link XmlSchemaBaseSimpleType#ANYTYPE}.
+     */
+    public XmlSchemaBaseSimpleType getBaseType() {
+        return baseSimpleType;
+    }
+
+    /**
+     * The type represented by this <code>XmlSchemaTypeInfo</code>.
+     */
+    public Type getType() {
+        return type;
+    }
+
+    /**
+     * If this represents a list or a union, returns the set of children types.
+     * (Lists will only have one child type.)
+     * <p>
+     * Otherwise, returns <code>null</code>.
+     * </p>
+     */
+    public List<XmlSchemaTypeInfo> getChildTypes() {
+        return childTypes;
+    }
+
+    /**
+     * The corresponding user-defined type, or <code>null</code> if none.
+     */
+    public QName getUserRecognizedType() {
+        return userRecognizedType;
+    }
+
+    /**
+     * If this is a complex type, returns whether its value is mixed. Otherwise,
+     * returns <code>false</code>.
+     */
+    public boolean isMixed() {
+        return isMixed;
+    }
+
+    /**
+     * Sets the user-recognized type.
+     *
+     * @param userRecType The user-recognized type.
+     */
+    public void setUserRecognizedType(QName userRecType) {
+        userRecognizedType = userRecType;
+    }
+
+    /**
+     * A {@link String} representation of this <code>XmlSchemaTypeInfo</code>.
+     */
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder("XmlSchemaTypeInfo [");
+        str.append(type).append("] Base Type: ").append(baseSimpleType);
+        str.append(" User Recognized Type: ").append(userRecognizedType);
+        str.append(" Is Mixed: ").append(isMixed);
+        str.append(" Num Children: ");
+        str.append((childTypes == null) ? 0 : childTypes.size());
+        return str.toString();
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaTypeInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaVisitor.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaVisitor.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaVisitor.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaVisitor.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,194 @@
+/**
+ * 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 org.apache.ws.commons.schema.XmlSchemaAll;
+import org.apache.ws.commons.schema.XmlSchemaAny;
+import org.apache.ws.commons.schema.XmlSchemaAnyAttribute;
+import org.apache.ws.commons.schema.XmlSchemaChoice;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+
+/**
+ * Defines a visitor interface for notifications when walking an
+ * {@link org.apache.ws.commons.schema.XmlSchema} using the
+ * {@link XmlSchemaWalker}.
+ * <p>
+ * Use this interface in conjunction with <code>XmlSchemaWalker</code> to
+ * receive events as an {@link org.apache.ws.commons.schema.XmlSchema} is
+ * traversed.
+ * </p>
+ */
+public interface XmlSchemaVisitor {
+
+    /**
+     * A notification that an {@link XmlSchemaElement} has been entered. The
+     * element returned will be a true representation of the element at that
+     * point in the schema: if the schema defines a reference, the reference is
+     * followed and merged with its global definition.
+     * <p>
+     * The first time this element is reached, all of its attributes will be
+     * visited (if any). Once the attributes have been visited,
+     * {@link #onEndAttributes(XmlSchemaElement, XmlSchemaTypeInfo)} will be
+     * called. The only exception is when the element has no type information,
+     * at which point the next call will be to
+     * {@link #onExitElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)}.
+     * </p>
+     * <p>
+     * On all subsequent visits to this element, <code>previouslyVisited</code>
+     * will be set to <code>true</code> and the attributes will not be
+     * revisited. The next call will be to
+     * {@link #onExitElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)}, as
+     * all of the element's attributes and children have already been provided.
+     * </p>
+     *
+     * @param element The element the walker is currently entering.
+     * @param typeInfo The type information of that element.
+     * @param previouslyVisited Whether the element was previously visited.
+     */
+    void onEnterElement(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo, boolean previouslyVisited);
+
+    /**
+     * Signifies the end of the element that was previously entered. Provides
+     * the same information about the element as was provided in
+     * {@link #onEnterElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)} in
+     * the event it is easier to process on exit.
+     *
+     * @param element The element the walker is currently exiting.
+     * @param typeInfo The type information of that element.
+     * @param previouslyVisited Whether the element was previously visited.
+     */
+    void onExitElement(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo, boolean previouslyVisited);
+
+    /**
+     * This method is called for each attribute associated with the element,
+     * providing the {@link XmlSchemaAttrInfo} representing that attribute.
+     *
+     * @param element The element owing the attribute.
+     * @param attrInfo The attribute information.
+     */
+    void onVisitAttribute(XmlSchemaElement element, XmlSchemaAttrInfo attrInfo);
+
+    /**
+     * This method is called when all of the attributes have been processed
+     * (provided the element has a type defined). This is a convenience method
+     * to allow the visitor to be notified when no more attributes are coming,
+     * and the walker will be traversing the element's children.
+     *
+     * @param element The element the walker is traversing.
+     * @param typeInfo Type information about the element, if it is easier to
+     *            process here.
+     */
+    void onEndAttributes(XmlSchemaElement element, XmlSchemaTypeInfo typeInfo);
+
+    /**
+     * This method is called when the walker enters a substitution group. This
+     * method is called providing the base type, and then
+     * {@link #onEnterElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)} is
+     * called for all types in the substitution group, starting with the base
+     * type.
+     * <p>
+     * The only exception is when the base type of the substitution group is
+     * abstract ({@link XmlSchemaElement#isAbstract()} returns <code>true</code>
+     * ). When this happens,
+     * {@link #onEnterElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)} is
+     * not called with the abstract type, as there is no information to provide.
+     * </p>
+     * <p>
+     * If the root element is the base of a substitution group, this method will
+     * be the first one called. Otherwise,
+     * {@link #onEnterElement(XmlSchemaElement, XmlSchemaTypeInfo, boolean)}
+     * will be called with the root element.
+     * </p>
+     *
+     * @param base The {@link XmlSchemaElement} representing the base of the
+     *            substitution group.
+     */
+    void onEnterSubstitutionGroup(XmlSchemaElement base);
+
+    /**
+     * Called when the end of the substitution group is reached. The base
+     * element of the substitution group is provided for convenience.
+     *
+     * @param base The base element of the subtitution group.
+     */
+    void onExitSubstitutionGroup(XmlSchemaElement base);
+
+    /**
+     * Called when an all group is entered.
+     *
+     * @param all The {@link XmlSchemaAll} representing the all group.
+     */
+    void onEnterAllGroup(XmlSchemaAll all);
+
+    /**
+     * Called when an all group is exited.
+     *
+     * @param all The {@link XmlSchemaAll} representing the all group.
+     */
+    void onExitAllGroup(XmlSchemaAll all);
+
+    /**
+     * Called when a choice group is entered.
+     *
+     * @param all The {@link XmlSchemaChoice} representing the choice group.
+     */
+    void onEnterChoiceGroup(XmlSchemaChoice choice);
+
+    /**
+     * Called when a choice group is exited.
+     *
+     * @param all The {@link XmlSchemaChoice} representing the choice group.
+     */
+    void onExitChoiceGroup(XmlSchemaChoice choice);
+
+    /**
+     * Called when a sequence is entered.
+     *
+     * @param seq The {@link XmlSchemaSequence} representing the sequence.
+     */
+    void onEnterSequenceGroup(XmlSchemaSequence seq);
+
+    /**
+     * Called when a sequence is exited.
+     *
+     * @param seq The {@link XmlSchemaSequence} representing the sequence.
+     */
+    void onExitSequenceGroup(XmlSchemaSequence seq);
+
+    /**
+     * Called when a wildcard element is entered.
+     *
+     * @param any The {@link XmlSchemaAny} representing the wildcard element.
+     */
+    void onVisitAny(XmlSchemaAny any);
+
+    /**
+     * Called when a wildcard attribute is visited. If an element has a wildcard
+     * element, this will be called after all other attributes have been
+     * visited, and before the call to
+     * {@link #onEndAttributes(XmlSchemaElement, XmlSchemaTypeInfo)}.
+     *
+     * @param element The owning element.
+     * @param anyAttr The {@link XmlSchemaAnyAttribute} representing the
+     *            wildcard attribute.
+     */
+    void onVisitAnyAttribute(XmlSchemaElement element, XmlSchemaAnyAttribute anyAttr);
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaWalker.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaWalker.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaWalker.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaWalker.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,559 @@
+/**
+ * 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.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+
+import org.apache.ws.commons.schema.XmlSchema;
+import org.apache.ws.commons.schema.XmlSchemaAll;
+import org.apache.ws.commons.schema.XmlSchemaAny;
+import org.apache.ws.commons.schema.XmlSchemaChoice;
+import org.apache.ws.commons.schema.XmlSchemaCollection;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaGroup;
+import org.apache.ws.commons.schema.XmlSchemaGroupParticle;
+import org.apache.ws.commons.schema.XmlSchemaGroupRef;
+import org.apache.ws.commons.schema.XmlSchemaObject;
+import org.apache.ws.commons.schema.XmlSchemaParticle;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.XmlSchemaSequenceMember;
+import org.apache.ws.commons.schema.XmlSchemaType;
+
+/**
+ * Walks an {@link XmlSchema} from a starting {@link XmlSchemaElement},
+ * notifying attached visitors as it descends.
+ */
+public final class XmlSchemaWalker {
+
+    private Set<QName> userRecognizedTypes;
+
+    private final XmlSchemaCollection schemas;
+    private final ArrayList<XmlSchemaVisitor> visitors;
+    private final Map<QName, List<XmlSchemaElement>> elemsBySubstGroup;
+    private final Map<String, XmlSchema> schemasByNamespace;
+    private final Map<QName, XmlSchemaScope> scopeCache;
+    private final Set<QName> visitedElements;
+
+    /**
+     * Initializes the {@link XmlSchemaWalker} with the
+     * {@link XmlScheamCollection} to reference when following an
+     * {@link XmlSchemaElement}.
+     */
+    public XmlSchemaWalker(XmlSchemaCollection xmlSchemas) {
+        if (xmlSchemas == null) {
+            throw new IllegalArgumentException("Input XmlSchemaCollection cannot be null.");
+        }
+
+        schemas = xmlSchemas;
+        visitors = new ArrayList<XmlSchemaVisitor>(1);
+
+        schemasByNamespace = new HashMap<String, XmlSchema>();
+        elemsBySubstGroup = new HashMap<QName, List<XmlSchemaElement>>();
+
+        for (XmlSchema schema : schemas.getXmlSchemas()) {
+            schemasByNamespace.put(schema.getTargetNamespace(), schema);
+
+            for (XmlSchemaElement elem : schema.getElements().values()) {
+                if (elem.getSubstitutionGroup() != null) {
+                    List<XmlSchemaElement> elems = elemsBySubstGroup.get(elem.getSubstitutionGroup());
+                    if (elems == null) {
+                        elems = new ArrayList<XmlSchemaElement>();
+                        elemsBySubstGroup.put(elem.getSubstitutionGroup(), elems);
+                    }
+                    elems.add(elem);
+                }
+            }
+        }
+
+        scopeCache = new HashMap<QName, XmlSchemaScope>();
+        visitedElements = new java.util.HashSet<QName>();
+        userRecognizedTypes = null;
+    }
+
+    /**
+     * Initializes the <code>XmlSchemaWalker</code> with an
+     * {@link XmlSchemaVisitor} to notify as the schema is walked.
+     * <p>
+     * (Other visitors may continue to be added after this one.)
+     * </p>
+     *
+     * @param xmlSchemas The set of schemas to walk.
+     * @param visitor The visitor to visit during the walk.
+     */
+    public XmlSchemaWalker(XmlSchemaCollection xmlSchemas, XmlSchemaVisitor visitor) {
+
+        this(xmlSchemas);
+        if (visitor != null) {
+            visitors.add(visitor);
+        }
+    }
+
+    /**
+     * Adds a new visitor to be notified as the XML Schemas are walked.
+     *
+     * @param visitor The visitor to be notified.
+     * @return This <code>XmlSchemaWalker</code> instance for method chaining.
+     */
+    public XmlSchemaWalker addVisitor(XmlSchemaVisitor visitor) {
+        visitors.add(visitor);
+        return this;
+    }
+
+    /**
+     * Removes the visitor to be notified as the XML Schemas are walked.
+     *
+     * @param visitor The visitor to remove.
+     * @return This <code>XmlSchemaWalker</code> instance for method chaining.
+     */
+    public XmlSchemaWalker removeVisitor(XmlSchemaVisitor visitor) {
+        if (visitor != null) {
+            visitors.remove(visitor);
+        }
+        return this;
+    }
+
+    /**
+     * Clears the internal state in preparation for another walk through the
+     * schema.
+     */
+    public void clear() {
+        scopeCache.clear();
+        visitedElements.clear();
+    }
+
+    /**
+     * Defines the set of types the calling code recognizes. If one of the types
+     * are found during the walk through the XML Schema, it is attached to the
+     * relevant {@link XmlSchemaTypeInfo} that is passed to the
+     * {@link XmlSchemaVisitor}s, with lower types in the hierarchy taking
+     * precedence over higher types.
+     * <p>
+     * This information is useful when translating from XML Schema to another
+     * schema, as this automatically associates the destination type with the
+     * source XML Schema type.
+     * </p>
+     *
+     * @param userRecognizedTypes The set of types the user recognizes and would
+     *            like recognized when traversed.
+     */
+    public void setUserRecognizedTypes(Set<QName> userRecognizedTypes) {
+        this.userRecognizedTypes = userRecognizedTypes;
+    }
+
+    /**
+     * The user-defined types set with the call to
+     * {@link #setUserRecognizedTypes(Set)}, or <code>null</code> if none.
+     */
+    public Set<QName> getUserRecognizedTypes() {
+        return userRecognizedTypes;
+    }
+
+    /**
+     * Initiates a walk through the {@link XmlSchemaCollection} starting with
+     * the provided root {@link XmlSchemaElement}. Any visitors will be notified
+     * as the walk progresses.
+     * <p>
+     * Once this method completes, call {@link #clear()} before starting another
+     * walk through the XML Schemas.
+     * </p>
+     *
+     * @param element The root element to start the walk from.
+     */
+    public void walk(XmlSchemaElement element) {
+        element = getElement(element, false);
+
+        final XmlSchemaElement substGroupElem = element;
+
+        /*
+         * If this element is the root of a substitution group, notify the
+         * visitors.
+         */
+        List<XmlSchemaElement> substitutes = null;
+        if (elemsBySubstGroup.containsKey(getElementQName(element))) {
+            substitutes = elemsBySubstGroup.get(element.getQName());
+
+            for (XmlSchemaVisitor visitor : visitors) {
+                visitor.onEnterSubstitutionGroup(substGroupElem);
+            }
+
+            // Force a copy to change the min & max occurs.
+            element = getElement(element, true);
+            element.setMinOccurs(XmlSchemaParticle.DEFAULT_MIN_OCCURS);
+            element.setMaxOccurs(XmlSchemaParticle.DEFAULT_MAX_OCCURS);
+        }
+
+        XmlSchemaType schemaType = element.getSchemaType();
+        if (schemaType == null) {
+            final QName typeQName = element.getSchemaTypeName();
+            if (typeQName != null) {
+                XmlSchema schema = schemasByNamespace.get(typeQName.getNamespaceURI());
+                schemaType = schema.getTypeByName(typeQName);
+            }
+        }
+
+        if (schemaType != null) {
+            XmlSchemaScope scope = null;
+            if ((schemaType.getQName() != null) && scopeCache.containsKey(schemaType.getQName())) {
+                scope = scopeCache.get(schemaType.getQName());
+            } else {
+                scope = new XmlSchemaScope(schemaType, schemasByNamespace, scopeCache, userRecognizedTypes);
+                if (schemaType.getQName() != null) {
+                    scopeCache.put(schemaType.getQName(), scope);
+                }
+            }
+
+            // 1. Fetch all attributes as a List<XmlSchemaAttribute>.
+            final Collection<XmlSchemaAttrInfo> attrs = scope.getAttributesInScope();
+            final XmlSchemaTypeInfo typeInfo = scope.getTypeInfo();
+
+            // 2. for each visitor, call visitor.startElement(element, type);
+            final boolean previouslyVisited = (!element.isAnonymous() && visitedElements.contains(element
+                .getQName()));
+
+            for (XmlSchemaVisitor visitor : visitors) {
+                visitor.onEnterElement(element, typeInfo, previouslyVisited);
+            }
+
+            if (!element.isAnonymous() && !previouslyVisited) {
+                visitedElements.add(element.getQName());
+            }
+
+            // If we already visited this element, skip the attributes and
+            // child.
+            if (!previouslyVisited) {
+
+                // 3. Walk the attributes in the element, retrieving type
+                // information.
+                if (attrs != null) {
+                    for (XmlSchemaAttrInfo attr : attrs) {
+                        XmlSchemaType attrType = attr.getAttribute().getSchemaType();
+                        XmlSchemaScope attrScope = null;
+                        if ((attrType.getQName() != null) && scopeCache.containsKey(attrType.getQName())) {
+                            attrScope = scopeCache.get(attrType.getQName());
+                        } else {
+                            attrScope = new XmlSchemaScope(attr.getAttribute().getSchemaType(),
+                                                           schemasByNamespace, scopeCache,
+                                                           userRecognizedTypes);
+
+                            if (attrType.getName() != null) {
+                                scopeCache.put(attrType.getQName(), attrScope);
+                            }
+                        }
+
+                        final XmlSchemaTypeInfo attrTypeInfo = attrScope.getTypeInfo();
+                        attr.setType(attrTypeInfo);
+
+                        for (XmlSchemaVisitor visitor : visitors) {
+                            visitor.onVisitAttribute(element, attr);
+                        }
+                    }
+                }
+
+                // 4. Visit the anyAttribute, if any.
+                if (scope.getAnyAttribute() != null) {
+                    for (XmlSchemaVisitor visitor : visitors) {
+                        visitor.onVisitAnyAttribute(element, scope.getAnyAttribute());
+                    }
+                }
+
+                /*
+                 * 5. Notify that we visited all of the attributes (even if
+                 * there weren't any).
+                 */
+                for (XmlSchemaVisitor visitor : visitors) {
+                    visitor.onEndAttributes(element, typeInfo);
+                }
+
+                // 6. Walk the child groups and elements (if any), depth-first.
+                final XmlSchemaParticle child = scope.getParticle();
+                if (child != null) {
+                    walk(child);
+                }
+            }
+
+            /*
+             * 7. On the way back up, call visitor.endElement(element, type,
+             * attributes);
+             */
+            for (XmlSchemaVisitor visitor : visitors) {
+                visitor.onExitElement(element, typeInfo, previouslyVisited);
+            }
+
+        } else if (!element.isAbstract()) {
+            throw new IllegalStateException("Element " + element.getQName()
+                                            + " is not abstract and has no type.");
+        }
+
+        // 8. Now handle substitute elements, if any.
+        if (substitutes != null) {
+            for (XmlSchemaElement substitute : substitutes) {
+                walk(substitute);
+            }
+
+            for (XmlSchemaVisitor visitor : visitors) {
+                visitor.onExitSubstitutionGroup(substGroupElem);
+            }
+        }
+    }
+
+    private void walk(XmlSchemaParticle particle) {
+        if (particle instanceof XmlSchemaGroupRef) {
+            XmlSchemaGroupRef groupRef = (XmlSchemaGroupRef)particle;
+            XmlSchemaGroupParticle group = groupRef.getParticle();
+            if (group == null) {
+                XmlSchema schema = schemasByNamespace.get(groupRef.getRefName().getNamespaceURI());
+
+                group = schema.getGroupByName(groupRef.getRefName()).getParticle();
+            }
+            walk(group, groupRef.getMinOccurs(), groupRef.getMaxOccurs());
+
+        } else if (particle instanceof XmlSchemaGroupParticle) {
+            walk((XmlSchemaGroupParticle)particle, particle.getMinOccurs(), particle.getMaxOccurs());
+
+        } else if (particle instanceof XmlSchemaElement) {
+            walk((XmlSchemaElement)particle);
+
+        } else if (particle instanceof XmlSchemaAny) {
+            for (XmlSchemaVisitor visitor : visitors) {
+                visitor.onVisitAny((XmlSchemaAny)particle);
+            }
+
+        } else {
+            throw new IllegalArgumentException("Unknown particle type " + particle.getClass().getName());
+        }
+
+    }
+
+    private void walk(XmlSchemaGroupParticle group, long minOccurs, long maxOccurs) {
+
+        // Only make a copy of the particle if the minOccurs or maxOccurs was
+        // set.
+        final boolean forceCopy = ((minOccurs != group.getMinOccurs()) || (maxOccurs != group.getMaxOccurs()));
+
+        // 1. Determine the group particle type.
+        XmlSchemaAll all = null;
+        XmlSchemaChoice choice = null;
+        XmlSchemaSequence seq = null;
+
+        ArrayList<XmlSchemaParticle> children = null;
+
+        if (group instanceof XmlSchemaAll) {
+            all = (XmlSchemaAll)group;
+
+        } else if (group instanceof XmlSchemaChoice) {
+            choice = (XmlSchemaChoice)group;
+
+        } else if (group instanceof XmlSchemaSequence) {
+            seq = (XmlSchemaSequence)group;
+
+        } else {
+            throw new IllegalArgumentException("Unrecognized XmlSchemaGroupParticle of type "
+                                               + group.getClass().getName());
+        }
+
+        // 2. Make a copy if necessary.
+        if (forceCopy) {
+            if (all != null) {
+                XmlSchemaAll copy = new XmlSchemaAll();
+                copy.setAnnotation(all.getAnnotation());
+                copy.setId(all.getId());
+                copy.setLineNumber(all.getLineNumber());
+                copy.setLinePosition(all.getLinePosition());
+                copy.setMetaInfoMap(all.getMetaInfoMap());
+                copy.setMinOccurs(minOccurs);
+                copy.setMaxOccurs(maxOccurs);
+                copy.setSourceURI(all.getSourceURI());
+                copy.setUnhandledAttributes(all.getUnhandledAttributes());
+                copy.getItems().addAll(all.getItems());
+
+                all = copy;
+
+            } else if (choice != null) {
+                XmlSchemaChoice copy = new XmlSchemaChoice();
+                copy.setAnnotation(choice.getAnnotation());
+                copy.setId(choice.getId());
+                copy.setLineNumber(choice.getLineNumber());
+                copy.setLinePosition(choice.getLinePosition());
+                copy.setMinOccurs(minOccurs);
+                copy.setMaxOccurs(maxOccurs);
+                copy.setMetaInfoMap(choice.getMetaInfoMap());
+                copy.setSourceURI(choice.getSourceURI());
+                copy.setUnhandledAttributes(choice.getUnhandledAttributes());
+                copy.getItems().addAll(choice.getItems());
+
+                choice = copy;
+
+            } else if (seq != null) {
+                XmlSchemaSequence copy = new XmlSchemaSequence();
+                copy.setAnnotation(seq.getAnnotation());
+                copy.setId(seq.getId());
+                copy.setLineNumber(seq.getLineNumber());
+                copy.setLinePosition(seq.getLinePosition());
+                copy.setMinOccurs(minOccurs);
+                copy.setMaxOccurs(maxOccurs);
+                copy.setMetaInfoMap(seq.getMetaInfoMap());
+                copy.setSourceURI(seq.getSourceURI());
+                copy.setUnhandledAttributes(seq.getUnhandledAttributes());
+
+                seq = copy;
+            }
+        }
+
+        // 3. Notify the visitors.
+        for (XmlSchemaVisitor visitor : visitors) {
+            if (all != null) {
+                visitor.onEnterAllGroup(all);
+            } else if (choice != null) {
+                visitor.onEnterChoiceGroup(choice);
+            } else if (seq != null) {
+                visitor.onEnterSequenceGroup(seq);
+            }
+        }
+
+        // 4. Walk the children.
+        if (all != null) {
+            children = new ArrayList<XmlSchemaParticle>(all.getItems().size());
+            children.addAll(all.getItems());
+
+        } else if (choice != null) {
+            children = new ArrayList<XmlSchemaParticle>(choice.getItems().size());
+            for (XmlSchemaObject item : choice.getItems()) {
+                if (item instanceof XmlSchemaGroup) {
+                    children.add(((XmlSchemaGroup)item).getParticle());
+                } else if (item instanceof XmlSchemaParticle) {
+                    children.add((XmlSchemaParticle)item);
+                } else {
+                    throw new IllegalArgumentException(
+                                                       "Choice child is not an XmlSchemaGroup or XmlSchemaParticle; "
+                                                           + "it is a " + item.getClass().getName());
+                }
+            }
+
+        } else if (seq != null) {
+            children = new ArrayList<XmlSchemaParticle>(seq.getItems().size());
+            for (XmlSchemaSequenceMember item : seq.getItems()) {
+                if (item instanceof XmlSchemaGroup) {
+                    children.add(((XmlSchemaGroup)item).getParticle());
+                } else if (item instanceof XmlSchemaParticle) {
+                    children.add((XmlSchemaParticle)item);
+                } else {
+                    throw new IllegalArgumentException(
+                                                       "Sequence child is not an XmlSchemaGroup or XmlSchemaParticle; "
+                                                           + "it is a " + item.getClass().getName());
+                }
+            }
+        }
+
+        if (children == null) {
+            throw new IllegalStateException("Could not process group of type " + group.getClass().getName());
+        }
+
+        for (XmlSchemaParticle child : children) {
+            walk(child);
+        }
+
+        // 5. Notify the visitors we are exiting the group.
+        for (XmlSchemaVisitor visitor : visitors) {
+            if (all != null) {
+                visitor.onExitAllGroup(all);
+            } else if (choice != null) {
+                visitor.onExitChoiceGroup(choice);
+            } else if (seq != null) {
+                visitor.onExitSequenceGroup(seq);
+            }
+        }
+    }
+
+    /**
+     * If the provided {@link XmlSchemaElement} is a reference, track down the
+     * original and add the minimum and maximum occurrence fields. Otherwise,
+     * just return the provided <code>element</code>.
+     *
+     * @param element The element to get the definition of.
+     * @return The real {@link XmlSchemaElement}.
+     */
+    private XmlSchemaElement getElement(XmlSchemaElement element, boolean isSubstitutionGroup) {
+
+        if (!element.isRef() && !isSubstitutionGroup) {
+            return element;
+        }
+
+        final QName elemQName = getElementQName(element);
+        final XmlSchema schema = schemasByNamespace.get(elemQName.getNamespaceURI());
+
+        XmlSchemaElement globalElem = null;
+        if (!element.isRef()) {
+            globalElem = element;
+        } else if (element.getRef().getTarget() != null) {
+            globalElem = element.getRef().getTarget();
+        } else {
+            globalElem = schema.getElementByName(elemQName);
+        }
+
+        /*
+         * An XML Schema element reference defines the id, minOccurs, and
+         * maxOccurs attributes, while the global element definition defines id
+         * and all other attributes. This combines the two together.
+         */
+        String id = element.getId();
+        if (id == null) {
+            id = globalElem.getId();
+        }
+
+        final XmlSchemaElement copy = new XmlSchemaElement(schema, false);
+        copy.setName(globalElem.getName());
+        copy.setAbstract(globalElem.isAbstract());
+        copy.setAnnotation(globalElem.getAnnotation());
+        copy.setBlock(globalElem.getBlock());
+        copy.setDefaultValue(globalElem.getDefaultValue());
+        copy.setFinal(globalElem.getFinal());
+        copy.setFixedValue(globalElem.getFixedValue());
+        copy.setForm(globalElem.getForm());
+        copy.setId(id);
+        copy.setLineNumber(element.getLineNumber());
+        copy.setLinePosition(element.getLinePosition());
+        copy.setMaxOccurs(element.getMaxOccurs());
+        copy.setMinOccurs(element.getMinOccurs());
+        copy.setMetaInfoMap(globalElem.getMetaInfoMap());
+        copy.setNillable(globalElem.isNillable());
+        copy.setType(globalElem.getSchemaType());
+        copy.setSchemaTypeName(globalElem.getSchemaTypeName());
+        copy.setSourceURI(globalElem.getSourceURI());
+        copy.setSubstitutionGroup(globalElem.getSubstitutionGroup());
+        copy.setUnhandledAttributes(globalElem.getUnhandledAttributes());
+
+        return copy;
+    }
+
+    private static QName getElementQName(XmlSchemaElement element) {
+        if (element.isRef()) {
+            return element.getRefBase().getTargetQName();
+        } else {
+            return element.getQName();
+        }
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/XmlSchemaWalker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/package-info.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/package-info.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/package-info.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/package-info.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+
+/**
+ * <h1>Walking XML Schemas</h1>
+ *
+ * This package simplifies walking over an
+ * {@link org.apache.ws.commons.schema.XmlSchemaCollection}.
+ *
+ * <h2>Walking an XML Schema</h2>
+ * 
+ * {@link org.apache.ws.commons.schema.walker.XmlSchemaWalker} walks through an
+ * {@link org.apache.ws.commons.schema.XmlSchemaCollection} given a starting
+ * {@link org.apache.ws.commons.schema.XmlSchemaElement} representing the root.
+ * Instances of {@link org.apache.ws.commons.schema.walker.XmlSchemaVisitor}
+ * can be attached to receive notifications when each element, attribute, and
+ * group (subsitution group, choice group, all group, or sequence) is reached.
+ */
+package org.apache.ws.commons.schema.walker;
\ No newline at end of file

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/main/java/org/apache/ws/commons/schema/walker/package-info.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedElement.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedElement.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedElement.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedElement.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,52 @@
+/**
+ * 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.docpath;
+
+import org.apache.ws.commons.schema.walker.XmlSchemaTypeInfo;
+
+import static org.junit.Assert.*;
+
+/**
+ * This is a simpler representation of an XML element to facilitate easier
+ * testing.
+ */
+class ExpectedElement {
+
+    private XmlSchemaTypeInfo typeInfo;
+
+    ExpectedElement(XmlSchemaTypeInfo typeInfo) {
+        this.typeInfo = typeInfo;
+    }
+
+    void validate(XmlSchemaDocumentNode docNode) {
+        String qName = docNode.getStateMachineNode().getElement().getQName().toString();
+
+        XmlSchemaTypeInfo actType = docNode.getStateMachineNode().getElementType();
+
+        validate(qName, actType);
+    }
+
+    void validate(String qName, XmlSchemaTypeInfo actType) {
+        assertEquals(qName, typeInfo.getType(), actType.getType());
+        assertEquals(qName, typeInfo.getBaseType(), actType.getBaseType());
+
+        assertEquals(qName, typeInfo.getUserRecognizedType(), actType.getUserRecognizedType());
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedElement.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedNode.java
URL: http://svn.apache.org/viewvc/webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedNode.java?rev=1625632&view=auto
==============================================================================
--- webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedNode.java (added)
+++ webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedNode.java Wed Sep 17 15:32:44 2014
@@ -0,0 +1,95 @@
+/**
+ * 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.docpath;
+
+import static org.junit.Assert.*;
+
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Describes an expected element or group in the document tree.
+ */
+public class ExpectedNode {
+
+    XmlSchemaStateMachineNode.Type nodeType;
+    long minOccurs;
+    long maxOccurs;
+    List<SortedMap<Integer, ExpectedNode>> children;
+    QName elemQName;
+
+    ExpectedNode(XmlSchemaStateMachineNode.Type nodeType, long minOccurs, long maxOccurs,
+                 List<SortedMap<Integer, ExpectedNode>> children) {
+
+        this.nodeType = nodeType;
+        this.minOccurs = minOccurs;
+        this.maxOccurs = maxOccurs;
+        this.children = children;
+    }
+
+    void setElemQName(QName elemQName) {
+        this.elemQName = elemQName;
+    }
+
+    static void validate(String msg, ExpectedNode exp, XmlSchemaDocumentNode docNode,
+                         Map<QName, ExpectedElement> expElements) {
+
+        assertEquals(msg, exp.nodeType, docNode.getStateMachineNode().getNodeType());
+
+        assertEquals(msg, exp.minOccurs, docNode.getMinOccurs());
+        assertEquals(msg, exp.maxOccurs, docNode.getMaxOccurs());
+        assertEquals(msg, exp.children.size(), docNode.getIteration());
+
+        if (docNode.getStateMachineNode().getNodeType().equals(XmlSchemaStateMachineNode.Type.ELEMENT)) {
+
+            QName actQName = docNode.getStateMachineNode().getElement().getQName();
+            assertEquals(msg, exp.elemQName, actQName);
+
+            if (expElements != null) {
+                ExpectedElement expElem = expElements.get(actQName);
+                assertNotNull(msg, expElem);
+                expElem.validate(docNode);
+            }
+        }
+
+        for (int iteration = 1; iteration <= docNode.getIteration(); ++iteration) {
+            SortedMap<Integer, ExpectedNode> expected = exp.children.get(iteration - 1);
+
+            SortedMap<Integer, XmlSchemaDocumentNode> actual = docNode.getChildren(iteration);
+
+            assertEquals(msg + ", iteration=" + iteration + "; " + exp.nodeType, expected.size(),
+                         (actual == null) ? 0 : actual.size());
+
+            if (actual != null) {
+                for (Map.Entry<Integer, XmlSchemaDocumentNode> actEntry : actual.entrySet()) {
+                    ExpectedNode expNode = expected.get(actEntry.getKey());
+                    assertNotNull(msg + ", iteration=" + iteration + ", child = " + actEntry.getKey()
+                                  + ": entry " + actEntry.getKey() + " is not expected.", expNode);
+
+                    validate(msg + "\titeration=" + iteration + "child=" + actEntry.getKey() + " ("
+                             + exp.nodeType + ")", expNode, actEntry.getValue(), expElements);
+                }
+            }
+        }
+    }
+}

Propchange: webservices/xmlschema/trunk/xmlschema-walker/src/test/java/org/apache/ws/commons/schema/docpath/ExpectedNode.java
------------------------------------------------------------------------------
    svn:eol-style = native