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.dv.ValidatedInfo;
021: import org.apache.xerces.impl.dv.XSSimpleType;
022: import org.apache.xerces.impl.xs.SchemaGrammar;
023: import org.apache.xerces.impl.xs.SchemaSymbols;
024: import org.apache.xerces.impl.xs.XSAnnotationImpl;
025: import org.apache.xerces.impl.xs.XSComplexTypeDecl;
026: import org.apache.xerces.impl.xs.XSConstraints;
027: import org.apache.xerces.impl.xs.XSElementDecl;
028: import org.apache.xerces.impl.xs.XSParticleDecl;
029: import org.apache.xerces.xs.XSConstants;
030: import org.apache.xerces.xs.XSObject;
031: import org.apache.xerces.xs.XSObjectList;
032: import org.apache.xerces.xs.XSTypeDefinition;
033: import org.apache.xerces.impl.xs.util.XInt;
034: import org.apache.xerces.impl.xs.util.XSObjectListImpl;
035: import org.apache.xerces.util.DOMUtil;
036: import org.apache.xerces.util.SymbolTable;
037: import org.apache.xerces.util.XMLChar;
038: import org.apache.xerces.xni.QName;
039: import org.w3c.dom.Element;
040: import org.w3c.dom.Attr;
041:
042: /**
043: * The element declaration schema component traverser.
044: * <element
045: * abstract = boolean : false
046: * block = (#all | List of (extension | restriction | substitution))
047: * default = string
048: * final = (#all | List of (extension | restriction))
049: * fixed = string
050: * form = (qualified | unqualified)
051: * id = ID
052: * maxOccurs = (nonNegativeInteger | unbounded) : 1
053: * minOccurs = nonNegativeInteger : 1
054: * name = NCName
055: * nillable = boolean : false
056: * ref = QName
057: * substitutionGroup = QName
058: * type = QName
059: * {any attributes with non-schema namespace . . .}>
060: * Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
061: * </element>
062: *
063: * @xerces.internal
064: *
065: * @author Sandy Gao, IBM
066: *
067: * @version $Id: XSDElementTraverser.java 469584 2006-10-31 17:57:34Z mrglavas $
068: */
069: class XSDElementTraverser extends XSDAbstractTraverser {
070:
071: protected final XSElementDecl fTempElementDecl = new XSElementDecl();
072:
073: // this controls what happens when a local element is encountered.
074: // We may not encounter all local elements when first parsing.
075: boolean fDeferTraversingLocalElements;
076:
077: XSDElementTraverser(XSDHandler handler,
078: XSAttributeChecker gAttrCheck) {
079: super (handler, gAttrCheck);
080: }
081:
082: /**
083: * Traverse a locally declared element (or an element reference).
084: *
085: * To handle the recursive cases efficiently, we delay the traversal
086: * and return an empty particle node. We'll fill in this particle node
087: * later after we've done with all the global declarations.
088: * This method causes a number of data structures in the schema handler to be filled in.
089: *
090: * @param elmDecl
091: * @param schemaDoc
092: * @param grammar
093: * @return the particle
094: */
095: XSParticleDecl traverseLocal(Element elmDecl,
096: XSDocumentInfo schemaDoc, SchemaGrammar grammar,
097: int allContextFlags, XSObject parent) {
098:
099: XSParticleDecl particle = null;
100: if (fSchemaHandler.fDeclPool != null) {
101: particle = fSchemaHandler.fDeclPool.getParticleDecl();
102: } else {
103: particle = new XSParticleDecl();
104: }
105: if (fDeferTraversingLocalElements) {
106: // The only thing we care about now is whether this element has
107: // minOccurs=0. This affects (if the element appears in a complex
108: // type) whether a type has emptiable content.
109: particle.fType = XSParticleDecl.PARTICLE_ELEMENT;
110: Attr attr = elmDecl
111: .getAttributeNode(SchemaSymbols.ATT_MINOCCURS);
112: if (attr != null) {
113: String min = attr.getValue();
114: try {
115: int m = Integer.parseInt(XMLChar.trim(min));
116: if (m >= 0)
117: particle.fMinOccurs = m;
118: } catch (NumberFormatException ex) {
119: }
120: }
121: fSchemaHandler.fillInLocalElemInfo(elmDecl, schemaDoc,
122: allContextFlags, parent, particle);
123: } else {
124: traverseLocal(particle, elmDecl, schemaDoc, grammar,
125: allContextFlags, parent, null);
126: // If it's an empty particle, return null.
127: if (particle.fType == XSParticleDecl.PARTICLE_EMPTY)
128: particle = null;
129: }
130:
131: return particle;
132: }
133:
134: /**
135: * Traverse a locally declared element (or an element reference).
136: *
137: * This is the real traversal method. It's called after we've done with
138: * all the global declarations.
139: *
140: * @param index
141: */
142: protected void traverseLocal(XSParticleDecl particle,
143: Element elmDecl, XSDocumentInfo schemaDoc,
144: SchemaGrammar grammar, int allContextFlags,
145: XSObject parent, String[] localNSDecls) {
146:
147: if (localNSDecls != null) {
148: schemaDoc.fNamespaceSupport
149: .setEffectiveContext(localNSDecls);
150: }
151:
152: // General Attribute Checking
153: Object[] attrValues = fAttrChecker.checkAttributes(elmDecl,
154: false, schemaDoc);
155:
156: QName refAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_REF];
157: XInt minAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MINOCCURS];
158: XInt maxAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS];
159:
160: XSElementDecl element = null;
161: XSAnnotationImpl annotation = null;
162: if (elmDecl.getAttributeNode(SchemaSymbols.ATT_REF) != null) {
163: if (refAtt != null) {
164: element = (XSElementDecl) fSchemaHandler.getGlobalDecl(
165: schemaDoc, XSDHandler.ELEMENT_TYPE, refAtt,
166: elmDecl);
167:
168: Element child = DOMUtil.getFirstChildElement(elmDecl);
169: if (child != null
170: && DOMUtil.getLocalName(child).equals(
171: SchemaSymbols.ELT_ANNOTATION)) {
172: annotation = traverseAnnotationDecl(child,
173: attrValues, false, schemaDoc);
174: child = DOMUtil.getNextSiblingElement(child);
175: } else {
176: String text = DOMUtil
177: .getSyntheticAnnotation(elmDecl);
178: if (text != null) {
179: annotation = traverseSyntheticAnnotation(
180: elmDecl, text, attrValues, false,
181: schemaDoc);
182: }
183: }
184: // Element Declaration Representation OK
185: // 2 If the item's parent is not <schema>, then all of the following must be true:
186: // 2.1 One of ref or name must be present, but not both.
187: // 2.2 If ref is present, then all of <complexType>, <simpleType>, <key>, <keyref>, <unique>, nillable, default, fixed, form, block and type must be absent, i.e. only minOccurs, maxOccurs, id are allowed in addition to ref, along with <annotation>.
188: if (child != null) {
189: reportSchemaError("src-element.2.2",
190: new Object[] { refAtt.rawname,
191: DOMUtil.getLocalName(child) },
192: child);
193: }
194: } else {
195: element = null;
196: }
197: } else {
198: element = traverseNamedElement(elmDecl, attrValues,
199: schemaDoc, grammar, false, parent);
200: }
201:
202: particle.fMinOccurs = minAtt.intValue();
203: particle.fMaxOccurs = maxAtt.intValue();
204: if (element != null) {
205: particle.fType = XSParticleDecl.PARTICLE_ELEMENT;
206: particle.fValue = element;
207: } else {
208: particle.fType = XSParticleDecl.PARTICLE_EMPTY;
209: }
210: if (refAtt != null) {
211: XSObjectList annotations;
212: if (annotation != null) {
213: annotations = new XSObjectListImpl();
214: ((XSObjectListImpl) annotations).add(annotation);
215: } else {
216: annotations = XSObjectListImpl.EMPTY_LIST;
217: }
218: particle.fAnnotations = annotations;
219: } else {
220: particle.fAnnotations = ((element != null) ? element.fAnnotations
221: : XSObjectListImpl.EMPTY_LIST);
222: }
223: Long defaultVals = (Long) attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT];
224: checkOccurrences(particle, SchemaSymbols.ELT_ELEMENT,
225: (Element) elmDecl.getParentNode(), allContextFlags,
226: defaultVals.longValue());
227:
228: fAttrChecker.returnAttrArray(attrValues, schemaDoc);
229: }
230:
231: /**
232: * Traverse a globally declared element.
233: *
234: * @param elmDecl
235: * @param schemaDoc
236: * @param grammar
237: * @return the element declaration
238: */
239: XSElementDecl traverseGlobal(Element elmDecl,
240: XSDocumentInfo schemaDoc, SchemaGrammar grammar) {
241:
242: // General Attribute Checking'
243:
244: Object[] attrValues = fAttrChecker.checkAttributes(elmDecl,
245: true, schemaDoc);
246: XSElementDecl element = traverseNamedElement(elmDecl,
247: attrValues, schemaDoc, grammar, true, null);
248: fAttrChecker.returnAttrArray(attrValues, schemaDoc);
249: return element;
250:
251: }
252:
253: /**
254: * Traverse a globally declared element.
255: *
256: * @param elmDecl
257: * @param attrValues
258: * @param schemaDoc
259: * @param grammar
260: * @param isGlobal
261: * @return the element declaration
262: */
263: XSElementDecl traverseNamedElement(Element elmDecl,
264: Object[] attrValues, XSDocumentInfo schemaDoc,
265: SchemaGrammar grammar, boolean isGlobal, XSObject parent) {
266:
267: Boolean abstractAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_ABSTRACT];
268: XInt blockAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_BLOCK];
269: String defaultAtt = (String) attrValues[XSAttributeChecker.ATTIDX_DEFAULT];
270: XInt finalAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FINAL];
271: String fixedAtt = (String) attrValues[XSAttributeChecker.ATTIDX_FIXED];
272: XInt formAtt = (XInt) attrValues[XSAttributeChecker.ATTIDX_FORM];
273: String nameAtt = (String) attrValues[XSAttributeChecker.ATTIDX_NAME];
274: Boolean nillableAtt = (Boolean) attrValues[XSAttributeChecker.ATTIDX_NILLABLE];
275: QName subGroupAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_SUBSGROUP];
276: QName typeAtt = (QName) attrValues[XSAttributeChecker.ATTIDX_TYPE];
277:
278: // Step 1: get declaration information
279:
280: XSElementDecl element = null;
281: if (fSchemaHandler.fDeclPool != null) {
282: element = fSchemaHandler.fDeclPool.getElementDecl();
283: } else {
284: element = new XSElementDecl();
285: }
286: // get 'name'
287: if (nameAtt != null)
288: element.fName = fSymbolTable.addSymbol(nameAtt);
289:
290: // get 'target namespace'
291: if (isGlobal) {
292: element.fTargetNamespace = schemaDoc.fTargetNamespace;
293: element.setIsGlobal();
294: } else {
295: if (parent instanceof XSComplexTypeDecl)
296: element.setIsLocal((XSComplexTypeDecl) parent);
297:
298: if (formAtt != null) {
299: if (formAtt.intValue() == SchemaSymbols.FORM_QUALIFIED)
300: element.fTargetNamespace = schemaDoc.fTargetNamespace;
301: else
302: element.fTargetNamespace = null;
303: } else if (schemaDoc.fAreLocalElementsQualified) {
304: element.fTargetNamespace = schemaDoc.fTargetNamespace;
305: } else {
306: element.fTargetNamespace = null;
307: }
308: }
309:
310: // get 'block', 'final', 'nillable', 'abstract'
311: element.fBlock = blockAtt == null ? schemaDoc.fBlockDefault
312: : blockAtt.shortValue();
313: element.fFinal = finalAtt == null ? schemaDoc.fFinalDefault
314: : finalAtt.shortValue();
315: // discard valid Block/Final 'Default' values that are invalid for Block/Final
316: element.fBlock &= (XSConstants.DERIVATION_EXTENSION
317: | XSConstants.DERIVATION_RESTRICTION | XSConstants.DERIVATION_SUBSTITUTION);
318: element.fFinal &= (XSConstants.DERIVATION_EXTENSION | XSConstants.DERIVATION_RESTRICTION);
319:
320: if (nillableAtt.booleanValue())
321: element.setIsNillable();
322: if (abstractAtt != null && abstractAtt.booleanValue())
323: element.setIsAbstract();
324:
325: // get 'value constraint'
326: if (fixedAtt != null) {
327: element.fDefault = new ValidatedInfo();
328: element.fDefault.normalizedValue = fixedAtt;
329: element.setConstraintType(XSConstants.VC_FIXED);
330: } else if (defaultAtt != null) {
331: element.fDefault = new ValidatedInfo();
332: element.fDefault.normalizedValue = defaultAtt;
333: element.setConstraintType(XSConstants.VC_DEFAULT);
334: } else {
335: element.setConstraintType(XSConstants.VC_NONE);
336: }
337:
338: // get 'substitutionGroup affiliation'
339: if (subGroupAtt != null) {
340: element.fSubGroup = (XSElementDecl) fSchemaHandler
341: .getGlobalDecl(schemaDoc, XSDHandler.ELEMENT_TYPE,
342: subGroupAtt, elmDecl);
343: }
344:
345: // get 'annotation'
346: Element child = DOMUtil.getFirstChildElement(elmDecl);
347: XSAnnotationImpl annotation = null;
348: if (child != null
349: && DOMUtil.getLocalName(child).equals(
350: SchemaSymbols.ELT_ANNOTATION)) {
351: annotation = traverseAnnotationDecl(child, attrValues,
352: false, schemaDoc);
353: child = DOMUtil.getNextSiblingElement(child);
354: } else {
355: String text = DOMUtil.getSyntheticAnnotation(elmDecl);
356: if (text != null) {
357: annotation = traverseSyntheticAnnotation(elmDecl, text,
358: attrValues, false, schemaDoc);
359: }
360: }
361:
362: XSObjectList annotations;
363: if (annotation != null) {
364: annotations = new XSObjectListImpl();
365: ((XSObjectListImpl) annotations).add(annotation);
366: } else {
367: annotations = XSObjectListImpl.EMPTY_LIST;
368: }
369: element.fAnnotations = annotations;
370:
371: // get 'type definition'
372: XSTypeDefinition elementType = null;
373: boolean haveAnonType = false;
374:
375: // Handle Anonymous type if there is one
376: if (child != null) {
377: String childName = DOMUtil.getLocalName(child);
378:
379: if (childName.equals(SchemaSymbols.ELT_COMPLEXTYPE)) {
380: elementType = fSchemaHandler.fComplexTypeTraverser
381: .traverseLocal(child, schemaDoc, grammar);
382: haveAnonType = true;
383: child = DOMUtil.getNextSiblingElement(child);
384: } else if (childName.equals(SchemaSymbols.ELT_SIMPLETYPE)) {
385: elementType = fSchemaHandler.fSimpleTypeTraverser
386: .traverseLocal(child, schemaDoc, grammar);
387: haveAnonType = true;
388: child = DOMUtil.getNextSiblingElement(child);
389: }
390: }
391:
392: // Handler type attribute
393: if (elementType == null && typeAtt != null) {
394: elementType = (XSTypeDefinition) fSchemaHandler
395: .getGlobalDecl(schemaDoc, XSDHandler.TYPEDECL_TYPE,
396: typeAtt, elmDecl);
397: }
398:
399: // Get it from the substitutionGroup declaration
400: if (elementType == null && element.fSubGroup != null) {
401: elementType = element.fSubGroup.fType;
402: }
403:
404: if (elementType == null) {
405: elementType = SchemaGrammar.fAnyType;
406: }
407:
408: element.fType = elementType;
409:
410: // get 'identity constraint'
411:
412: // see if there's something here; it had better be key, keyref or unique.
413: if (child != null) {
414: String childName = DOMUtil.getLocalName(child);
415: while (child != null
416: && (childName.equals(SchemaSymbols.ELT_KEY)
417: || childName
418: .equals(SchemaSymbols.ELT_KEYREF) || childName
419: .equals(SchemaSymbols.ELT_UNIQUE))) {
420:
421: if (childName.equals(SchemaSymbols.ELT_KEY)
422: || childName.equals(SchemaSymbols.ELT_UNIQUE)) {
423: // need to set <key>/<unique> to hidden before traversing it,
424: // because it has global scope
425: DOMUtil.setHidden(child,
426: fSchemaHandler.fHiddenNodes);
427: fSchemaHandler.fUniqueOrKeyTraverser.traverse(
428: child, element, schemaDoc, grammar);
429: if (DOMUtil.getAttrValue(child,
430: SchemaSymbols.ATT_NAME).length() != 0) {
431: fSchemaHandler
432: .checkForDuplicateNames(
433: (schemaDoc.fTargetNamespace == null) ? ","
434: + DOMUtil
435: .getAttrValue(
436: child,
437: SchemaSymbols.ATT_NAME)
438: : schemaDoc.fTargetNamespace
439: + ","
440: + DOMUtil
441: .getAttrValue(
442: child,
443: SchemaSymbols.ATT_NAME),
444: fSchemaHandler.getIDRegistry(),
445: fSchemaHandler
446: .getIDRegistry_sub(),
447: child, schemaDoc);
448: }
449: } else if (childName.equals(SchemaSymbols.ELT_KEYREF)) {
450: fSchemaHandler.storeKeyRef(child, schemaDoc,
451: element);
452: }
453: child = DOMUtil.getNextSiblingElement(child);
454: if (child != null) {
455: childName = DOMUtil.getLocalName(child);
456: }
457: }
458: }
459:
460: // Step 2: register the element decl to the grammar
461: if (isGlobal && nameAtt != null)
462: grammar.addGlobalElementDecl(element);
463:
464: // Step 3: check against schema for schemas
465:
466: // required attributes
467: if (nameAtt == null) {
468: if (isGlobal)
469: reportSchemaError("s4s-att-must-appear", new Object[] {
470: SchemaSymbols.ELT_ELEMENT,
471: SchemaSymbols.ATT_NAME }, elmDecl);
472: else
473: reportSchemaError("src-element.2.1", null, elmDecl);
474: nameAtt = NO_NAME;
475: }
476:
477: // element
478: if (child != null) {
479: reportSchemaError(
480: "s4s-elt-must-match.1",
481: new Object[] {
482: nameAtt,
483: "(annotation?, (simpleType | complexType)?, (unique | key | keyref)*))",
484: DOMUtil.getLocalName(child) }, child);
485: }
486:
487: // Step 4: check 3.3.3 constraints
488:
489: // src-element
490:
491: // 1 default and fixed must not both be present.
492: if (defaultAtt != null && fixedAtt != null) {
493: reportSchemaError("src-element.1",
494: new Object[] { nameAtt }, elmDecl);
495: }
496:
497: // 2 If the item's parent is not <schema>, then all of the following must be true:
498: // 2.1 One of ref or name must be present, but not both.
499: // This is checked in XSAttributeChecker
500:
501: // 2.2 If ref is present, then all of <complexType>, <simpleType>, <key>, <keyref>, <unique>, nillable, default, fixed, form, block and type must be absent, i.e. only minOccurs, maxOccurs, id are allowed in addition to ref, along with <annotation>.
502: // Attributes are checked in XSAttributeChecker, elements are checked in "traverse" method
503:
504: // 3 type and either <simpleType> or <complexType> are mutually exclusive.
505: if (haveAnonType && (typeAtt != null)) {
506: reportSchemaError("src-element.3",
507: new Object[] { nameAtt }, elmDecl);
508: }
509:
510: // Step 5: check 3.3.6 constraints
511: // check for NOTATION type
512: checkNotationType(nameAtt, elementType, elmDecl);
513:
514: // e-props-correct
515:
516: // 2 If there is a {value constraint}, the canonical lexical representation of its value must be valid with respect to the {type definition} as defined in Element Default Valid (Immediate) (3.3.6).
517: if (element.fDefault != null) {
518: fValidationState
519: .setNamespaceSupport(schemaDoc.fNamespaceSupport);
520: if (XSConstraints.ElementDefaultValidImmediate(
521: element.fType, element.fDefault.normalizedValue,
522: fValidationState, element.fDefault) == null) {
523: reportSchemaError("e-props-correct.2", new Object[] {
524: nameAtt, element.fDefault.normalizedValue },
525: elmDecl);
526: element.setConstraintType(XSConstants.VC_NONE);
527: }
528: }
529:
530: // 4 If there is an {substitution group affiliation}, the {type definition} of the element declaration must be validly derived from the {type definition} of the {substitution group affiliation}, given the value of the {substitution group exclusions} of the {substitution group affiliation}, as defined in Type Derivation OK (Complex) (3.4.6) (if the {type definition} is complex) or as defined in Type Derivation OK (Simple) (3.14.6) (if the {type definition} is simple).
531: if (element.fSubGroup != null) {
532: if (!XSConstraints.checkTypeDerivationOk(element.fType,
533: element.fSubGroup.fType, element.fSubGroup.fFinal)) {
534: reportSchemaError("e-props-correct.4", new Object[] {
535: nameAtt,
536: subGroupAtt.prefix + ":"
537: + subGroupAtt.localpart }, elmDecl);
538: }
539: }
540:
541: // 5 If the {type definition} or {type definition}'s {content type} is or is derived from ID then there must not be a {value constraint}.
542: if (element.fDefault != null) {
543: if ((elementType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE && ((XSSimpleType) elementType)
544: .isIDType())
545: || (elementType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE && ((XSComplexTypeDecl) elementType)
546: .containsTypeID())) {
547: reportSchemaError("e-props-correct.5",
548: new Object[] { element.fName }, elmDecl);
549: }
550: }
551:
552: // Element without a name. Return null.
553: if (element.fName == null)
554: return null;
555:
556: return element;
557: }
558:
559: void reset(SymbolTable symbolTable, boolean validateAnnotations) {
560: super .reset(symbolTable, validateAnnotations);
561: fDeferTraversingLocalElements = true;
562: } // reset()
563:
564: }
|