View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.impl.xs.traversers;
22  
23  import java.util.Locale;
24  import java.util.Vector;
25  
26  import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
27  import com.sun.org.apache.xerces.internal.impl.dv.XSFacets;
28  import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
29  import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
30  import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
31  import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
32  import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
33  import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeGroupDecl;
34  import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeUseImpl;
35  import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
36  import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
37  import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
38  import com.sun.org.apache.xerces.internal.impl.xs.XSWildcardDecl;
39  import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
40  import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
41  import com.sun.org.apache.xerces.internal.util.DOMUtil;
42  import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
43  import com.sun.org.apache.xerces.internal.util.SymbolTable;
44  import com.sun.org.apache.xerces.internal.xni.QName;
45  import com.sun.org.apache.xerces.internal.xs.XSAttributeUse;
46  import com.sun.org.apache.xerces.internal.xs.XSObjectList;
47  import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
48  import org.w3c.dom.Element;
49  
50  /**
51   * Class <code>XSDAbstractTraverser</code> serves as the base class for all
52   * other <code>XSD???Traverser</code>s. It holds the common data and provide
53   * a unified way to initialize these data.
54   *
55   * @xerces.internal
56   *
57   * @author Elena Litani, IBM
58   * @author Rahul Srivastava, Sun Microsystems Inc.
59   * @author Neeraj Bajaj, Sun Microsystems Inc.
60   *
61   * @version $Id: XSDAbstractTraverser.java,v 1.8 2010-11-01 04:40:02 joehw Exp $
62   */
63  abstract class XSDAbstractTraverser {
64  
65      protected static final String NO_NAME      = "(no name)";
66  
67      // Flags for checkOccurrences to indicate any special
68      // restrictions on minOccurs and maxOccurs relating to "all".
69      //    NOT_ALL_CONTEXT    - not processing an <all>
70      //    PROCESSING_ALL_EL  - processing an <element> in an <all>
71      //    GROUP_REF_WITH_ALL - processing <group> reference that contained <all>
72      //    CHILD_OF_GROUP     - processing a child of a model group definition
73      //    PROCESSING_ALL_GP  - processing an <all> group itself
74  
75      protected static final int NOT_ALL_CONTEXT    = 0;
76      protected static final int PROCESSING_ALL_EL  = 1;
77      protected static final int GROUP_REF_WITH_ALL = 2;
78      protected static final int CHILD_OF_GROUP     = 4;
79      protected static final int PROCESSING_ALL_GP  = 8;
80  
81      //Shared data
82      protected XSDHandler            fSchemaHandler = null;
83      protected SymbolTable           fSymbolTable = null;
84      protected XSAttributeChecker    fAttrChecker = null;
85      protected boolean               fValidateAnnotations = false;
86  
87      // used to validate default/fixed attribute values
88      ValidationState fValidationState = new ValidationState();
89  
90      XSDAbstractTraverser (XSDHandler handler,
91              XSAttributeChecker attrChecker) {
92          fSchemaHandler = handler;
93          fAttrChecker = attrChecker;
94      }
95  
96      void reset(SymbolTable symbolTable, boolean validateAnnotations, Locale locale) {
97          fSymbolTable = symbolTable;
98          fValidateAnnotations = validateAnnotations;
99          fValidationState.setExtraChecking(false);
100         fValidationState.setSymbolTable(symbolTable);
101         fValidationState.setLocale(locale);
102     }
103 
104     // traverse the annotation declaration
105     // REVISIT: how to pass the parentAttrs? as DOM attributes?
106     //          as name/value pairs (string)? in parsed form?
107     // @return XSAnnotationImpl object
108     XSAnnotationImpl traverseAnnotationDecl(Element annotationDecl, Object[] parentAttrs,
109             boolean isGlobal, XSDocumentInfo schemaDoc) {
110         // General Attribute Checking
111         Object[] attrValues = fAttrChecker.checkAttributes(annotationDecl, isGlobal, schemaDoc);
112         fAttrChecker.returnAttrArray(attrValues, schemaDoc);
113 
114         String contents = DOMUtil.getAnnotation(annotationDecl);
115         Element child = DOMUtil.getFirstChildElement(annotationDecl);
116         if (child != null) {
117             do {
118                 String name = DOMUtil.getLocalName(child);
119 
120                 // the only valid children of "annotation" are
121                 // "appinfo" and "documentation"
122                 if (!((name.equals(SchemaSymbols.ELT_APPINFO)) ||
123                         (name.equals(SchemaSymbols.ELT_DOCUMENTATION)))) {
124                     reportSchemaError("src-annotation", new Object[]{name}, child);
125                 }
126                 else {
127                     // General Attribute Checking
128                     // There is no difference between global or local appinfo/documentation,
129                     // so we assume it's always global.
130                     attrValues = fAttrChecker.checkAttributes(child, true, schemaDoc);
131                     fAttrChecker.returnAttrArray(attrValues, schemaDoc);
132                 }
133 
134                 child = DOMUtil.getNextSiblingElement(child);
135             }
136             while (child != null);
137         }
138         // if contents was null, must have been some kind of error;
139         // nothing to contribute to PSVI
140         if (contents == null) return null;
141 
142         // find the grammar; fSchemaHandler must be known!
143         SchemaGrammar grammar = fSchemaHandler.getGrammar(schemaDoc.fTargetNamespace);
144         // fish out local attributes passed from parent
145         Vector annotationLocalAttrs = (Vector)parentAttrs[XSAttributeChecker.ATTIDX_NONSCHEMA];
146         // optimize for case where there are no local attributes
147         if(annotationLocalAttrs != null && !annotationLocalAttrs.isEmpty()) {
148             StringBuffer localStrBuffer = new StringBuffer(64);
149             localStrBuffer.append(" ");
150             // Vector should contain rawname value pairs
151             int i = 0;
152             while (i < annotationLocalAttrs.size()) {
153                 String rawname = (String)annotationLocalAttrs.elementAt(i++);
154                 int colonIndex = rawname.indexOf(':');
155                 String prefix, localpart;
156                 if (colonIndex == -1) {
157                     prefix = "";
158                     localpart = rawname;
159                 }
160                 else {
161                     prefix = rawname.substring(0,colonIndex);
162                     localpart = rawname.substring(colonIndex+1);
163                 }
164                 String uri = schemaDoc.fNamespaceSupport.getURI(fSymbolTable.addSymbol(prefix));
165                 if (annotationDecl.getAttributeNS(uri, localpart).length() != 0) {
166                     i++; // skip the next value, too
167                     continue;
168                 }
169                 localStrBuffer.append(rawname)
170                 .append("=\"");
171                 String value = (String)annotationLocalAttrs.elementAt(i++);
172                 // search for pesky "s and <s within attr value:
173                 value = processAttValue(value);
174                 localStrBuffer.append(value)
175                 .append("\" ");
176             }
177             // and now splice it into place; immediately after the annotation token, for simplicity's sake
178             StringBuffer contentBuffer = new StringBuffer(contents.length() + localStrBuffer.length());
179             int annotationTokenEnd = contents.indexOf(SchemaSymbols.ELT_ANNOTATION);
180             // annotation must occur somewhere or we're in big trouble...
181             if(annotationTokenEnd == -1) return null;
182             annotationTokenEnd += SchemaSymbols.ELT_ANNOTATION.length();
183             contentBuffer.append(contents.substring(0,annotationTokenEnd));
184             contentBuffer.append(localStrBuffer.toString());
185             contentBuffer.append(contents.substring(annotationTokenEnd, contents.length()));
186             final String annotation = contentBuffer.toString();
187             if (fValidateAnnotations) {
188                 schemaDoc.addAnnotation(new XSAnnotationInfo(annotation, annotationDecl));
189             }
190             return new XSAnnotationImpl(annotation, grammar);
191         } else {
192             if (fValidateAnnotations) {
193                 schemaDoc.addAnnotation(new XSAnnotationInfo(contents, annotationDecl));
194             }
195             return new XSAnnotationImpl(contents, grammar);
196         }
197 
198     }
199 
200     XSAnnotationImpl traverseSyntheticAnnotation(Element annotationParent, String initialContent,
201             Object[] parentAttrs, boolean isGlobal, XSDocumentInfo schemaDoc) {
202 
203         String contents = initialContent;
204 
205         // find the grammar; fSchemaHandler must be known!
206         SchemaGrammar grammar = fSchemaHandler.getGrammar(schemaDoc.fTargetNamespace);
207         // fish out local attributes passed from parent
208         Vector annotationLocalAttrs = (Vector)parentAttrs[XSAttributeChecker.ATTIDX_NONSCHEMA];
209         // optimize for case where there are no local attributes
210         if (annotationLocalAttrs != null && !annotationLocalAttrs.isEmpty()) {
211             StringBuffer localStrBuffer = new StringBuffer(64);
212             localStrBuffer.append(" ");
213             // Vector should contain rawname value pairs
214             int i = 0;
215             while (i < annotationLocalAttrs.size()) {
216                 String rawname = (String)annotationLocalAttrs.elementAt(i++);
217                 int colonIndex = rawname.indexOf(':');
218                 String prefix, localpart;
219                 if (colonIndex == -1) {
220                     prefix = "";
221                     localpart = rawname;
222                 }
223                 else {
224                     prefix = rawname.substring(0,colonIndex);
225                     localpart = rawname.substring(colonIndex+1);
226                 }
227                 String uri = schemaDoc.fNamespaceSupport.getURI(fSymbolTable.addSymbol(prefix));
228                 localStrBuffer.append(rawname)
229                 .append("=\"");
230                 String value = (String)annotationLocalAttrs.elementAt(i++);
231                 // search for pesky "s and <s within attr value:
232                 value = processAttValue(value);
233                 localStrBuffer.append(value)
234                 .append("\" ");
235             }
236             // and now splice it into place; immediately after the annotation token, for simplicity's sake
237             StringBuffer contentBuffer = new StringBuffer(contents.length() + localStrBuffer.length());
238             int annotationTokenEnd = contents.indexOf(SchemaSymbols.ELT_ANNOTATION);
239             // annotation must occur somewhere or we're in big trouble...
240             if(annotationTokenEnd == -1) return null;
241             annotationTokenEnd += SchemaSymbols.ELT_ANNOTATION.length();
242             contentBuffer.append(contents.substring(0,annotationTokenEnd));
243             contentBuffer.append(localStrBuffer.toString());
244             contentBuffer.append(contents.substring(annotationTokenEnd, contents.length()));
245             final String annotation = contentBuffer.toString();
246             if (fValidateAnnotations) {
247                 schemaDoc.addAnnotation(new XSAnnotationInfo(annotation, annotationParent));
248             }
249             return new XSAnnotationImpl(annotation, grammar);
250         } else {
251             if (fValidateAnnotations) {
252                 schemaDoc.addAnnotation(new XSAnnotationInfo(contents, annotationParent));
253             }
254             return new XSAnnotationImpl(contents, grammar);
255         }
256     }
257 
258     // the QName simple type used to resolve qnames
259     private static final XSSimpleType fQNameDV = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);
260     // Temp data structures to be re-used in traversing facets
261     private StringBuffer fPattern = new StringBuffer();
262     private final XSFacets xsFacets = new XSFacets();
263 
264     static final class FacetInfo {
265 
266         final XSFacets facetdata;
267         final Element nodeAfterFacets;
268         final short fPresentFacets;
269         final short fFixedFacets;
270 
271         FacetInfo(XSFacets facets, Element nodeAfterFacets, short presentFacets, short fixedFacets) {
272             facetdata = facets;
273             this.nodeAfterFacets = nodeAfterFacets;
274             fPresentFacets = presentFacets;
275             fFixedFacets = fixedFacets;
276         }
277     }
278 
279     FacetInfo traverseFacets(Element content,
280             XSSimpleType baseValidator,
281             XSDocumentInfo schemaDoc) {
282 
283         short facetsPresent = 0 ;
284         short facetsFixed = 0; // facets that have fixed="true"
285         String facet;
286         boolean hasQName = containsQName(baseValidator);
287         Vector enumData = null;
288         XSObjectListImpl enumAnnotations = null;
289         XSObjectListImpl patternAnnotations = null;
290         Vector enumNSDecls = hasQName ? new Vector() : null;
291         int currentFacet = 0;
292         xsFacets.reset();
293         while (content != null) {
294             // General Attribute Checking
295             Object[] attrs = null;
296             facet = DOMUtil.getLocalName(content);
297             if (facet.equals(SchemaSymbols.ELT_ENUMERATION)) {
298                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc, hasQName);
299                 String enumVal = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
300                 // The facet can't be used if the value is missing. Ignore
301                 // this facet element.
302                 if (enumVal == null) {
303                     reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_ENUMERATION, SchemaSymbols.ATT_VALUE}, content);
304                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
305                     content = DOMUtil.getNextSiblingElement(content);
306                     continue;
307                 }
308 
309                 NamespaceSupport nsDecls = (NamespaceSupport)attrs[XSAttributeChecker.ATTIDX_ENUMNSDECLS];
310 
311                 // for NOTATION types, need to check whether there is a notation
312                 // declared with the same name as the enumeration value.
313                 if (baseValidator.getVariety() == XSSimpleType.VARIETY_ATOMIC &&
314                         baseValidator.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
315                     // need to use the namespace context returned from checkAttributes
316                     schemaDoc.fValidationContext.setNamespaceSupport(nsDecls);
317                     Object notation = null;
318                     try{
319                         QName temp = (QName)fQNameDV.validate(enumVal, schemaDoc.fValidationContext, null);
320                         // try to get the notation decl. if failed, getGlobalDecl
321                         // reports an error, so we don't need to report one again.
322                         notation = fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.NOTATION_TYPE, temp, content);
323                     }catch(InvalidDatatypeValueException ex){
324                         reportSchemaError(ex.getKey(), ex.getArgs(), content);
325                     }
326                     if (notation == null) {
327                         // Either the QName value is invalid, or it doens't
328                         // resolve to a notation declaration.
329                         // Ignore this facet, to avoid instance validation problems
330                         fAttrChecker.returnAttrArray (attrs, schemaDoc);
331                         content = DOMUtil.getNextSiblingElement(content);
332                         continue;
333                     }
334                     // restore to the normal namespace context
335                     schemaDoc.fValidationContext.setNamespaceSupport(schemaDoc.fNamespaceSupport);
336                 }
337                 if (enumData == null){
338                     enumData = new Vector();
339                     enumAnnotations = new XSObjectListImpl();
340                 }
341                 enumData.addElement(enumVal);
342                 enumAnnotations.addXSObject(null);
343                 if (hasQName)
344                     enumNSDecls.addElement(nsDecls);
345                 Element child = DOMUtil.getFirstChildElement( content );
346 
347                 if (child != null &&
348                     DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
349                     // traverse annotation if any
350                     enumAnnotations.addXSObject(enumAnnotations.getLength()-1,traverseAnnotationDecl(child, attrs, false, schemaDoc));
351                     child = DOMUtil.getNextSiblingElement(child);
352                 }
353                 else {
354                     String text = DOMUtil.getSyntheticAnnotation(content);
355                     if (text != null) {
356                         enumAnnotations.addXSObject(enumAnnotations.getLength()-1, traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc));
357                     }
358                 }
359                 if (child !=null) {
360                     reportSchemaError("s4s-elt-must-match.1", new Object[]{"enumeration", "(annotation?)", DOMUtil.getLocalName(child)}, child);
361                 }
362             }
363             else if (facet.equals(SchemaSymbols.ELT_PATTERN)) {
364                 facetsPresent |= XSSimpleType.FACET_PATTERN;
365                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc);
366                 String patternVal = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
367                 // The facet can't be used if the value is missing. Ignore
368                 // this facet element.
369                 if (patternVal == null) {
370                     reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_PATTERN, SchemaSymbols.ATT_VALUE}, content);
371                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
372                     content = DOMUtil.getNextSiblingElement(content);
373                     continue;
374                 }
375 
376                 if (fPattern.length() == 0) {
377                     fPattern.append(patternVal);
378                 } else {
379                     // ---------------------------------------------
380                     //datatypes: 5.2.4 pattern: src-multiple-pattern
381                     // ---------------------------------------------
382                     fPattern.append("|");
383                     fPattern.append(patternVal);
384                 }
385                 Element child = DOMUtil.getFirstChildElement( content );
386                 if (child != null &&
387                         DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
388                     // traverse annotation if any
389                     if (patternAnnotations == null){
390                         patternAnnotations = new XSObjectListImpl();
391                     }
392                     patternAnnotations.addXSObject(traverseAnnotationDecl(child, attrs, false, schemaDoc));
393                     child = DOMUtil.getNextSiblingElement(child);
394                 }
395                 else {
396                     String text = DOMUtil.getSyntheticAnnotation(content);
397                     if (text != null) {
398                         if (patternAnnotations == null){
399                             patternAnnotations = new XSObjectListImpl();
400                         }
401                         patternAnnotations.addXSObject(traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc));
402                     }
403                 }
404                 if (child !=null) {
405                     reportSchemaError("s4s-elt-must-match.1", new Object[]{"pattern", "(annotation?)", DOMUtil.getLocalName(child)}, child);
406                 }
407             }
408             else {
409                 if (facet.equals(SchemaSymbols.ELT_MINLENGTH)) {
410                     currentFacet = XSSimpleType.FACET_MINLENGTH;
411                 }
412                 else if (facet.equals(SchemaSymbols.ELT_MAXLENGTH)) {
413                     currentFacet = XSSimpleType.FACET_MAXLENGTH;
414                 }
415                 else if (facet.equals(SchemaSymbols.ELT_MAXEXCLUSIVE)) {
416                     currentFacet = XSSimpleType.FACET_MAXEXCLUSIVE;
417                 }
418                 else if (facet.equals(SchemaSymbols.ELT_MAXINCLUSIVE)) {
419                     currentFacet = XSSimpleType.FACET_MAXINCLUSIVE;
420                 }
421                 else if (facet.equals(SchemaSymbols.ELT_MINEXCLUSIVE)) {
422                     currentFacet = XSSimpleType.FACET_MINEXCLUSIVE;
423                 }
424                 else if (facet.equals(SchemaSymbols.ELT_MININCLUSIVE)) {
425                     currentFacet = XSSimpleType.FACET_MININCLUSIVE;
426                 }
427                 else if (facet.equals(SchemaSymbols.ELT_TOTALDIGITS)) {
428                     currentFacet = XSSimpleType.FACET_TOTALDIGITS;
429                 }
430                 else if (facet.equals(SchemaSymbols.ELT_FRACTIONDIGITS)) {
431                     currentFacet = XSSimpleType.FACET_FRACTIONDIGITS;
432                 }
433                 else if (facet.equals(SchemaSymbols.ELT_WHITESPACE)) {
434                     currentFacet = XSSimpleType.FACET_WHITESPACE;
435                 }
436                 else if (facet.equals(SchemaSymbols.ELT_LENGTH)) {
437                     currentFacet = XSSimpleType.FACET_LENGTH;
438                 }
439                 else {
440                     break;   // a non-facet
441                 }
442 
443                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc);
444 
445                 // check for duplicate facets
446                 if ((facetsPresent & currentFacet) != 0) {
447                     // Ignore this facet, to avoid corrupting the previous facet
448                     reportSchemaError("src-single-facet-value", new Object[]{facet}, content);
449                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
450                     content = DOMUtil.getNextSiblingElement(content);
451                     continue;
452                 }
453 
454                 // The facet can't be used if the value is missing. Ignore
455                 // this facet element.
456                 if (attrs[XSAttributeChecker.ATTIDX_VALUE] == null) {
457                     // Report an error if the "value" attribute is missing.
458                     // If it's not missing, then its value is invalid, and an
459                     // error should have already been reported by the
460                     // attribute checker.
461                     if (content.getAttributeNodeNS(null, "value") == null) {
462                         reportSchemaError("s4s-att-must-appear", new Object[]{content.getLocalName(), SchemaSymbols.ATT_VALUE}, content);
463                     }
464                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
465                     content = DOMUtil.getNextSiblingElement(content);
466                     continue;
467                 }
468 
469                 facetsPresent |= currentFacet;
470                 // check for fixed facet
471                 if (((Boolean)attrs[XSAttributeChecker.ATTIDX_FIXED]).booleanValue()) {
472                     facetsFixed |= currentFacet;
473                 }
474                 switch (currentFacet) {
475                 case XSSimpleType.FACET_MINLENGTH:
476                     xsFacets.minLength = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
477                     break;
478                 case XSSimpleType.FACET_MAXLENGTH:
479                     xsFacets.maxLength = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
480                     break;
481                 case XSSimpleType.FACET_MAXEXCLUSIVE:
482                     xsFacets.maxExclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
483                     break;
484                 case XSSimpleType.FACET_MAXINCLUSIVE:
485                     xsFacets.maxInclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
486                     break;
487                 case XSSimpleType.FACET_MINEXCLUSIVE:
488                     xsFacets.minExclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
489                     break;
490                 case XSSimpleType.FACET_MININCLUSIVE:
491                     xsFacets.minInclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
492                     break;
493                 case XSSimpleType.FACET_TOTALDIGITS:
494                     xsFacets.totalDigits = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
495                     break;
496                 case XSSimpleType.FACET_FRACTIONDIGITS:
497                     xsFacets.fractionDigits = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
498                     break;
499                 case XSSimpleType.FACET_WHITESPACE:
500                     xsFacets.whiteSpace = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).shortValue();
501                     break;
502                 case XSSimpleType.FACET_LENGTH:
503                     xsFacets.length = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
504                     break;
505                 }
506 
507                 Element child = DOMUtil.getFirstChildElement( content );
508                 XSAnnotationImpl annotation = null;
509                 if (child != null &&
510                     DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
511                     // traverse annotation if any
512                     annotation = traverseAnnotationDecl(child, attrs, false, schemaDoc);
513                     child = DOMUtil.getNextSiblingElement(child);
514                 }
515                 else {
516                     String text = DOMUtil.getSyntheticAnnotation(content);
517                     if (text != null) {
518                         annotation = traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc);
519                     }
520                }
521                 switch (currentFacet) {
522                 case XSSimpleType.FACET_MINLENGTH:
523                     xsFacets.minLengthAnnotation = annotation;
524                 break;
525                 case XSSimpleType.FACET_MAXLENGTH:
526                     xsFacets.maxLengthAnnotation = annotation;
527                 break;
528                 case XSSimpleType.FACET_MAXEXCLUSIVE:
529                     xsFacets.maxExclusiveAnnotation = annotation;
530                 break;
531                 case XSSimpleType.FACET_MAXINCLUSIVE:
532                     xsFacets.maxInclusiveAnnotation = annotation;
533                 break;
534                 case XSSimpleType.FACET_MINEXCLUSIVE:
535                     xsFacets.minExclusiveAnnotation = annotation;
536                 break;
537                 case XSSimpleType.FACET_MININCLUSIVE:
538                     xsFacets.minInclusiveAnnotation = annotation;
539                 break;
540                 case XSSimpleType.FACET_TOTALDIGITS:
541                     xsFacets.totalDigitsAnnotation = annotation;
542                 break;
543                 case XSSimpleType.FACET_FRACTIONDIGITS:
544                     xsFacets.fractionDigitsAnnotation = annotation;
545                 break;
546                 case XSSimpleType.FACET_WHITESPACE:
547                     xsFacets.whiteSpaceAnnotation = annotation;
548                 break;
549                 case XSSimpleType.FACET_LENGTH:
550                     xsFacets.lengthAnnotation = annotation;
551                 break;
552                 }
553                 if (child != null) {
554                     reportSchemaError("s4s-elt-must-match.1", new Object[]{facet, "(annotation?)", DOMUtil.getLocalName(child)}, child);
555                 }
556             }
557             fAttrChecker.returnAttrArray (attrs, schemaDoc);
558             content = DOMUtil.getNextSiblingElement(content);
559         }
560         if (enumData !=null) {
561             facetsPresent |= XSSimpleType.FACET_ENUMERATION;
562             xsFacets.enumeration = enumData;
563             xsFacets.enumNSDecls = enumNSDecls;
564             xsFacets.enumAnnotations = enumAnnotations;
565         }
566         if ((facetsPresent & XSSimpleType.FACET_PATTERN) != 0) {
567             xsFacets.pattern = fPattern.toString();
568             xsFacets.patternAnnotations = patternAnnotations;
569         }
570 
571         fPattern.setLength(0);
572 
573         return new FacetInfo(xsFacets, content, facetsPresent, facetsFixed);
574     }
575 
576 
577     // return whether QName/NOTATION is part of the given type
578     private boolean containsQName(XSSimpleType type) {
579         if (type.getVariety() == XSSimpleType.VARIETY_ATOMIC) {
580             short primitive = type.getPrimitiveKind();
581             return (primitive == XSSimpleType.PRIMITIVE_QNAME ||
582                     primitive == XSSimpleType.PRIMITIVE_NOTATION);
583         }
584         else if (type.getVariety() == XSSimpleType.VARIETY_LIST) {
585             return containsQName((XSSimpleType)type.getItemType());
586         }
587         else if (type.getVariety() == XSSimpleType.VARIETY_UNION) {
588             XSObjectList members = type.getMemberTypes();
589             for (int i = 0; i < members.getLength(); i++) {
590                 if (containsQName((XSSimpleType)members.item(i)))
591                     return true;
592             }
593         }
594         return false;
595     }
596 
597     //
598     // Traverse a set of attribute and attribute group elements
599     // Needed by complexType and attributeGroup traversal
600     // This method will return the first non-attribute/attrgrp found
601     //
602     Element traverseAttrsAndAttrGrps(Element firstAttr, XSAttributeGroupDecl attrGrp,
603             XSDocumentInfo schemaDoc, SchemaGrammar grammar,
604             XSComplexTypeDecl enclosingCT) {
605 
606         Element child=null;
607         XSAttributeGroupDecl tempAttrGrp = null;
608         XSAttributeUseImpl tempAttrUse = null;
609         XSAttributeUse otherUse = null;
610         String childName;
611 
612         for (child=firstAttr; child!=null; child=DOMUtil.getNextSiblingElement(child)) {
613             childName = DOMUtil.getLocalName(child);
614             if (childName.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
615                 tempAttrUse = fSchemaHandler.fAttributeTraverser.traverseLocal(child,
616                         schemaDoc,
617                         grammar,
618                         enclosingCT);
619                 if (tempAttrUse == null) continue;
620                 if (tempAttrUse.fUse == SchemaSymbols.USE_PROHIBITED) {
621                     attrGrp.addAttributeUse(tempAttrUse);
622                     continue;
623                 }
624                 otherUse = attrGrp.getAttributeUseNoProhibited(
625                         tempAttrUse.fAttrDecl.getNamespace(),
626                         tempAttrUse.fAttrDecl.getName());
627                 if (otherUse==null) {
628                     String idName = attrGrp.addAttributeUse(tempAttrUse);
629                     if (idName != null) {
630                         String code = (enclosingCT == null) ? "ag-props-correct.3" : "ct-props-correct.5";
631                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
632                         reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName(), idName}, child);
633                     }
634                 }
635                 else if (otherUse != tempAttrUse) {
636                     String code = (enclosingCT == null) ? "ag-props-correct.2" : "ct-props-correct.4";
637                     String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
638                     reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName()}, child);
639                 }
640             }
641             else if (childName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
642                 //REVISIT: do we need to save some state at this point??
643                 tempAttrGrp = fSchemaHandler.fAttributeGroupTraverser.traverseLocal(
644                         child, schemaDoc, grammar);
645                 if(tempAttrGrp == null ) continue;
646                 XSObjectList attrUseS = tempAttrGrp.getAttributeUses();
647                 XSAttributeUseImpl oneAttrUse;
648                 int attrCount = attrUseS.getLength();
649                 for (int i=0; i<attrCount; i++) {
650                     oneAttrUse = (XSAttributeUseImpl)attrUseS.item(i);
651                     if (oneAttrUse.fUse == SchemaSymbols.USE_PROHIBITED) {
652                         attrGrp.addAttributeUse(oneAttrUse);
653                         continue;
654                     }
655                     otherUse = attrGrp.getAttributeUseNoProhibited(
656                             oneAttrUse.fAttrDecl.getNamespace(),
657                             oneAttrUse.fAttrDecl.getName());
658                     if (otherUse==null) {
659                         String idName = attrGrp.addAttributeUse(oneAttrUse);
660                         if (idName != null) {
661                             String code = (enclosingCT == null) ? "ag-props-correct.3" : "ct-props-correct.5";
662                             String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
663                             reportSchemaError(code, new Object[]{name, oneAttrUse.fAttrDecl.getName(), idName}, child);
664                         }
665                     }
666                     else if (oneAttrUse != otherUse) {
667                         String code = (enclosingCT == null) ? "ag-props-correct.2" : "ct-props-correct.4";
668                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
669                         reportSchemaError(code, new Object[]{name, oneAttrUse.fAttrDecl.getName()}, child);
670                     }
671                 }
672 
673                 if (tempAttrGrp.fAttributeWC != null) {
674                     if (attrGrp.fAttributeWC == null) {
675                         attrGrp.fAttributeWC = tempAttrGrp.fAttributeWC;
676                     }
677                     // perform intersection of attribute wildcard
678                     else {
679                         attrGrp.fAttributeWC = attrGrp.fAttributeWC.
680                         performIntersectionWith(tempAttrGrp.fAttributeWC, attrGrp.fAttributeWC.fProcessContents);
681                         if (attrGrp.fAttributeWC == null) {
682                             String code = (enclosingCT == null) ? "src-attribute_group.2" : "src-ct.4";
683                             String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
684                             reportSchemaError(code, new Object[]{name}, child);
685                         }
686                     }
687                 }
688             }
689             else
690                 break;
691         } // for
692 
693         if (child != null) {
694             childName = DOMUtil.getLocalName(child);
695             if (childName.equals(SchemaSymbols.ELT_ANYATTRIBUTE)) {
696                 XSWildcardDecl tempAttrWC = fSchemaHandler.fWildCardTraverser.
697                 traverseAnyAttribute(child, schemaDoc, grammar);
698                 if (attrGrp.fAttributeWC == null) {
699                     attrGrp.fAttributeWC = tempAttrWC;
700                 }
701                 // perform intersection of attribute wildcard
702                 else {
703                     attrGrp.fAttributeWC = tempAttrWC.
704                     performIntersectionWith(attrGrp.fAttributeWC, tempAttrWC.fProcessContents);
705                     if (attrGrp.fAttributeWC == null) {
706                         String code = (enclosingCT == null) ? "src-attribute_group.2" : "src-ct.4";
707                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
708                         reportSchemaError(code, new Object[]{name}, child);
709                     }
710                 }
711                 child = DOMUtil.getNextSiblingElement(child);
712             }
713         }
714 
715         // Success
716         return child;
717 
718     }
719 
720     void reportSchemaError (String key, Object[] args, Element ele) {
721         fSchemaHandler.reportSchemaError(key, args, ele);
722     }
723 
724     /**
725      * Element/Attribute traversers call this method to check whether
726      * the type is NOTATION without enumeration facet
727      */
728     void checkNotationType(String refName, XSTypeDefinition typeDecl, Element elem) {
729         if (typeDecl.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE &&
730                 ((XSSimpleType)typeDecl).getVariety() == XSSimpleType.VARIETY_ATOMIC &&
731                 ((XSSimpleType)typeDecl).getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
732             if ((((XSSimpleType)typeDecl).getDefinedFacets() & XSSimpleType.FACET_ENUMERATION) == 0) {
733                 reportSchemaError("enumeration-required-notation", new Object[]{typeDecl.getName(), refName, DOMUtil.getLocalName(elem)}, elem);
734             }
735         }
736     }
737 
738     // Checks constraints for minOccurs, maxOccurs
739     protected XSParticleDecl checkOccurrences(XSParticleDecl particle,
740             String particleName, Element parent,
741             int allContextFlags,
742             long defaultVals) {
743 
744         int min = particle.fMinOccurs;
745         int max = particle.fMaxOccurs;
746         boolean defaultMin = (defaultVals & (1 << XSAttributeChecker.ATTIDX_MINOCCURS)) != 0;
747         boolean defaultMax = (defaultVals & (1 << XSAttributeChecker.ATTIDX_MAXOCCURS)) != 0;
748 
749         boolean processingAllEl = ((allContextFlags & PROCESSING_ALL_EL) != 0);
750         boolean processingAllGP = ((allContextFlags & PROCESSING_ALL_GP) != 0);
751         boolean groupRefWithAll = ((allContextFlags & GROUP_REF_WITH_ALL) != 0);
752         boolean isGroupChild    = ((allContextFlags & CHILD_OF_GROUP) != 0);
753 
754         // Neither minOccurs nor maxOccurs may be specified
755         // for the child of a model group definition.
756         if (isGroupChild) {
757             if (!defaultMin) {
758                 Object[] args = new Object[]{particleName, "minOccurs"};
759                 reportSchemaError("s4s-att-not-allowed", args, parent);
760                 min = 1;
761             }
762             if (!defaultMax) {
763                 Object[] args = new Object[]{particleName, "maxOccurs"};
764                 reportSchemaError("s4s-att-not-allowed", args, parent);
765                 max = 1;
766             }
767         }
768 
769         // If minOccurs=maxOccurs=0, no component is specified
770         if (min == 0 && max== 0) {
771             particle.fType = XSParticleDecl.PARTICLE_EMPTY;
772             return null;
773         }
774 
775         // For the elements referenced in an <all>, minOccurs attribute
776         // must be zero or one, and maxOccurs attribute must be one.
777         // For a complex type definition that contains an <all> or a
778         // reference a <group> whose model group is an all model group,
779         // minOccurs and maxOccurs must be one.
780         if (processingAllEl) {
781             if (max != 1) {
782                 reportSchemaError("cos-all-limited.2", new Object[]{
783                         (max == SchemaSymbols.OCCURRENCE_UNBOUNDED) ? SchemaSymbols.ATTVAL_UNBOUNDED : Integer.toString(max),
784                         ((XSElementDecl)particle.fValue).getName()}, parent);
785                 max = 1;
786                 if (min > 1)
787                     min = 1;
788             }
789         }
790         else if (processingAllGP || groupRefWithAll) {
791             if (max != 1) {
792                 reportSchemaError("cos-all-limited.1.2", null, parent);
793                 if (min > 1)
794                     min = 1;
795                 max = 1;
796             }
797         }
798 
799         particle.fMinOccurs = min;
800         particle.fMaxOccurs = max;
801 
802         return particle;
803     }
804 
805     private static String processAttValue(String original) {
806         final int length = original.length();
807         // normally, nothing will happen
808         for (int i = 0; i < length; ++i) {
809             char currChar = original.charAt(i);
810             if (currChar == '"' || currChar == '<' || currChar == '&' ||
811                     currChar == 0x09 || currChar == 0x0A || currChar == 0x0D) {
812                 return escapeAttValue(original, i);
813             }
814         }
815         return original;
816     }
817 
818     // this is not terribly performant!
819     private static String escapeAttValue(String original, int from) {
820         int i;
821         final int length = original.length();
822         StringBuffer newVal = new StringBuffer(length);
823         newVal.append(original.substring(0, from));
824         for (i = from; i < length; ++i) {
825             char currChar = original.charAt(i);
826             if (currChar == '"') {
827                 newVal.append("&quot;");
828             }
829             else if (currChar == '<') {
830                 newVal.append("&lt;");
831             }
832             else if (currChar == '&') {
833                 newVal.append("&amp;");
834             }
835             // Must escape 0x09, 0x0A and 0x0D if they appear in attribute
836             // value so that they may be round-tripped. They would otherwise
837             // be transformed to a 0x20 during attribute value normalization.
838             else if (currChar == 0x09) {
839                 newVal.append("&#x9;");
840             }
841             else if (currChar == 0x0A) {
842                 newVal.append("&#xA;");
843             }
844             else if (currChar == 0x0D) {
845                 newVal.append("&#xD;");
846             }
847             else {
848                 newVal.append(currChar);
849             }
850         }
851         return newVal.toString();
852     }
853 }