XSDAbstractTraverser.java revision 1113:2fdbfbde3bc0
1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xerces.internal.impl.xs.traversers;
23
24import java.util.Locale;
25import java.util.Vector;
26
27import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
28import com.sun.org.apache.xerces.internal.impl.dv.XSFacets;
29import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
30import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
31import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
32import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
33import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
34import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeGroupDecl;
35import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeUseImpl;
36import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
37import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
38import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
39import com.sun.org.apache.xerces.internal.impl.xs.XSWildcardDecl;
40import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
41import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
42import com.sun.org.apache.xerces.internal.util.DOMUtil;
43import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
44import com.sun.org.apache.xerces.internal.util.SymbolTable;
45import com.sun.org.apache.xerces.internal.xni.QName;
46import com.sun.org.apache.xerces.internal.xs.XSAttributeUse;
47import com.sun.org.apache.xerces.internal.xs.XSObjectList;
48import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
49import org.w3c.dom.Element;
50
51/**
52 * Class <code>XSDAbstractTraverser</code> serves as the base class for all
53 * other <code>XSD???Traverser</code>s. It holds the common data and provide
54 * a unified way to initialize these data.
55 *
56 * @xerces.internal
57 *
58 * @author Elena Litani, IBM
59 * @author Rahul Srivastava, Sun Microsystems Inc.
60 * @author Neeraj Bajaj, Sun Microsystems Inc.
61 *
62 */
63abstract 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}
854