| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Copyright 2001-2004 The Apache Software Foundation. |
| * |
| * Licensed 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 com.sun.org.apache.xerces.internal.impl.xs.traversers; |
| |
| import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar; |
| import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols; |
| import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl; |
| import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl; |
| import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl; |
| import com.sun.org.apache.xerces.internal.impl.xs.util.XInt; |
| import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl; |
| import com.sun.org.apache.xerces.internal.util.DOMUtil; |
| import com.sun.org.apache.xerces.internal.xs.XSObject; |
| import com.sun.org.apache.xerces.internal.xs.XSObjectList; |
| import org.w3c.dom.Element; |
| |
| /** |
| * @xerces.internal |
| * |
| * @author Elena Litani, IBM |
| * @author Sandy Gao, IBM |
| * @version $Id: XSDAbstractParticleTraverser.java,v 1.7 2010-11-01 04:40:02 joehw Exp $ |
| */ |
| abstract class XSDAbstractParticleTraverser extends XSDAbstractTraverser { |
| |
| XSDAbstractParticleTraverser (XSDHandler handler, |
| XSAttributeChecker gAttrCheck) { |
| super(handler, gAttrCheck); |
| } |
| |
| /** |
| * |
| * Traverse the "All" declaration |
| * |
| * <all |
| * id = ID |
| * maxOccurs = 1 : 1 |
| * minOccurs = (0 | 1) : 1> |
| * Content: (annotation? , element*) |
| * </all> |
| **/ |
| XSParticleDecl traverseAll(Element allDecl, |
| XSDocumentInfo schemaDoc, |
| SchemaGrammar grammar, |
| int allContextFlags, |
| XSObject parent) { |
| |
| // General Attribute Checking |
| |
| Object[] attrValues = fAttrChecker.checkAttributes(allDecl, false, schemaDoc); |
| |
| Element child = DOMUtil.getFirstChildElement(allDecl); |
| |
| XSAnnotationImpl annotation = null; |
| if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { |
| annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); |
| child = DOMUtil.getNextSiblingElement(child); |
| } |
| else { |
| String text = DOMUtil.getSyntheticAnnotation(allDecl); |
| if (text != null) { |
| annotation = traverseSyntheticAnnotation(allDecl, text, attrValues, false, schemaDoc); |
| } |
| } |
| String childName = null; |
| XSParticleDecl particle; |
| fPArray.pushContext(); |
| |
| for (; child != null; child = DOMUtil.getNextSiblingElement(child)) { |
| |
| particle = null; |
| childName = DOMUtil.getLocalName(child); |
| |
| // Only elements are allowed in <all> |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, PROCESSING_ALL_EL, parent); |
| } |
| else { |
| Object[] args = {"all", "(annotation?, element*)", DOMUtil.getLocalName(child)}; |
| reportSchemaError("s4s-elt-must-match.1", args, child); |
| } |
| |
| if (particle != null) |
| fPArray.addParticle(particle); |
| } |
| |
| particle = null; |
| XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; |
| XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; |
| Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; |
| |
| XSModelGroupImpl group = new XSModelGroupImpl(); |
| group.fCompositor = XSModelGroupImpl.MODELGROUP_ALL; |
| group.fParticleCount = fPArray.getParticleCount(); |
| group.fParticles = fPArray.popContext(); |
| XSObjectList annotations; |
| if (annotation != null) { |
| annotations = new XSObjectListImpl(); |
| ((XSObjectListImpl)annotations).addXSObject (annotation); |
| } else { |
| annotations = XSObjectListImpl.EMPTY_LIST; |
| } |
| group.fAnnotations = annotations; |
| particle = new XSParticleDecl(); |
| particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; |
| particle.fMinOccurs = minAtt.intValue(); |
| particle.fMaxOccurs = maxAtt.intValue(); |
| particle.fValue = group; |
| particle.fAnnotations = annotations; |
| |
| particle = checkOccurrences(particle, |
| SchemaSymbols.ELT_ALL, |
| (Element)allDecl.getParentNode(), |
| allContextFlags, |
| defaultVals.longValue()); |
| fAttrChecker.returnAttrArray(attrValues, schemaDoc); |
| |
| return particle; |
| } |
| |
| /** |
| * Traverse the Sequence declaration |
| * |
| * <sequence |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </sequence> |
| * |
| * @param seqDecl |
| * @param schemaDoc |
| * @param grammar |
| * @return |
| */ |
| XSParticleDecl traverseSequence(Element seqDecl, |
| XSDocumentInfo schemaDoc, |
| SchemaGrammar grammar, |
| int allContextFlags, |
| XSObject parent) { |
| |
| return traverseSeqChoice(seqDecl, schemaDoc, grammar, allContextFlags, false, parent); |
| } |
| |
| /** |
| * Traverse the Choice declaration |
| * |
| * <choice |
| * id = ID |
| * maxOccurs = string |
| * minOccurs = nonNegativeInteger> |
| * Content: (annotation? , (element | group | choice | sequence | any)*) |
| * </choice> |
| * |
| * @param choiceDecl |
| * @param schemaDoc |
| * @param grammar |
| * @return |
| */ |
| XSParticleDecl traverseChoice(Element choiceDecl, |
| XSDocumentInfo schemaDoc, |
| SchemaGrammar grammar, |
| int allContextFlags, |
| XSObject parent) { |
| |
| return traverseSeqChoice (choiceDecl, schemaDoc, grammar, allContextFlags, true, parent); |
| } |
| |
| /** |
| * Common traversal for <choice> and <sequence> |
| * |
| * @param decl |
| * @param schemaDoc |
| * @param grammar |
| * @param choice If traversing <choice> this parameter is true. |
| * @return |
| */ |
| private XSParticleDecl traverseSeqChoice(Element decl, |
| XSDocumentInfo schemaDoc, |
| SchemaGrammar grammar, |
| int allContextFlags, |
| boolean choice, |
| XSObject parent) { |
| |
| // General Attribute Checking |
| Object[] attrValues = fAttrChecker.checkAttributes(decl, false, schemaDoc); |
| |
| Element child = DOMUtil.getFirstChildElement(decl); |
| XSAnnotationImpl annotation = null; |
| if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) { |
| annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc); |
| child = DOMUtil.getNextSiblingElement(child); |
| } |
| else { |
| String text = DOMUtil.getSyntheticAnnotation(decl); |
| if (text != null) { |
| annotation = traverseSyntheticAnnotation(decl, text, attrValues, false, schemaDoc); |
| } |
| } |
| |
| String childName = null; |
| XSParticleDecl particle; |
| fPArray.pushContext(); |
| |
| for (;child != null;child = DOMUtil.getNextSiblingElement(child)) { |
| |
| particle = null; |
| |
| childName = DOMUtil.getLocalName(child); |
| if (childName.equals(SchemaSymbols.ELT_ELEMENT)) { |
| particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); |
| } |
| else if (childName.equals(SchemaSymbols.ELT_GROUP)) { |
| particle = fSchemaHandler.fGroupTraverser.traverseLocal(child, schemaDoc, grammar); |
| |
| // A content type of all can only appear |
| // as the content type of a complex type definition. |
| if (hasAllContent(particle)) { |
| // don't insert the "all" particle, otherwise we won't be |
| // able to create DFA from this content model |
| particle = null; |
| reportSchemaError("cos-all-limited.1.2", null, child); |
| } |
| |
| } |
| else if (childName.equals(SchemaSymbols.ELT_CHOICE)) { |
| particle = traverseChoice(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); |
| } |
| else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) { |
| particle = traverseSequence(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent); |
| } |
| else if (childName.equals(SchemaSymbols.ELT_ANY)) { |
| particle = fSchemaHandler.fWildCardTraverser.traverseAny(child, schemaDoc, grammar); |
| } |
| else { |
| Object [] args; |
| if (choice) { |
| args = new Object[]{"choice", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)}; |
| } |
| else { |
| args = new Object[]{"sequence", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)}; |
| } |
| reportSchemaError("s4s-elt-must-match.1", args, child); |
| } |
| |
| if (particle != null) |
| fPArray.addParticle(particle); |
| } |
| |
| particle = null; |
| |
| XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS]; |
| XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS]; |
| Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT]; |
| |
| XSModelGroupImpl group = new XSModelGroupImpl(); |
| group.fCompositor = choice ? XSModelGroupImpl.MODELGROUP_CHOICE : XSModelGroupImpl.MODELGROUP_SEQUENCE; |
| group.fParticleCount = fPArray.getParticleCount(); |
| group.fParticles = fPArray.popContext(); |
| XSObjectList annotations; |
| if (annotation != null) { |
| annotations = new XSObjectListImpl(); |
| ((XSObjectListImpl)annotations).addXSObject (annotation); |
| } else { |
| annotations = XSObjectListImpl.EMPTY_LIST; |
| } |
| group.fAnnotations = annotations; |
| particle = new XSParticleDecl(); |
| particle.fType = XSParticleDecl.PARTICLE_MODELGROUP; |
| particle.fMinOccurs = minAtt.intValue(); |
| particle.fMaxOccurs = maxAtt.intValue(); |
| particle.fValue = group; |
| particle.fAnnotations = annotations; |
| |
| particle = checkOccurrences(particle, |
| choice ? SchemaSymbols.ELT_CHOICE : SchemaSymbols.ELT_SEQUENCE, |
| (Element)decl.getParentNode(), |
| allContextFlags, |
| defaultVals.longValue()); |
| fAttrChecker.returnAttrArray(attrValues, schemaDoc); |
| |
| return particle; |
| } |
| |
| // Determines whether a content spec tree represents an "all" content model |
| protected boolean hasAllContent(XSParticleDecl particle) { |
| // If the content is not empty, is the top node ALL? |
| if (particle != null && particle.fType == XSParticleDecl.PARTICLE_MODELGROUP) { |
| return ((XSModelGroupImpl)particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL; |
| } |
| |
| return false; |
| } |
| |
| // the inner class: used to store particles for model groups |
| // to avoid creating a new Vector in each model group, or when traversing |
| // each model group, we use this one big array to store all particles |
| // for model groups. when the traversal finishes, this class returns an |
| // XSParticleDecl[] containing all particles for the current model group. |
| // it's possible that we need to traverse another model group while |
| // traversing one (one inside another one; referring to a global group, |
| // etc.), so we have push/pos context methods to save the same of the |
| // current traversal before starting the traversal of another model group. |
| protected static class ParticleArray { |
| // big array to contain all particles |
| XSParticleDecl[] fParticles = new XSParticleDecl[10]; |
| // the ending position of particles in the array for each context |
| // index 0 is reserved, with value 0. index 1 is used for the fist |
| // context. so that the number of particles for context 'i' can be |
| // computed simply by fPos[i] - fPos[i-1]. |
| int[] fPos = new int[5]; |
| // number of contexts |
| int fContextCount = 0; |
| |
| // start a new context (start traversing a new model group) |
| void pushContext() { |
| fContextCount++; |
| // resize position array if necessary |
| if (fContextCount == fPos.length) { |
| int newSize = fContextCount * 2; |
| int[] newArray = new int[newSize]; |
| System.arraycopy(fPos, 0, newArray, 0, fContextCount); |
| fPos = newArray; |
| } |
| // the initial ending position of the current context is the |
| // ending position of the previsous context. which means there is |
| // no particle for the current context yet. |
| fPos[fContextCount] = fPos[fContextCount-1]; |
| } |
| |
| // get the number of particles of this context (model group) |
| int getParticleCount() { |
| return fPos[fContextCount] - fPos[fContextCount-1]; |
| } |
| |
| // add a particle to the current context |
| void addParticle(XSParticleDecl particle) { |
| // resize the particle array if necessary |
| if (fPos[fContextCount] == fParticles.length) { |
| int newSize = fPos[fContextCount] * 2; |
| XSParticleDecl[] newArray = new XSParticleDecl[newSize]; |
| System.arraycopy(fParticles, 0, newArray, 0, fPos[fContextCount]); |
| fParticles = newArray; |
| } |
| fParticles[fPos[fContextCount]++] = particle; |
| } |
| |
| // end the current context, and return an array of particles |
| XSParticleDecl[] popContext() { |
| int count = fPos[fContextCount] - fPos[fContextCount-1]; |
| XSParticleDecl[] array = null; |
| if (count != 0) { |
| array = new XSParticleDecl[count]; |
| System.arraycopy(fParticles, fPos[fContextCount-1], array, 0, count); |
| // clear the particle array, to release memory |
| for (int i = fPos[fContextCount-1]; i < fPos[fContextCount]; i++) |
| fParticles[i] = null; |
| } |
| fContextCount--; |
| return array; |
| } |
| |
| } |
| |
| // the big particle array to hold all particles in model groups |
| ParticleArray fPArray = new ParticleArray(); |
| } |