001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.xs.traversers;
019:
020: import org.apache.xerces.impl.xs.SchemaGrammar;
021: import org.apache.xerces.impl.xs.SchemaSymbols;
022: import org.apache.xerces.impl.xs.XSAnnotationImpl;
023: import org.apache.xerces.impl.xs.XSModelGroupImpl;
024: import org.apache.xerces.impl.xs.XSParticleDecl;
025: import org.apache.xerces.impl.xs.util.XInt;
026: import org.apache.xerces.impl.xs.util.XSObjectListImpl;
027: import org.apache.xerces.util.DOMUtil;
028: import org.apache.xerces.xs.XSObject;
029: import org.apache.xerces.xs.XSObjectList;
030: import org.w3c.dom.Element;
031:
032: /**
033: * @xerces.internal
034: *
035: * @author Elena Litani, IBM
036: * @author Sandy Gao, IBM
037: * @version $Id: XSDAbstractParticleTraverser.java 449424 2006-09-24 16:22:30Z mrglavas $
038: */
039: abstract class XSDAbstractParticleTraverser extends
040: XSDAbstractTraverser {
041:
042: XSDAbstractParticleTraverser(XSDHandler handler,
043: XSAttributeChecker gAttrCheck) {
044: super (handler, gAttrCheck);
045: }
046:
047: /**
048: *
049: * Traverse the "All" declaration
050: *
051: * <all
052: * id = ID
053: * maxOccurs = 1 : 1
054: * minOccurs = (0 | 1) : 1>
055: * Content: (annotation? , element*)
056: * </all>
057: **/
058: XSParticleDecl traverseAll(Element allDecl,
059: XSDocumentInfo schemaDoc, SchemaGrammar grammar,
060: int allContextFlags, XSObject parent) {
061:
062: // General Attribute Checking
063:
064: Object[] attrValues = fAttrChecker.checkAttributes(allDecl,
065: false, schemaDoc);
066:
067: Element child = DOMUtil.getFirstChildElement(allDecl);
068:
069: XSAnnotationImpl annotation = null;
070: if (child != null
071: && DOMUtil.getLocalName(child).equals(
072: SchemaSymbols.ELT_ANNOTATION)) {
073: annotation = traverseAnnotationDecl(child, attrValues,
074: false, schemaDoc);
075: child = DOMUtil.getNextSiblingElement(child);
076: } else {
077: String text = DOMUtil.getSyntheticAnnotation(allDecl);
078: if (text != null) {
079: annotation = traverseSyntheticAnnotation(allDecl, text,
080: attrValues, false, schemaDoc);
081: }
082: }
083: String childName = null;
084: XSParticleDecl particle;
085: fPArray.pushContext();
086:
087: for (; child != null; child = DOMUtil
088: .getNextSiblingElement(child)) {
089:
090: particle = null;
091: childName = DOMUtil.getLocalName(child);
092:
093: // Only elements are allowed in <all>
094: if (childName.equals(SchemaSymbols.ELT_ELEMENT)) {
095: particle = fSchemaHandler.fElementTraverser
096: .traverseLocal(child, schemaDoc, grammar,
097: PROCESSING_ALL_EL, parent);
098: } else {
099: Object[] args = { "all", "(annotation?, element*)",
100: DOMUtil.getLocalName(child) };
101: reportSchemaError("s4s-elt-must-match.1", args, child);
102: }
103:
104: if (particle != null)
105: fPArray.addParticle(particle);
106: }
107:
108: particle = null;
109: XInt minAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MINOCCURS];
110: XInt maxAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS];
111: Long defaultVals = (Long) attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT];
112:
113: XSModelGroupImpl group = new XSModelGroupImpl();
114: group.fCompositor = XSModelGroupImpl.MODELGROUP_ALL;
115: group.fParticleCount = fPArray.getParticleCount();
116: group.fParticles = fPArray.popContext();
117: XSObjectList annotations;
118: if (annotation != null) {
119: annotations = new XSObjectListImpl();
120: ((XSObjectListImpl) annotations).add(annotation);
121: } else {
122: annotations = XSObjectListImpl.EMPTY_LIST;
123: }
124: group.fAnnotations = annotations;
125: particle = new XSParticleDecl();
126: particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
127: particle.fMinOccurs = minAtt.intValue();
128: particle.fMaxOccurs = maxAtt.intValue();
129: particle.fValue = group;
130: particle.fAnnotations = annotations;
131:
132: particle = checkOccurrences(particle, SchemaSymbols.ELT_ALL,
133: (Element) allDecl.getParentNode(), allContextFlags,
134: defaultVals.longValue());
135: fAttrChecker.returnAttrArray(attrValues, schemaDoc);
136:
137: return particle;
138: }
139:
140: /**
141: * Traverse the Sequence declaration
142: *
143: * <sequence
144: * id = ID
145: * maxOccurs = string
146: * minOccurs = nonNegativeInteger>
147: * Content: (annotation? , (element | group | choice | sequence | any)*)
148: * </sequence>
149: *
150: * @param seqDecl
151: * @param schemaDoc
152: * @param grammar
153: * @return
154: */
155: XSParticleDecl traverseSequence(Element seqDecl,
156: XSDocumentInfo schemaDoc, SchemaGrammar grammar,
157: int allContextFlags, XSObject parent) {
158:
159: return traverseSeqChoice(seqDecl, schemaDoc, grammar,
160: allContextFlags, false, parent);
161: }
162:
163: /**
164: * Traverse the Choice declaration
165: *
166: * <choice
167: * id = ID
168: * maxOccurs = string
169: * minOccurs = nonNegativeInteger>
170: * Content: (annotation? , (element | group | choice | sequence | any)*)
171: * </choice>
172: *
173: * @param choiceDecl
174: * @param schemaDoc
175: * @param grammar
176: * @return
177: */
178: XSParticleDecl traverseChoice(Element choiceDecl,
179: XSDocumentInfo schemaDoc, SchemaGrammar grammar,
180: int allContextFlags, XSObject parent) {
181:
182: return traverseSeqChoice(choiceDecl, schemaDoc, grammar,
183: allContextFlags, true, parent);
184: }
185:
186: /**
187: * Common traversal for <choice> and <sequence>
188: *
189: * @param decl
190: * @param schemaDoc
191: * @param grammar
192: * @param choice If traversing <choice> this parameter is true.
193: * @return
194: */
195: private XSParticleDecl traverseSeqChoice(Element decl,
196: XSDocumentInfo schemaDoc, SchemaGrammar grammar,
197: int allContextFlags, boolean choice, XSObject parent) {
198:
199: // General Attribute Checking
200: Object[] attrValues = fAttrChecker.checkAttributes(decl, false,
201: schemaDoc);
202:
203: Element child = DOMUtil.getFirstChildElement(decl);
204: XSAnnotationImpl annotation = null;
205: if (child != null
206: && DOMUtil.getLocalName(child).equals(
207: SchemaSymbols.ELT_ANNOTATION)) {
208: annotation = traverseAnnotationDecl(child, attrValues,
209: false, schemaDoc);
210: child = DOMUtil.getNextSiblingElement(child);
211: } else {
212: String text = DOMUtil.getSyntheticAnnotation(decl);
213: if (text != null) {
214: annotation = traverseSyntheticAnnotation(decl, text,
215: attrValues, false, schemaDoc);
216: }
217: }
218:
219: String childName = null;
220: XSParticleDecl particle;
221: fPArray.pushContext();
222:
223: for (; child != null; child = DOMUtil
224: .getNextSiblingElement(child)) {
225:
226: particle = null;
227:
228: childName = DOMUtil.getLocalName(child);
229: if (childName.equals(SchemaSymbols.ELT_ELEMENT)) {
230: particle = fSchemaHandler.fElementTraverser
231: .traverseLocal(child, schemaDoc, grammar,
232: NOT_ALL_CONTEXT, parent);
233: } else if (childName.equals(SchemaSymbols.ELT_GROUP)) {
234: particle = fSchemaHandler.fGroupTraverser
235: .traverseLocal(child, schemaDoc, grammar);
236:
237: // A content type of all can only appear
238: // as the content type of a complex type definition.
239: if (hasAllContent(particle)) {
240: // don't insert the "all" particle, otherwise we won't be
241: // able to create DFA from this content model
242: particle = null;
243: reportSchemaError("cos-all-limited.1.2", null,
244: child);
245: }
246:
247: } else if (childName.equals(SchemaSymbols.ELT_CHOICE)) {
248: particle = traverseChoice(child, schemaDoc, grammar,
249: NOT_ALL_CONTEXT, parent);
250: } else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) {
251: particle = traverseSequence(child, schemaDoc, grammar,
252: NOT_ALL_CONTEXT, parent);
253: } else if (childName.equals(SchemaSymbols.ELT_ANY)) {
254: particle = fSchemaHandler.fWildCardTraverser
255: .traverseAny(child, schemaDoc, grammar);
256: } else {
257: Object[] args;
258: if (choice) {
259: args = new Object[] {
260: "choice",
261: "(annotation?, (element | group | choice | sequence | any)*)",
262: DOMUtil.getLocalName(child) };
263: } else {
264: args = new Object[] {
265: "sequence",
266: "(annotation?, (element | group | choice | sequence | any)*)",
267: DOMUtil.getLocalName(child) };
268: }
269: reportSchemaError("s4s-elt-must-match.1", args, child);
270: }
271:
272: if (particle != null)
273: fPArray.addParticle(particle);
274: }
275:
276: particle = null;
277:
278: XInt minAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MINOCCURS];
279: XInt maxAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS];
280: Long defaultVals = (Long) attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT];
281:
282: XSModelGroupImpl group = new XSModelGroupImpl();
283: group.fCompositor = choice ? XSModelGroupImpl.MODELGROUP_CHOICE
284: : XSModelGroupImpl.MODELGROUP_SEQUENCE;
285: group.fParticleCount = fPArray.getParticleCount();
286: group.fParticles = fPArray.popContext();
287: XSObjectList annotations;
288: if (annotation != null) {
289: annotations = new XSObjectListImpl();
290: ((XSObjectListImpl) annotations).add(annotation);
291: } else {
292: annotations = XSObjectListImpl.EMPTY_LIST;
293: }
294: group.fAnnotations = annotations;
295: particle = new XSParticleDecl();
296: particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
297: particle.fMinOccurs = minAtt.intValue();
298: particle.fMaxOccurs = maxAtt.intValue();
299: particle.fValue = group;
300: particle.fAnnotations = annotations;
301:
302: particle = checkOccurrences(particle,
303: choice ? SchemaSymbols.ELT_CHOICE
304: : SchemaSymbols.ELT_SEQUENCE, (Element) decl
305: .getParentNode(), allContextFlags, defaultVals
306: .longValue());
307: fAttrChecker.returnAttrArray(attrValues, schemaDoc);
308:
309: return particle;
310: }
311:
312: // Determines whether a content spec tree represents an "all" content model
313: protected boolean hasAllContent(XSParticleDecl particle) {
314: // If the content is not empty, is the top node ALL?
315: if (particle != null
316: && particle.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
317: return ((XSModelGroupImpl) particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL;
318: }
319:
320: return false;
321: }
322:
323: // the inner class: used to store particles for model groups
324: // to avoid creating a new Vector in each model group, or when traversing
325: // each model group, we use this one big array to store all particles
326: // for model groups. when the traversal finishes, this class returns an
327: // XSParticleDecl[] containing all particles for the current model group.
328: // it's possible that we need to traverse another model group while
329: // traversing one (one inside another one; referring to a global group,
330: // etc.), so we have push/pos context methods to save the same of the
331: // current traversal before starting the traversal of another model group.
332: protected static class ParticleArray {
333: // big array to contain all particles
334: XSParticleDecl[] fParticles = new XSParticleDecl[10];
335: // the ending position of particles in the array for each context
336: // index 0 is reserved, with value 0. index 1 is used for the fist
337: // context. so that the number of particles for context 'i' can be
338: // computed simply by fPos[i] - fPos[i-1].
339: int[] fPos = new int[5];
340: // number of contexts
341: int fContextCount = 0;
342:
343: // start a new context (start traversing a new model group)
344: void pushContext() {
345: fContextCount++;
346: // resize position array if necessary
347: if (fContextCount == fPos.length) {
348: int newSize = fContextCount * 2;
349: int[] newArray = new int[newSize];
350: System.arraycopy(fPos, 0, newArray, 0, fContextCount);
351: fPos = newArray;
352: }
353: // the initial ending position of the current context is the
354: // ending position of the previsous context. which means there is
355: // no particle for the current context yet.
356: fPos[fContextCount] = fPos[fContextCount - 1];
357: }
358:
359: // get the number of particles of this context (model group)
360: int getParticleCount() {
361: return fPos[fContextCount] - fPos[fContextCount - 1];
362: }
363:
364: // add a particle to the current context
365: void addParticle(XSParticleDecl particle) {
366: // resize the particle array if necessary
367: if (fPos[fContextCount] == fParticles.length) {
368: int newSize = fPos[fContextCount] * 2;
369: XSParticleDecl[] newArray = new XSParticleDecl[newSize];
370: System.arraycopy(fParticles, 0, newArray, 0,
371: fPos[fContextCount]);
372: fParticles = newArray;
373: }
374: fParticles[fPos[fContextCount]++] = particle;
375: }
376:
377: // end the current context, and return an array of particles
378: XSParticleDecl[] popContext() {
379: int count = fPos[fContextCount] - fPos[fContextCount - 1];
380: XSParticleDecl[] array = null;
381: if (count != 0) {
382: array = new XSParticleDecl[count];
383: System.arraycopy(fParticles, fPos[fContextCount - 1],
384: array, 0, count);
385: // clear the particle array, to release memory
386: for (int i = fPos[fContextCount - 1]; i < fPos[fContextCount]; i++)
387: fParticles[i] = null;
388: }
389: fContextCount--;
390: return array;
391: }
392:
393: }
394:
395: // the big particle array to hold all particles in model groups
396: ParticleArray fPArray = new ParticleArray();
397: }
|