1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.xerces.impl.dtd;
19
20 import org.apache.xerces.impl.Constants;
21 import org.apache.xerces.impl.RevalidationHandler;
22 import org.apache.xerces.impl.XMLEntityManager;
23 import org.apache.xerces.impl.XMLErrorReporter;
24 import org.apache.xerces.impl.dtd.models.ContentModelValidator;
25 import org.apache.xerces.impl.dv.DTDDVFactory;
26 import org.apache.xerces.impl.dv.DatatypeValidator;
27 import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
28 import org.apache.xerces.impl.msg.XMLMessageFormatter;
29 import org.apache.xerces.impl.validation.ValidationManager;
30 import org.apache.xerces.impl.validation.ValidationState;
31 import org.apache.xerces.util.SymbolTable;
32 import org.apache.xerces.util.XMLChar;
33 import org.apache.xerces.util.XMLSymbols;
34 import org.apache.xerces.xni.Augmentations;
35 import org.apache.xerces.xni.NamespaceContext;
36 import org.apache.xerces.xni.QName;
37 import org.apache.xerces.xni.XMLAttributes;
38 import org.apache.xerces.xni.XMLDocumentHandler;
39 import org.apache.xerces.xni.XMLLocator;
40 import org.apache.xerces.xni.XMLResourceIdentifier;
41 import org.apache.xerces.xni.XMLString;
42 import org.apache.xerces.xni.XNIException;
43 import org.apache.xerces.xni.grammars.Grammar;
44 import org.apache.xerces.xni.grammars.XMLGrammarDescription;
45 import org.apache.xerces.xni.grammars.XMLGrammarPool;
46 import org.apache.xerces.xni.parser.XMLComponent;
47 import org.apache.xerces.xni.parser.XMLComponentManager;
48 import org.apache.xerces.xni.parser.XMLConfigurationException;
49 import org.apache.xerces.xni.parser.XMLDocumentFilter;
50 import org.apache.xerces.xni.parser.XMLDocumentSource;
51
52 /**
53 * The DTD validator. The validator implements a document
54 * filter: receiving document events from the scanner; validating
55 * the content and structure; augmenting the InfoSet, if applicable;
56 * and notifying the parser of the information resulting from the
57 * validation process.
58 * <p> Formerly, this component also handled DTD events and grammar construction.
59 * To facilitate the development of a meaningful DTD grammar caching/preparsing
60 * framework, this functionality has been moved into the XMLDTDLoader
61 * class. Therefore, this class no longer implements the DTDFilter
62 * or DTDContentModelFilter interfaces.
63 * <p>
64 * This component requires the following features and properties from the
65 * component manager that uses it:
66 * <ul>
67 * <li>http://xml.org/sax/features/namespaces</li>
68 * <li>http://xml.org/sax/features/validation</li>
69 * <li>http://apache.org/xml/features/validation/dynamic</li>
70 * <li>http://apache.org/xml/properties/internal/symbol-table</li>
71 * <li>http://apache.org/xml/properties/internal/error-reporter</li>
72 * <li>http://apache.org/xml/properties/internal/grammar-pool</li>
73 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
74 * </ul>
75 *
76 * @xerces.internal
77 *
78 * @author Eric Ye, IBM
79 * @author Andy Clark, IBM
80 * @author Jeffrey Rodriguez IBM
81 * @author Neil Graham, IBM
82 *
83 * @version $Id: XMLDTDValidator.java 572055 2007-09-02 17:55:43Z mrglavas $
84 */
85 public class XMLDTDValidator
86 implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler {
87
88 //
89 // Constants
90 //
91
92 /** Symbol: "<<datatypes>>". */
93
94 /** Top level scope (-1). */
95 private static final int TOP_LEVEL_SCOPE = -1;
96
97 // feature identifiers
98
99 /** Feature identifier: namespaces. */
100 protected static final String NAMESPACES =
101 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
102
103 /** Feature identifier: validation. */
104 protected static final String VALIDATION =
105 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
106
107 /** Feature identifier: dynamic validation. */
108 protected static final String DYNAMIC_VALIDATION =
109 Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
110
111 /** Feature identifier: balance syntax trees. */
112 protected static final String BALANCE_SYNTAX_TREES =
113 Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES;
114
115 /** Feature identifier: warn on duplicate attdef */
116 protected static final String WARN_ON_DUPLICATE_ATTDEF =
117 Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE;
118
119 protected static final String PARSER_SETTINGS =
120 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
121
122
123
124 // property identifiers
125
126 /** Property identifier: symbol table. */
127 protected static final String SYMBOL_TABLE =
128 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
129
130 /** Property identifier: error reporter. */
131 protected static final String ERROR_REPORTER =
132 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
133
134 /** Property identifier: grammar pool. */
135 protected static final String GRAMMAR_POOL =
136 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
137
138 /** Property identifier: datatype validator factory. */
139 protected static final String DATATYPE_VALIDATOR_FACTORY =
140 Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY;
141
142 // property identifier: ValidationManager
143 protected static final String VALIDATION_MANAGER =
144 Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
145
146 // recognized features and properties
147
148 /** Recognized features. */
149 private static final String[] RECOGNIZED_FEATURES = {
150 NAMESPACES,
151 VALIDATION,
152 DYNAMIC_VALIDATION,
153 BALANCE_SYNTAX_TREES
154 };
155
156 /** Feature defaults. */
157 private static final Boolean[] FEATURE_DEFAULTS = {
158 null,
159 null,
160 Boolean.FALSE,
161 Boolean.FALSE,
162 };
163
164 /** Recognized properties. */
165 private static final String[] RECOGNIZED_PROPERTIES = {
166 SYMBOL_TABLE,
167 ERROR_REPORTER,
168 GRAMMAR_POOL,
169 DATATYPE_VALIDATOR_FACTORY,
170 VALIDATION_MANAGER
171 };
172
173 /** Property defaults. */
174 private static final Object[] PROPERTY_DEFAULTS = {
175 null,
176 null,
177 null,
178 null,
179 null,
180 };
181
182 // debugging
183
184 /** Compile to true to debug attributes. */
185 private static final boolean DEBUG_ATTRIBUTES = false;
186
187 /** Compile to true to debug element children. */
188 private static final boolean DEBUG_ELEMENT_CHILDREN = false;
189
190 //
191 // Data
192 //
193
194 // updated during reset
195 protected ValidationManager fValidationManager = null;
196
197 // validation state
198 protected final ValidationState fValidationState = new ValidationState();
199
200 // features
201
202 /** Namespaces. */
203 protected boolean fNamespaces;
204
205 /** Validation. */
206 protected boolean fValidation;
207
208 /** Validation against only DTD */
209 protected boolean fDTDValidation;
210
211 /**
212 * Dynamic validation. This state of this feature is only useful when
213 * the validation feature is set to <code>true</code>.
214 */
215 protected boolean fDynamicValidation;
216
217 /** Controls whether the DTD grammar produces balanced syntax trees. */
218 protected boolean fBalanceSyntaxTrees;
219
220 /** warn on duplicate attribute definition, this feature works only when validation is true */
221 protected boolean fWarnDuplicateAttdef;
222
223 // properties
224
225 /** Symbol table. */
226 protected SymbolTable fSymbolTable;
227
228 /** Error reporter. */
229 protected XMLErrorReporter fErrorReporter;
230
231 // the grammar pool
232 protected XMLGrammarPool fGrammarPool;
233
234 /** Grammar bucket. */
235 protected DTDGrammarBucket fGrammarBucket;
236
237 /* location of the document as passed in from startDocument call */
238 protected XMLLocator fDocLocation;
239
240 /** Namespace support. */
241 protected NamespaceContext fNamespaceContext = null;
242
243 /** Datatype validator factory. */
244 protected DTDDVFactory fDatatypeValidatorFactory;
245
246 // handlers
247
248 /** Document handler. */
249 protected XMLDocumentHandler fDocumentHandler;
250
251 protected XMLDocumentSource fDocumentSource;
252 // grammars
253
254 /** DTD Grammar. */
255 protected DTDGrammar fDTDGrammar;
256
257 // state
258
259 /** True if seen DOCTYPE declaration. */
260 protected boolean fSeenDoctypeDecl = false;
261
262 /** Perform validation. */
263 private boolean fPerformValidation;
264
265 /** Schema type: None, DTD, Schema */
266 private String fSchemaType;
267
268 // information regarding the current element
269
270 /** Current element name. */
271 private final QName fCurrentElement = new QName();
272
273 /** Current element index. */
274 private int fCurrentElementIndex = -1;
275
276 /** Current content spec type. */
277 private int fCurrentContentSpecType = -1;
278
279 /** The root element name. */
280 private final QName fRootElement = new QName();
281
282 private boolean fInCDATASection = false;
283 // element stack
284
285 /** Element index stack. */
286 private int[] fElementIndexStack = new int[8];
287
288 /** Content spec type stack. */
289 private int[] fContentSpecTypeStack = new int[8];
290
291 /** Element name stack. */
292 private QName[] fElementQNamePartsStack = new QName[8];
293
294 // children list and offset stack
295
296 /**
297 * Element children. This data structure is a growing stack that
298 * holds the children of elements from the root to the current
299 * element depth. This structure never gets "deeper" than the
300 * deepest element. Space is re-used once each element is closed.
301 * <p>
302 * <strong>Note:</strong> This is much more efficient use of memory
303 * than creating new arrays for each element depth.
304 * <p>
305 * <strong>Note:</strong> The use of this data structure is for
306 * validation "on the way out". If the validation model changes to
307 * "on the way in", then this data structure is not needed.
308 */
309 private QName[] fElementChildren = new QName[32];
310
311 /** Element children count. */
312 private int fElementChildrenLength = 0;
313
314 /**
315 * Element children offset stack. This stack refers to offsets
316 * into the <code>fElementChildren</code> array.
317 * @see #fElementChildren
318 */
319 private int[] fElementChildrenOffsetStack = new int[32];
320
321 /** Element depth. */
322 private int fElementDepth = -1;
323
324 // validation states
325
326 /** True if seen the root element. */
327 private boolean fSeenRootElement = false;
328
329 /** True if inside of element content. */
330 private boolean fInElementContent = false;
331
332 // temporary variables
333
334 /** Temporary element declaration. */
335 private XMLElementDecl fTempElementDecl = new XMLElementDecl();
336
337 /** Temporary atribute declaration. */
338 private XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl();
339
340 /** Temporary entity declaration. */
341 private XMLEntityDecl fEntityDecl = new XMLEntityDecl();
342
343 /** Temporary qualified name. */
344 private QName fTempQName = new QName();
345
346 /** Temporary string buffers. */
347 private StringBuffer fBuffer = new StringBuffer();
348
349 // symbols: general
350
351 // attribute validators
352
353 /** Datatype validator: ID. */
354 protected DatatypeValidator fValID;
355
356 /** Datatype validator: IDREF. */
357 protected DatatypeValidator fValIDRef;
358
359 /** Datatype validator: IDREFS. */
360 protected DatatypeValidator fValIDRefs;
361
362 /** Datatype validator: ENTITY. */
363 protected DatatypeValidator fValENTITY;
364
365 /** Datatype validator: ENTITIES. */
366 protected DatatypeValidator fValENTITIES;
367
368 /** Datatype validator: NMTOKEN. */
369 protected DatatypeValidator fValNMTOKEN;
370
371 /** Datatype validator: NMTOKENS. */
372 protected DatatypeValidator fValNMTOKENS;
373
374 /** Datatype validator: NOTATION. */
375 protected DatatypeValidator fValNOTATION;
376
377 // to check for duplicate ID or ANNOTATION attribute declare in
378 // ATTLIST, and misc VCs
379
380 //
381 // Constructors
382 //
383
384 /** Default constructor. */
385 public XMLDTDValidator() {
386
387 // initialize data
388 for (int i = 0; i < fElementQNamePartsStack.length; i++) {
389 fElementQNamePartsStack[i] = new QName();
390 }
391 fGrammarBucket = new DTDGrammarBucket();
392
393 } // <init>()
394
395 DTDGrammarBucket getGrammarBucket() {
396 return fGrammarBucket;
397 } // getGrammarBucket(): DTDGrammarBucket
398
399 //
400 // XMLComponent methods
401 //
402
403 /*
404 * Resets the component. The component can query the component manager
405 * about any features and properties that affect the operation of the
406 * component.
407 *
408 * @param componentManager The component manager.
409 *
410 * @throws SAXException Thrown by component on finitialization error.
411 * For example, if a feature or property is
412 * required for the operation of the component, the
413 * component manager may throw a
414 * SAXNotRecognizedException or a
415 * SAXNotSupportedException.
416 */
417 public void reset(XMLComponentManager componentManager)
418 throws XMLConfigurationException {
419
420 // clear grammars
421 fDTDGrammar = null;
422 fSeenDoctypeDecl = false;
423 fInCDATASection = false;
424 // initialize state
425 fSeenRootElement = false;
426 fInElementContent = false;
427 fCurrentElementIndex = -1;
428 fCurrentContentSpecType = -1;
429
430 fRootElement.clear();
431
432 fValidationState.resetIDTables();
433
434 fGrammarBucket.clear();
435 fElementDepth = -1;
436 fElementChildrenLength = 0;
437
438 boolean parser_settings;
439 try {
440 parser_settings = componentManager.getFeature(PARSER_SETTINGS);
441 }
442 catch (XMLConfigurationException e){
443 parser_settings = true;
444 }
445
446 if (!parser_settings){
447 // parser settings have not been changed
448 fValidationManager.addValidationState(fValidationState);
449 return;
450 }
451
452 // sax features
453 try {
454 fNamespaces = componentManager.getFeature(NAMESPACES);
455 }
456 catch (XMLConfigurationException e) {
457 fNamespaces = true;
458 }
459 try {
460 fValidation = componentManager.getFeature(VALIDATION);
461 }
462 catch (XMLConfigurationException e) {
463 fValidation = false;
464 }
465 try {
466 fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE));
467 }
468 catch (XMLConfigurationException e) {
469 // must be in a schema-less configuration!
470 fDTDValidation = true;
471 }
472
473 // Xerces features
474 try {
475 fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION);
476 }
477 catch (XMLConfigurationException e) {
478 fDynamicValidation = false;
479 }
480
481 try {
482 fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES);
483 }
484 catch (XMLConfigurationException e) {
485 fBalanceSyntaxTrees = false;
486 }
487
488 try {
489 fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF);
490 }
491 catch (XMLConfigurationException e) {
492 fWarnDuplicateAttdef = false;
493 }
494
495 try {
496 fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX
497 + Constants.SCHEMA_LANGUAGE);
498 }
499 catch (XMLConfigurationException e){
500 fSchemaType = null;
501 }
502
503 fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER);
504 fValidationManager.addValidationState(fValidationState);
505 fValidationState.setUsingNamespaces(fNamespaces);
506
507 // get needed components
508 fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY);
509 fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY);
510 try {
511 fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL);
512 } catch (XMLConfigurationException e) {
513 fGrammarPool = null;
514 }
515
516 fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY);
517 init();
518
519 } // reset(XMLComponentManager)
520
521 /**
522 * Returns a list of feature identifiers that are recognized by
523 * this component. This method may return null if no features
524 * are recognized by this component.
525 */
526 public String[] getRecognizedFeatures() {
527 return (String[])(RECOGNIZED_FEATURES.clone());
528 } // getRecognizedFeatures():String[]
529
530 /**
531 * Sets the state of a feature. This method is called by the component
532 * manager any time after reset when a feature changes state.
533 * <p>
534 * <strong>Note:</strong> Components should silently ignore features
535 * that do not affect the operation of the component.
536 *
537 * @param featureId The feature identifier.
538 * @param state The state of the feature.
539 *
540 * @throws SAXNotRecognizedException The component should not throw
541 * this exception.
542 * @throws SAXNotSupportedException The component should not throw
543 * this exception.
544 */
545 public void setFeature(String featureId, boolean state)
546 throws XMLConfigurationException {
547 } // setFeature(String,boolean)
548
549 /**
550 * Returns a list of property identifiers that are recognized by
551 * this component. This method may return null if no properties
552 * are recognized by this component.
553 */
554 public String[] getRecognizedProperties() {
555 return (String[])(RECOGNIZED_PROPERTIES.clone());
556 } // getRecognizedProperties():String[]
557
558 /**
559 * Sets the value of a property. This method is called by the component
560 * manager any time after reset when a property changes value.
561 * <p>
562 * <strong>Note:</strong> Components should silently ignore properties
563 * that do not affect the operation of the component.
564 *
565 * @param propertyId The property identifier.
566 * @param value The value of the property.
567 *
568 * @throws SAXNotRecognizedException The component should not throw
569 * this exception.
570 * @throws SAXNotSupportedException The component should not throw
571 * this exception.
572 */
573 public void setProperty(String propertyId, Object value)
574 throws XMLConfigurationException {
575 } // setProperty(String,Object)
576
577 /**
578 * Returns the default state for a feature, or null if this
579 * component does not want to report a default value for this
580 * feature.
581 *
582 * @param featureId The feature identifier.
583 *
584 * @since Xerces 2.2.0
585 */
586 public Boolean getFeatureDefault(String featureId) {
587 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
588 if (RECOGNIZED_FEATURES[i].equals(featureId)) {
589 return FEATURE_DEFAULTS[i];
590 }
591 }
592 return null;
593 } // getFeatureDefault(String):Boolean
594
595 /**
596 * Returns the default state for a property, or null if this
597 * component does not want to report a default value for this
598 * property.
599 *
600 * @param propertyId The property identifier.
601 *
602 * @since Xerces 2.2.0
603 */
604 public Object getPropertyDefault(String propertyId) {
605 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
606 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
607 return PROPERTY_DEFAULTS[i];
608 }
609 }
610 return null;
611 } // getPropertyDefault(String):Object
612
613 //
614 // XMLDocumentSource methods
615 //
616
617 /** Sets the document handler to receive information about the document. */
618 public void setDocumentHandler(XMLDocumentHandler documentHandler) {
619 fDocumentHandler = documentHandler;
620 } // setDocumentHandler(XMLDocumentHandler)
621
622 /** Returns the document handler */
623 public XMLDocumentHandler getDocumentHandler() {
624 return fDocumentHandler;
625 } // getDocumentHandler(): XMLDocumentHandler
626
627
628 //
629 // XMLDocumentHandler methods
630 //
631
632 /** Sets the document source */
633 public void setDocumentSource(XMLDocumentSource source){
634 fDocumentSource = source;
635 } // setDocumentSource
636
637 /** Returns the document source */
638 public XMLDocumentSource getDocumentSource (){
639 return fDocumentSource;
640 } // getDocumentSource
641
642 /**
643 * The start of the document.
644 *
645 * @param locator The system identifier of the entity if the entity
646 * is external, null otherwise.
647 * @param encoding The auto-detected IANA encoding name of the entity
648 * stream. This value will be null in those situations
649 * where the entity encoding is not auto-detected (e.g.
650 * internal entities or a document entity that is
651 * parsed from a java.io.Reader).
652 * @param namespaceContext
653 * The namespace context in effect at the
654 * start of this document.
655 * This object represents the current context.
656 * Implementors of this class are responsible
657 * for copying the namespace bindings from the
658 * the current context (and its parent contexts)
659 * if that information is important.
660 * @param augs Additional information that may include infoset augmentations
661 *
662 * @throws XNIException Thrown by handler to signal an error.
663 */
664 public void startDocument(XMLLocator locator, String encoding,
665 NamespaceContext namespaceContext, Augmentations augs)
666 throws XNIException {
667
668 // call handlers
669 // get initial grammars
670 if(fGrammarPool != null) {
671 Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD);
672 for(int i = 0; i<grammars.length; i++) {
673 fGrammarBucket.putGrammar((DTDGrammar)grammars[i]);
674 }
675 }
676 fDocLocation = locator;
677 fNamespaceContext = namespaceContext;
678
679 if (fDocumentHandler != null) {
680 fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
681 }
682
683 } // startDocument(XMLLocator,String)
684
685 /**
686 * Notifies of the presence of an XMLDecl line in the document. If
687 * present, this method will be called immediately following the
688 * startDocument call.
689 *
690 * @param version The XML version.
691 * @param encoding The IANA encoding name of the document, or null if
692 * not specified.
693 * @param standalone The standalone value, or null if not specified.
694 * @param augs Additional information that may include infoset augmentations
695 *
696 * @throws XNIException Thrown by handler to signal an error.
697 */
698 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
699 throws XNIException {
700
701 // save standalone state
702 fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes"));
703
704 // call handlers
705 if (fDocumentHandler != null) {
706 fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
707 }
708
709 } // xmlDecl(String,String,String)
710
711 /**
712 * Notifies of the presence of the DOCTYPE line in the document.
713 *
714 * @param rootElement The name of the root element.
715 * @param publicId The public identifier if an external DTD or null
716 * if the external DTD is specified using SYSTEM.
717 * @param systemId The system identifier if an external DTD, null
718 * otherwise.
719 * @param augs Additional information that may include infoset augmentations
720 *
721 * @throws XNIException Thrown by handler to signal an error.
722 */
723 public void doctypeDecl(String rootElement, String publicId, String systemId,
724 Augmentations augs)
725 throws XNIException {
726
727 // save root element state
728 fSeenDoctypeDecl = true;
729 fRootElement.setValues(null, rootElement, rootElement, null);
730 // find or create grammar:
731 String eid = null;
732 try {
733 eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false);
734 } catch (java.io.IOException e) {
735 }
736 XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement);
737 fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc);
738 if(fDTDGrammar == null) {
739 // give grammar pool a chance...
740 //
741 // Do not bother checking the pool if no public or system identifier was provided.
742 // Since so many different DTDs have roots in common, using only a root name as the
743 // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario
744 // would occur when an ExternalSubsetResolver has been queried and the
745 // XMLInputSource returned contains an input stream but no external identifier.
746 // This can never happen when the instance document specified a DOCTYPE. -- mrglavas
747 if (fGrammarPool != null && (systemId != null || publicId != null)) {
748 fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc);
749 }
750 }
751 if(fDTDGrammar == null) {
752 // we'll have to create it...
753 if (!fBalanceSyntaxTrees) {
754 fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc);
755 }
756 else {
757 fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc);
758 }
759 } else {
760 // we've found a cached one;so let's make sure not to read
761 // any external subset!
762 fValidationManager.setCachedDTD(true);
763 }
764 fGrammarBucket.setActiveGrammar(fDTDGrammar);
765
766 // call handlers
767 if (fDocumentHandler != null) {
768 fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
769 }
770
771 } // doctypeDecl(String,String,String, Augmentations)
772
773
774 /**
775 * The start of an element.
776 *
777 * @param element The name of the element.
778 * @param attributes The element attributes.
779 * @param augs Additional information that may include infoset augmentations
780 *
781 * @throws XNIException Thrown by handler to signal an error.
782 */
783 public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
784 throws XNIException {
785
786 handleStartElement(element, attributes, augs);
787 // call handlers
788 if (fDocumentHandler != null) {
789 fDocumentHandler.startElement(element, attributes, augs);
790
791 }
792
793 } // startElement(QName,XMLAttributes)
794
795 /**
796 * An empty element.
797 *
798 * @param element The name of the element.
799 * @param attributes The element attributes.
800 * @param augs Additional information that may include infoset augmentations
801 *
802 * @throws XNIException Thrown by handler to signal an error.
803 */
804 public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
805 throws XNIException {
806
807 boolean removed = handleStartElement(element, attributes, augs);
808
809 if (fDocumentHandler !=null) {
810 fDocumentHandler.emptyElement(element, attributes, augs);
811 }
812 if (!removed) {
813 handleEndElement(element, augs, true);
814 }
815
816
817 } // emptyElement(QName,XMLAttributes)
818
819 /**
820 * Character content.
821 *
822 * @param text The content.
823 *
824 * @param augs Additional information that may include infoset augmentations
825 *
826 * @throws XNIException Thrown by handler to signal an error.
827 */
828 public void characters(XMLString text, Augmentations augs) throws XNIException {
829
830 boolean callNextCharacters = true;
831
832 // REVISIT: [Q] Is there a more efficient way of doing this?
833 // Perhaps if the scanner told us so we don't have to
834 // look at the characters again. -Ac
835 boolean allWhiteSpace = true;
836 for (int i=text.offset; i< text.offset+text.length; i++) {
837 if (!isSpace(text.ch[i])) {
838 allWhiteSpace = false;
839 break;
840 }
841 }
842 // call the ignoreableWhiteSpace callback
843 // never call ignorableWhitespace if we are in cdata section
844 if (fInElementContent && allWhiteSpace && !fInCDATASection) {
845 if (fDocumentHandler != null) {
846 fDocumentHandler.ignorableWhitespace(text, augs);
847 callNextCharacters = false;
848 }
849 }
850
851 // validate
852 if (fPerformValidation) {
853 if (fInElementContent) {
854 if (fGrammarBucket.getStandalone() &&
855 fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) {
856 if (allWhiteSpace) {
857 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
858 "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE",
859 null, XMLErrorReporter.SEVERITY_ERROR);
860 }
861 }
862 if (!allWhiteSpace) {
863 charDataInContent();
864 }
865
866 // For E15.2
867 if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) {
868 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
869 "MSG_CONTENT_INVALID_SPECIFIED",
870 new Object[]{ fCurrentElement.rawname,
871 fDTDGrammar.getContentSpecAsString(fElementDepth),
872 "character reference"},
873 XMLErrorReporter.SEVERITY_ERROR);
874 }
875 }
876
877 if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) {
878 charDataInContent();
879 }
880 }
881
882 // call handlers
883 if (callNextCharacters && fDocumentHandler != null) {
884 fDocumentHandler.characters(text, augs);
885 }
886
887 } // characters(XMLString)
888
889
890
891 /**
892 * Ignorable whitespace. For this method to be called, the document
893 * source must have some way of determining that the text containing
894 * only whitespace characters should be considered ignorable. For
895 * example, the validator can determine if a length of whitespace
896 * characters in the document are ignorable based on the element
897 * content model.
898 *
899 * @param text The ignorable whitespace.
900 * @param augs Additional information that may include infoset augmentations
901 *
902 * @throws XNIException Thrown by handler to signal an error.
903 */
904 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
905
906 // call handlers
907 if (fDocumentHandler != null) {
908 fDocumentHandler.ignorableWhitespace(text, augs);
909 }
910
911 } // ignorableWhitespace(XMLString)
912
913 /**
914 * The end of an element.
915 *
916 * @param element The name of the element.
917 * @param augs Additional information that may include infoset augmentations
918 *
919 * @throws XNIException Thrown by handler to signal an error.
920 */
921 public void endElement(QName element, Augmentations augs) throws XNIException {
922
923 handleEndElement(element, augs, false);
924
925 } // endElement(QName)
926
927 /**
928 * The start of a CDATA section.
929 * @param augs Additional information that may include infoset augmentations
930 *
931 * @throws XNIException Thrown by handler to signal an error.
932 */
933 public void startCDATA(Augmentations augs) throws XNIException {
934
935 if (fPerformValidation && fInElementContent) {
936 charDataInContent();
937 }
938 fInCDATASection = true;
939 // call handlers
940 if (fDocumentHandler != null) {
941 fDocumentHandler.startCDATA(augs);
942 }
943
944 } // startCDATA()
945
946 /**
947 * The end of a CDATA section.
948 * @param augs Additional information that may include infoset augmentations
949 *
950 * @throws XNIException Thrown by handler to signal an error.
951 */
952 public void endCDATA(Augmentations augs) throws XNIException {
953
954 fInCDATASection = false;
955 // call handlers
956 if (fDocumentHandler != null) {
957 fDocumentHandler.endCDATA(augs);
958 }
959
960 } // endCDATA()
961
962 /**
963 * The end of the document.
964 * @param augs Additional information that may include infoset augmentations
965 *
966 * @throws XNIException Thrown by handler to signal an error.
967 */
968 public void endDocument(Augmentations augs) throws XNIException {
969
970 // call handlers
971 if (fDocumentHandler != null) {
972 fDocumentHandler.endDocument(augs);
973 }
974
975 } // endDocument()
976
977 /**
978 * A comment.
979 *
980 * @param text The text in the comment.
981 * @param augs Additional information that may include infoset augmentations
982 *
983 * @throws XNIException Thrown by application to signal an error.
984 */
985 public void comment(XMLString text, Augmentations augs) throws XNIException {
986 // fixes E15.1
987 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
988 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
989 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
990 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
991 "MSG_CONTENT_INVALID_SPECIFIED",
992 new Object[]{ fCurrentElement.rawname,
993 "EMPTY",
994 "comment"},
995 XMLErrorReporter.SEVERITY_ERROR);
996 }
997 }
998 // call handlers
999 if (fDocumentHandler != null) {
1000 fDocumentHandler.comment(text, augs);
1001 }
1002
1003 } // comment(XMLString)
1004
1005
1006 /**
1007 * A processing instruction. Processing instructions consist of a
1008 * target name and, optionally, text data. The data is only meaningful
1009 * to the application.
1010 * <p>
1011 * Typically, a processing instruction's data will contain a series
1012 * of pseudo-attributes. These pseudo-attributes follow the form of
1013 * element attributes but are <strong>not</strong> parsed or presented
1014 * to the application as anything other than text. The application is
1015 * responsible for parsing the data.
1016 *
1017 * @param target The target.
1018 * @param data The data or null if none specified.
1019 * @param augs Additional information that may include infoset augmentations
1020 *
1021 * @throws XNIException Thrown by handler to signal an error.
1022 */
1023 public void processingInstruction(String target, XMLString data, Augmentations augs)
1024 throws XNIException {
1025
1026 // fixes E15.1
1027 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
1028 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
1029 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
1030 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1031 "MSG_CONTENT_INVALID_SPECIFIED",
1032 new Object[]{ fCurrentElement.rawname,
1033 "EMPTY",
1034 "processing instruction"},
1035 XMLErrorReporter.SEVERITY_ERROR);
1036 }
1037 }
1038 // call handlers
1039 if (fDocumentHandler != null) {
1040 fDocumentHandler.processingInstruction(target, data, augs);
1041 }
1042 } // processingInstruction(String,XMLString)
1043
1044 /**
1045 * This method notifies the start of a general entity.
1046 * <p>
1047 * <strong>Note:</strong> This method is not called for entity references
1048 * appearing as part of attribute values.
1049 *
1050 * @param name The name of the general entity.
1051 * @param identifier The resource identifier.
1052 * @param encoding The auto-detected IANA encoding name of the entity
1053 * stream. This value will be null in those situations
1054 * where the entity encoding is not auto-detected (e.g.
1055 * internal entities or a document entity that is
1056 * parsed from a java.io.Reader).
1057 * @param augs Additional information that may include infoset augmentations
1058 *
1059 * @exception XNIException Thrown by handler to signal an error.
1060 */
1061 public void startGeneralEntity(String name,
1062 XMLResourceIdentifier identifier,
1063 String encoding,
1064 Augmentations augs) throws XNIException {
1065 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) {
1066 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl);
1067 // fixes E15.1
1068 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
1069 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1070 "MSG_CONTENT_INVALID_SPECIFIED",
1071 new Object[]{ fCurrentElement.rawname,
1072 "EMPTY", "ENTITY"},
1073 XMLErrorReporter.SEVERITY_ERROR);
1074 }
1075 if (fGrammarBucket.getStandalone()) {
1076 XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter);
1077 }
1078 }
1079 if (fDocumentHandler != null) {
1080 fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
1081 }
1082 }
1083
1084 /**
1085 * This method notifies the end of a general entity.
1086 * <p>
1087 * <strong>Note:</strong> This method is not called for entity references
1088 * appearing as part of attribute values.
1089 *
1090 * @param name The name of the entity.
1091 * @param augs Additional information that may include infoset augmentations
1092 *
1093 * @exception XNIException
1094 * Thrown by handler to signal an error.
1095 */
1096 public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
1097 // call handlers
1098 if (fDocumentHandler != null) {
1099 fDocumentHandler.endGeneralEntity(name, augs);
1100 }
1101 } // endEntity(String)
1102
1103 /**
1104 * Notifies of the presence of a TextDecl line in an entity. If present,
1105 * this method will be called immediately following the startParameterEntity call.
1106 * <p>
1107 * <strong>Note:</strong> This method is only called for external
1108 * parameter entities referenced in the DTD.
1109 *
1110 * @param version The XML version, or null if not specified.
1111 * @param encoding The IANA encoding name of the entity.
1112 * @param augs Additional information that may include infoset
1113 * augmentations.
1114 *
1115 * @throws XNIException Thrown by handler to signal an error.
1116 */
1117 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
1118
1119 // call handlers
1120 if (fDocumentHandler != null) {
1121 fDocumentHandler.textDecl(version, encoding, augs);
1122 }
1123 }
1124
1125
1126 public final boolean hasGrammar(){
1127
1128 return (fDTDGrammar != null);
1129 }
1130
1131 public final boolean validate(){
1132 // Do validation if all of the following are true:
1133 // 1. The JAXP Schema Language property is not XML Schema
1134 // REVISIT: since only DTD and Schema are supported at this time,
1135 // such checking is sufficient. but if more schema types
1136 // are introduced in the future, we'll need to change it
1137 // to something like
1138 // (fSchemaType == null || fSchemaType == NS_XML_DTD)
1139 // 2. One of the following is true (validation features)
1140 // 2.1 Dynamic validation is off, and validation is on
1141 // 2.2 Dynamic validation is on, and DOCTYPE was seen
1142 // 3 Xerces schema validation feature is off, or DOCTYPE was seen.
1143 return (fSchemaType != Constants.NS_XMLSCHEMA) &&
1144 (!fDynamicValidation && fValidation ||
1145 fDynamicValidation && fSeenDoctypeDecl) &&
1146 (fDTDValidation || fSeenDoctypeDecl);
1147 }
1148
1149 //REVISIT:we can convert into functions.. adding default attribute values.. and one validating.
1150
1151 /** Add default attributes and validate. */
1152 protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex,
1153 XMLAttributes attributes)
1154 throws XNIException {
1155
1156 // is there anything to do?
1157 if (elementIndex == -1 || fDTDGrammar == null) {
1158 return;
1159 }
1160
1161 //
1162 // Check after all specified attrs are scanned
1163 // (1) report error for REQUIRED attrs that are missing (V_TAGc)
1164 // (2) add default attrs (FIXED and NOT_FIXED)
1165 //
1166 int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex);
1167
1168 while (attlistIndex != -1) {
1169
1170 fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl);
1171
1172 if (DEBUG_ATTRIBUTES) {
1173 if (fTempAttDecl != null) {
1174 XMLElementDecl elementDecl = new XMLElementDecl();
1175 fDTDGrammar.getElementDecl(elementIndex, elementDecl);
1176 System.out.println("element: "+(elementDecl.name.localpart));
1177 System.out.println("attlistIndex " + attlistIndex + "\n"+
1178 "attName : '"+(fTempAttDecl.name.localpart) + "'\n"
1179 + "attType : "+fTempAttDecl.simpleType.type + "\n"
1180 + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n"
1181 + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n"
1182 + attributes.getLength() +"\n"
1183 );
1184 }
1185 }
1186 String attPrefix = fTempAttDecl.name.prefix;
1187 String attLocalpart = fTempAttDecl.name.localpart;
1188 String attRawName = fTempAttDecl.name.rawname;
1189 String attType = getAttributeTypeName(fTempAttDecl);
1190 int attDefaultType =fTempAttDecl.simpleType.defaultType;
1191 String attValue = null;
1192
1193 if (fTempAttDecl.simpleType.defaultValue != null) {
1194 attValue = fTempAttDecl.simpleType.defaultValue;
1195 }
1196
1197 boolean specified = false;
1198 boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED;
1199 boolean cdata = attType == XMLSymbols.fCDATASymbol;
1200
1201 if (!cdata || required || attValue != null) {
1202 int attrCount = attributes.getLength();
1203 for (int i = 0; i < attrCount; i++) {
1204 if (attributes.getQName(i) == attRawName) {
1205 specified = true;
1206 break;
1207 }
1208 }
1209 }
1210
1211 if (!specified) {
1212 if (required) {
1213 if (fPerformValidation) {
1214 Object[] args = {elementName.localpart, attRawName};
1215 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1216 "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args,
1217 XMLErrorReporter.SEVERITY_ERROR);
1218 }
1219 }
1220 else if (attValue != null) {
1221 if (fPerformValidation && fGrammarBucket.getStandalone()) {
1222 if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) {
1223
1224 Object[] args = { elementName.localpart, attRawName};
1225 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1226 "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args,
1227 XMLErrorReporter.SEVERITY_ERROR);
1228 }
1229 }
1230
1231 // add namespace information
1232 if (fNamespaces) {
1233 int index = attRawName.indexOf(':');
1234 if (index != -1) {
1235 attPrefix = attRawName.substring(0, index);
1236 attPrefix = fSymbolTable.addSymbol(attPrefix);
1237 attLocalpart = attRawName.substring(index + 1);
1238 attLocalpart = fSymbolTable.addSymbol(attLocalpart);
1239 }
1240 }
1241
1242 // add attribute
1243 fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri);
1244 int newAttr = attributes.addAttribute(fTempQName, attType, attValue);
1245 }
1246 }
1247 // get next att decl in the Grammar for this element
1248 attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex);
1249 }
1250
1251 // now iterate through the expanded attributes for
1252 // 1. if every attribute seen is declared in the DTD
1253 // 2. check if the VC: default_fixed holds
1254 // 3. validate every attribute.
1255 int attrCount = attributes.getLength();
1256 for (int i = 0; i < attrCount; i++) {
1257 String attrRawName = attributes.getQName(i);
1258 boolean declared = false;
1259 if (fPerformValidation) {
1260 if (fGrammarBucket.getStandalone()) {
1261 // check VC: Standalone Document Declaration, entities
1262 // references appear in the document.
1263 // REVISIT: this can be combined to a single check in
1264 // startEntity if we add one more argument in
1265 // startEnity, inAttrValue
1266 String nonNormalizedValue = attributes.getNonNormalizedValue(i);
1267 if (nonNormalizedValue != null) {
1268 String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue);
1269 if (entityName != null) {
1270 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1271 "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE",
1272 new Object[]{entityName},
1273 XMLErrorReporter.SEVERITY_ERROR);
1274 }
1275 }
1276 }
1277 }
1278 int attDefIndex = -1;
1279 int position =
1280 fDTDGrammar.getFirstAttributeDeclIndex(elementIndex);
1281 while (position != -1) {
1282 fDTDGrammar.getAttributeDecl(position, fTempAttDecl);
1283 if (fTempAttDecl.name.rawname == attrRawName) {
1284 // found the match att decl,
1285 attDefIndex = position;
1286 declared = true;
1287 break;
1288 }
1289 position = fDTDGrammar.getNextAttributeDeclIndex(position);
1290 }
1291 if (!declared) {
1292 if (fPerformValidation) {
1293 // REVISIT - cache the elem/attr tuple so that we only
1294 // give this error once for each unique occurrence
1295 Object[] args = { elementName.rawname, attrRawName};
1296
1297 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1298 "MSG_ATTRIBUTE_NOT_DECLARED",
1299 args,XMLErrorReporter.SEVERITY_ERROR);
1300 }
1301 continue;
1302 }
1303 // attribute is declared
1304
1305 // fTempAttDecl should have the right value set now, so
1306 // the following is not needed
1307 // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl);
1308
1309 String type = getAttributeTypeName(fTempAttDecl);
1310 attributes.setType(i, type);
1311 attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
1312
1313 boolean changedByNormalization = false;
1314 String oldValue = attributes.getValue(i);
1315 String attrValue = oldValue;
1316 if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) {
1317 changedByNormalization = normalizeAttrValue(attributes, i);
1318 attrValue = attributes.getValue(i);
1319 if (fPerformValidation && fGrammarBucket.getStandalone()
1320 && changedByNormalization
1321 && fDTDGrammar.getAttributeDeclIsExternal(position)
1322 ) {
1323 // check VC: Standalone Document Declaration
1324 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1325 "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE",
1326 new Object[]{attrRawName, oldValue, attrValue},
1327 XMLErrorReporter.SEVERITY_ERROR);
1328 }
1329 }
1330 if (!fPerformValidation) {
1331 continue;
1332 }
1333 if (fTempAttDecl.simpleType.defaultType ==
1334 XMLSimpleType.DEFAULT_TYPE_FIXED) {
1335 String defaultValue = fTempAttDecl.simpleType.defaultValue;
1336
1337 if (!attrValue.equals(defaultValue)) {
1338 Object[] args = {elementName.localpart,
1339 attrRawName,
1340 attrValue,
1341 defaultValue};
1342 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1343 "MSG_FIXED_ATTVALUE_INVALID",
1344 args, XMLErrorReporter.SEVERITY_ERROR);
1345 }
1346 }
1347
1348 if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY ||
1349 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION ||
1350 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID ||
1351 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF ||
1352 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN ||
1353 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION
1354 ) {
1355 validateDTDattribute(elementName, attrValue, fTempAttDecl);
1356 }
1357 } // for all attributes
1358
1359 } // addDTDDefaultAttrsAndValidate(int,XMLAttrList)
1360
1361 /** Checks entities in attribute values for standalone VC. */
1362 protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) {
1363 int valLength = nonNormalizedValue.length();
1364 int ampIndex = nonNormalizedValue.indexOf('&');
1365 while (ampIndex != -1) {
1366 if (ampIndex + 1 < valLength &&
1367 nonNormalizedValue.charAt(ampIndex+1) != '#') {
1368 int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1);
1369 String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex);
1370 entityName = fSymbolTable.addSymbol(entityName);
1371 int entIndex = fDTDGrammar.getEntityDeclIndex(entityName);
1372 if (entIndex > -1) {
1373 fDTDGrammar.getEntityDecl(entIndex, fEntityDecl);
1374 if (fEntityDecl.inExternal ||
1375 (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) {
1376 return entityName;
1377 }
1378 }
1379 }
1380 ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1);
1381 }
1382 return null;
1383 } // isExternalEntityRefInAttrValue(String):String
1384
1385 /**
1386 * Validate attributes in DTD fashion.
1387 */
1388 protected void validateDTDattribute(QName element, String attValue,
1389 XMLAttributeDecl attributeDecl)
1390 throws XNIException {
1391
1392 switch (attributeDecl.simpleType.type) {
1393 case XMLSimpleType.TYPE_ENTITY: {
1394 // NOTE: Save this information because invalidStandaloneAttDef
1395 boolean isAlistAttribute = attributeDecl.simpleType.list;
1396
1397 try {
1398 if (isAlistAttribute) {
1399 fValENTITIES.validate(attValue, fValidationState);
1400 }
1401 else {
1402 fValENTITY.validate(attValue, fValidationState);
1403 }
1404 }
1405 catch (InvalidDatatypeValueException ex) {
1406 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1407 ex.getKey(),
1408 ex.getArgs(),
1409 XMLErrorReporter.SEVERITY_ERROR );
1410
1411 }
1412 break;
1413 }
1414
1415 case XMLSimpleType.TYPE_NOTATION:
1416 case XMLSimpleType.TYPE_ENUMERATION: {
1417 boolean found = false;
1418 String [] enumVals = attributeDecl.simpleType.enumeration;
1419 if (enumVals == null) {
1420 found = false;
1421 }
1422 else
1423 for (int i = 0; i < enumVals.length; i++) {
1424 if (attValue == enumVals[i] || attValue.equals(enumVals[i])) {
1425 found = true;
1426 break;
1427 }
1428 }
1429
1430 if (!found) {
1431 StringBuffer enumValueString = new StringBuffer();
1432 if (enumVals != null)
1433 for (int i = 0; i < enumVals.length; i++) {
1434 enumValueString.append(enumVals[i]+" ");
1435 }
1436 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1437 "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST",
1438 new Object[]{attributeDecl.name.rawname, attValue, enumValueString},
1439 XMLErrorReporter.SEVERITY_ERROR);
1440 }
1441 break;
1442 }
1443
1444 case XMLSimpleType.TYPE_ID: {
1445 try {
1446 fValID.validate(attValue, fValidationState);
1447 }
1448 catch (InvalidDatatypeValueException ex) {
1449 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1450 ex.getKey(),
1451 ex.getArgs(),
1452 XMLErrorReporter.SEVERITY_ERROR );
1453 }
1454 break;
1455 }
1456
1457 case XMLSimpleType.TYPE_IDREF: {
1458 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
1459
1460 try {
1461 if (isAlistAttribute) {
1462 fValIDRefs.validate(attValue, fValidationState);
1463 }
1464 else {
1465 fValIDRef.validate(attValue, fValidationState);
1466 }
1467 }
1468 catch (InvalidDatatypeValueException ex) {
1469 if (isAlistAttribute) {
1470 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1471 "IDREFSInvalid",
1472 new Object[]{attValue},
1473 XMLErrorReporter.SEVERITY_ERROR );
1474 }
1475 else {
1476 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1477 ex.getKey(),
1478 ex.getArgs(),
1479 XMLErrorReporter.SEVERITY_ERROR );
1480 }
1481
1482 }
1483 break;
1484 }
1485
1486 case XMLSimpleType.TYPE_NMTOKEN: {
1487 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef
1488 //changes fTempAttDef
1489 try {
1490 if (isAlistAttribute) {
1491 fValNMTOKENS.validate(attValue, fValidationState);
1492 }
1493 else {
1494 fValNMTOKEN.validate(attValue, fValidationState);
1495 }
1496 }
1497 catch (InvalidDatatypeValueException ex) {
1498 if (isAlistAttribute) {
1499 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1500 "NMTOKENSInvalid",
1501 new Object[] { attValue},
1502 XMLErrorReporter.SEVERITY_ERROR);
1503 }
1504 else {
1505 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1506 "NMTOKENInvalid",
1507 new Object[] { attValue},
1508 XMLErrorReporter.SEVERITY_ERROR);
1509 }
1510 }
1511 break;
1512 }
1513
1514 } // switch
1515
1516 } // validateDTDattribute(QName,String,XMLAttributeDecl)
1517
1518
1519 /** Returns true if invalid standalone attribute definition. */
1520 protected boolean invalidStandaloneAttDef(QName element, QName attribute) {
1521 // REVISIT: This obviously needs to be fixed! -Ac
1522 boolean state = true;
1523 /*
1524 if (fStandaloneReader == -1) {
1525 return false;
1526 }
1527 // we are normalizing a default att value... this ok?
1528 if (element.rawname == -1) {
1529 return false;
1530 }
1531 return getAttDefIsExternal(element, attribute);
1532 */
1533 return state;
1534 }
1535
1536
1537 //
1538 // Private methods
1539 //
1540
1541
1542 /**
1543 * Normalize the attribute value of a non CDATA attributes collapsing
1544 * sequences of space characters (x20)
1545 *
1546 * @param attributes The list of attributes
1547 * @param index The index of the attribute to normalize
1548 */
1549 private boolean normalizeAttrValue(XMLAttributes attributes, int index) {
1550 // vars
1551 boolean leadingSpace = true;
1552 boolean spaceStart = false;
1553 boolean readingNonSpace = false;
1554 int count = 0;
1555 int eaten = 0;
1556 String attrValue = attributes.getValue(index);
1557 char[] attValue = new char[attrValue.length()];
1558
1559 fBuffer.setLength(0);
1560 attrValue.getChars(0, attrValue.length(), attValue, 0);
1561 for (int i = 0; i < attValue.length; i++) {
1562
1563 if (attValue[i] == ' ') {
1564
1565 // now the tricky part
1566 if (readingNonSpace) {
1567 spaceStart = true;
1568 readingNonSpace = false;
1569 }
1570
1571 if (spaceStart && !leadingSpace) {
1572 spaceStart = false;
1573 fBuffer.append(attValue[i]);
1574 count++;
1575 }
1576 else {
1577 if (leadingSpace || !spaceStart) {
1578 eaten ++;
1579 /*** BUG #3512 ***
1580 int entityCount = attributes.getEntityCount(index);
1581 for (int j = 0; j < entityCount; j++) {
1582 int offset = attributes.getEntityOffset(index, j);
1583 int length = attributes.getEntityLength(index, j);
1584 if (offset <= i-eaten+1) {
1585 if (offset+length >= i-eaten+1) {
1586 if (length > 0)
1587 length--;
1588 }
1589 }
1590 else {
1591 if (offset > 0)
1592 offset--;
1593 }
1594 attributes.setEntityOffset(index, j, offset);
1595 attributes.setEntityLength(index, j, length);
1596 }
1597 /***/
1598 }
1599 }
1600
1601 }
1602 else {
1603 readingNonSpace = true;
1604 spaceStart = false;
1605 leadingSpace = false;
1606 fBuffer.append(attValue[i]);
1607 count++;
1608 }
1609 }
1610
1611 // check if the last appended character is a space.
1612 if (count > 0 && fBuffer.charAt(count-1) == ' ') {
1613 fBuffer.setLength(count-1);
1614 /*** BUG #3512 ***
1615 int entityCount = attributes.getEntityCount(index);
1616 for (int j=0; j < entityCount; j++) {
1617 int offset = attributes.getEntityOffset(index, j);
1618 int length = attributes.getEntityLength(index, j);
1619 if (offset < count-1) {
1620 if (offset+length == count) {
1621 length--;
1622 }
1623 }
1624 else {
1625 offset--;
1626 }
1627 attributes.setEntityOffset(index, j, offset);
1628 attributes.setEntityLength(index, j, length);
1629 }
1630 /***/
1631 }
1632 String newValue = fBuffer.toString();
1633 attributes.setValue(index, newValue);
1634 return ! attrValue.equals(newValue);
1635 }
1636
1637 /** Root element specified. */
1638 private final void rootElementSpecified(QName rootElement) throws XNIException {
1639 if (fPerformValidation) {
1640 String root1 = fRootElement.rawname;
1641 String root2 = rootElement.rawname;
1642 if (root1 == null || !root1.equals(root2)) {
1643 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
1644 "RootElementTypeMustMatchDoctypedecl",
1645 new Object[]{root1, root2},
1646 XMLErrorReporter.SEVERITY_ERROR);
1647 }
1648 }
1649 } // rootElementSpecified(QName)
1650
1651 /**
1652 * Check that the content of an element is valid.
1653 * <p>
1654 * This is the method of primary concern to the validator. This method is called
1655 * upon the scanner reaching the end tag of an element. At that time, the
1656 * element's children must be structurally validated, so it calls this method.
1657 * The index of the element being checked (in the decl pool), is provided as
1658 * well as an array of element name indexes of the children. The validator must
1659 * confirm that this element can have these children in this order.
1660 * <p>
1661 * This can also be called to do 'what if' testing of content models just to see
1662 * if they would be valid.
1663 * <p>
1664 * Note that the element index is an index into the element decl pool, whereas
1665 * the children indexes are name indexes, i.e. into the string pool.
1666 * <p>
1667 * A value of -1 in the children array indicates a PCDATA node. All other
1668 * indexes will be positive and represent child elements. The count can be
1669 * zero, since some elements have the EMPTY content model and that must be
1670 * confirmed.
1671 *
1672 * @param elementIndex The index within the <code>ElementDeclPool</code> of this
1673 * element.
1674 * @param childCount The number of entries in the <code>children</code> array.
1675 * @param children The children of this element.
1676 *
1677 * @return The value -1 if fully valid, else the 0 based index of the child
1678 * that first failed. If the value returned is equal to the number
1679 * of children, then additional content is required to reach a valid
1680 * ending state.
1681 *
1682 * @exception Exception Thrown on error.
1683 */
1684 private int checkContent(int elementIndex,
1685 QName[] children,
1686 int childOffset,
1687 int childCount) throws XNIException {
1688
1689 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
1690
1691 // Get the element name index from the element
1692 final String elementType = fCurrentElement.rawname;
1693
1694 // Get out the content spec for this element
1695 final int contentType = fCurrentContentSpecType;
1696
1697
1698 //
1699 // Deal with the possible types of content. We try to optimized here
1700 // by dealing specially with content models that don't require the
1701 // full DFA treatment.
1702 //
1703 if (contentType == XMLElementDecl.TYPE_EMPTY) {
1704 //
1705 // If the child count is greater than zero, then this is
1706 // an error right off the bat at index 0.
1707 //
1708 if (childCount != 0) {
1709 return 0;
1710 }
1711 }
1712 else if (contentType == XMLElementDecl.TYPE_ANY) {
1713 //
1714 // This one is open game so we don't pass any judgement on it
1715 // at all. Its assumed to fine since it can hold anything.
1716 //
1717 }
1718 else if (contentType == XMLElementDecl.TYPE_MIXED ||
1719 contentType == XMLElementDecl.TYPE_CHILDREN) {
1720 // Get the content model for this element, faulting it in if needed
1721 ContentModelValidator cmElem = null;
1722 cmElem = fTempElementDecl.contentModelValidator;
1723 int result = cmElem.validate(children, childOffset, childCount);
1724 return result;
1725 }
1726 else if (contentType == -1) {
1727 //REVISIT
1728 /****
1729 reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED,
1730 XMLMessages.VC_ELEMENT_VALID,
1731 elementType);
1732 /****/
1733 }
1734 else if (contentType == XMLElementDecl.TYPE_SIMPLE) {
1735
1736 //REVISIT
1737 // this should never be reached in the case of DTD validation.
1738
1739 }
1740 else {
1741 //REVISIT
1742 /****
1743 fErrorReporter.reportError(fErrorReporter.getLocator(),
1744 ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN,
1745 ImplementationMessages.VAL_CST,
1746 0,
1747 null,
1748 XMLErrorReporter.ERRORTYPE_FATAL_ERROR);
1749 /****/
1750 }
1751
1752 // We succeeded
1753 return -1;
1754
1755 } // checkContent(int,int,QName[]):int
1756
1757 /** Returns the content spec type for an element index. */
1758 private int getContentSpecType(int elementIndex) {
1759
1760 int contentSpecType = -1;
1761 if (elementIndex > -1) {
1762 if (fDTDGrammar.getElementDecl(elementIndex,fTempElementDecl)) {
1763 contentSpecType = fTempElementDecl.type;
1764 }
1765 }
1766 return contentSpecType;
1767 }
1768
1769 /** Character data in content. */
1770 private void charDataInContent() {
1771
1772 if (DEBUG_ELEMENT_CHILDREN) {
1773 System.out.println("charDataInContent()");
1774 }
1775 if (fElementChildren.length <= fElementChildrenLength) {
1776 QName[] newarray = new QName[fElementChildren.length * 2];
1777 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
1778 fElementChildren = newarray;
1779 }
1780 QName qname = fElementChildren[fElementChildrenLength];
1781 if (qname == null) {
1782 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
1783 fElementChildren[i] = new QName();
1784 }
1785 qname = fElementChildren[fElementChildrenLength];
1786 }
1787 qname.clear();
1788 fElementChildrenLength++;
1789
1790 } // charDataInCount()
1791
1792 /** convert attribute type from ints to strings */
1793 private String getAttributeTypeName(XMLAttributeDecl attrDecl) {
1794
1795 switch (attrDecl.simpleType.type) {
1796 case XMLSimpleType.TYPE_ENTITY: {
1797 return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol;
1798 }
1799 case XMLSimpleType.TYPE_ENUMERATION: {
1800 StringBuffer buffer = new StringBuffer();
1801 buffer.append('(');
1802 for (int i=0; i<attrDecl.simpleType.enumeration.length ; i++) {
1803 if (i > 0) {
1804 buffer.append("|");
1805 }
1806 buffer.append(attrDecl.simpleType.enumeration[i]);
1807 }
1808 buffer.append(')');
1809 return fSymbolTable.addSymbol(buffer.toString());
1810 }
1811 case XMLSimpleType.TYPE_ID: {
1812 return XMLSymbols.fIDSymbol;
1813 }
1814 case XMLSimpleType.TYPE_IDREF: {
1815 return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol;
1816 }
1817 case XMLSimpleType.TYPE_NMTOKEN: {
1818 return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol;
1819 }
1820 case XMLSimpleType.TYPE_NOTATION: {
1821 return XMLSymbols.fNOTATIONSymbol;
1822 }
1823 }
1824 return XMLSymbols.fCDATASymbol;
1825
1826 } // getAttributeTypeName(XMLAttributeDecl):String
1827
1828 /** initialization */
1829 protected void init() {
1830
1831 // datatype validators
1832 if (fValidation || fDynamicValidation) {
1833 try {
1834 //REVISIT: datatypeRegistry + initialization of datatype
1835 // why do we cast to ListDatatypeValidator?
1836 fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol);
1837 fValIDRef = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol);
1838 fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol);
1839 fValENTITY = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol);
1840 fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol);
1841 fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol);
1842 fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol);
1843 fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol);
1844
1845 }
1846 catch (Exception e) {
1847 // should never happen
1848 e.printStackTrace(System.err);
1849 }
1850
1851 }
1852
1853 } // init()
1854
1855 /** ensure element stack capacity */
1856 private void ensureStackCapacity (int newElementDepth) {
1857 if (newElementDepth == fElementQNamePartsStack.length) {
1858
1859 QName[] newStackOfQueue = new QName[newElementDepth * 2];
1860 System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth );
1861 fElementQNamePartsStack = newStackOfQueue;
1862
1863 QName qname = fElementQNamePartsStack[newElementDepth];
1864 if (qname == null) {
1865 for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) {
1866 fElementQNamePartsStack[i] = new QName();
1867 }
1868 }
1869
1870 int[] newStack = new int[newElementDepth * 2];
1871 System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth);
1872 fElementIndexStack = newStack;
1873
1874 newStack = new int[newElementDepth * 2];
1875 System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth);
1876 fContentSpecTypeStack = newStack;
1877
1878 }
1879 } // ensureStackCapacity
1880
1881
1882 //
1883 // Protected methods
1884 //
1885
1886 /** Handle element
1887 * @return true if validator is removed from the pipeline
1888 */
1889 protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs)
1890 throws XNIException {
1891
1892
1893 // VC: Root Element Type
1894 // see if the root element's name matches the one in DoctypeDecl
1895 if (!fSeenRootElement) {
1896 // REVISIT: Here are current assumptions about validation features
1897 // given that XMLSchema validator is in the pipeline
1898 //
1899 // http://xml.org/sax/features/validation = true
1900 // http://apache.org/xml/features/validation/schema = true
1901 //
1902 // [1] XML instance document only has reference to a DTD
1903 // Outcome: report validation errors only against dtd.
1904 //
1905 // [2] XML instance document has only XML Schema grammars:
1906 // Outcome: report validation errors only against schemas (no errors produced from DTD validator)
1907 //
1908 // [3] XML instance document has DTD and XML schemas:
1909 // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas.
1910 // [b] if schema language is set to XML Schema - do not report validation errors
1911 //
1912 // if dynamic validation is on
1913 // validate only against grammar we've found (depending on settings
1914 // for schema feature)
1915 //
1916 //
1917 fPerformValidation = validate();
1918 fSeenRootElement = true;
1919 fValidationManager.setEntityState(fDTDGrammar);
1920 fValidationManager.setGrammarFound(fSeenDoctypeDecl);
1921 rootElementSpecified(element);
1922 }
1923 if (fDTDGrammar == null) {
1924
1925 if (!fPerformValidation) {
1926 fCurrentElementIndex = -1;
1927 fCurrentContentSpecType = -1;
1928 fInElementContent = false;
1929 }
1930 if (fPerformValidation) {
1931 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1932 "MSG_GRAMMAR_NOT_FOUND",
1933 new Object[]{ element.rawname},
1934 XMLErrorReporter.SEVERITY_ERROR);
1935 }
1936 // modify pipeline
1937 if (fDocumentSource !=null ) {
1938 fDocumentSource.setDocumentHandler(fDocumentHandler);
1939 if (fDocumentHandler != null)
1940 fDocumentHandler.setDocumentSource(fDocumentSource);
1941 return true;
1942 }
1943 }
1944 else {
1945 // resolve the element
1946 fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element);
1947 //changed here.. new function for getContentSpecType
1948 fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex);
1949 if (fCurrentContentSpecType == -1 && fPerformValidation) {
1950 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
1951 "MSG_ELEMENT_NOT_DECLARED",
1952 new Object[]{ element.rawname},
1953 XMLErrorReporter.SEVERITY_ERROR);
1954 }
1955
1956 // 0. insert default attributes
1957 // 1. normalize the attributes
1958 // 2. validate the attrivute list.
1959 // TO DO:
1960 //changed here.. also pass element name,
1961 addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes);
1962 }
1963
1964 // set element content state
1965 fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN;
1966
1967 // increment the element depth, add this element's
1968 // QName to its enclosing element 's children list
1969 fElementDepth++;
1970 if (fPerformValidation) {
1971 // push current length onto stack
1972 if (fElementChildrenOffsetStack.length <= fElementDepth) {
1973 int newarray[] = new int[fElementChildrenOffsetStack.length * 2];
1974 System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length);
1975 fElementChildrenOffsetStack = newarray;
1976 }
1977 fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength;
1978
1979 // add this element to children
1980 if (fElementChildren.length <= fElementChildrenLength) {
1981 QName[] newarray = new QName[fElementChildrenLength * 2];
1982 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length);
1983 fElementChildren = newarray;
1984 }
1985 QName qname = fElementChildren[fElementChildrenLength];
1986 if (qname == null) {
1987 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) {
1988 fElementChildren[i] = new QName();
1989 }
1990 qname = fElementChildren[fElementChildrenLength];
1991 }
1992 qname.setValues(element);
1993 fElementChildrenLength++;
1994 }
1995
1996 // save current element information
1997 fCurrentElement.setValues(element);
1998 ensureStackCapacity(fElementDepth);
1999 fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement);
2000 fElementIndexStack[fElementDepth] = fCurrentElementIndex;
2001 fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType;
2002 startNamespaceScope(element, attributes, augs);
2003 return false;
2004
2005 } // handleStartElement(QName,XMLAttributes)
2006
2007 protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){
2008 }
2009
2010 /** Handle end element. */
2011 protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty)
2012 throws XNIException {
2013
2014 // decrease element depth
2015 fElementDepth--;
2016
2017 // validate
2018 if (fPerformValidation) {
2019 int elementIndex = fCurrentElementIndex;
2020 if (elementIndex != -1 && fCurrentContentSpecType != -1) {
2021 QName children[] = fElementChildren;
2022 int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
2023 int childrenLength = fElementChildrenLength - childrenOffset;
2024 int result = checkContent(elementIndex,
2025 children, childrenOffset, childrenLength);
2026
2027 if (result != -1) {
2028 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl);
2029 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) {
2030 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
2031 "MSG_CONTENT_INVALID",
2032 new Object[]{ element.rawname, "EMPTY"},
2033 XMLErrorReporter.SEVERITY_ERROR);
2034 }
2035 else {
2036 String messageKey = result != childrenLength ?
2037 "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE";
2038 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
2039 messageKey,
2040 new Object[]{ element.rawname,
2041 fDTDGrammar.getContentSpecAsString(elementIndex)},
2042 XMLErrorReporter.SEVERITY_ERROR);
2043 }
2044 }
2045 }
2046 fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1;
2047 }
2048
2049 endNamespaceScope(fCurrentElement, augs, isEmpty);
2050
2051 // now pop this element off the top of the element stack
2052 if (fElementDepth < -1) {
2053 throw new RuntimeException("FWK008 Element stack underflow");
2054 }
2055 if (fElementDepth < 0) {
2056 fCurrentElement.clear();
2057 fCurrentElementIndex = -1;
2058 fCurrentContentSpecType = -1;
2059 fInElementContent = false;
2060
2061 // TO DO : fix this
2062 //
2063 // Check after document is fully parsed
2064 // (1) check that there was an element with a matching id for every
2065 // IDREF and IDREFS attr (V_IDREF0)
2066 //
2067 if (fPerformValidation) {
2068 String value = fValidationState.checkIDRefID();
2069 if (value != null) {
2070 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
2071 "MSG_ELEMENT_WITH_ID_REQUIRED",
2072 new Object[]{value},
2073 XMLErrorReporter.SEVERITY_ERROR );
2074 }
2075 }
2076 return;
2077 }
2078
2079 // If Namespace enable then localName != rawName
2080 fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]);
2081
2082 fCurrentElementIndex = fElementIndexStack[fElementDepth];
2083 fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth];
2084 fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN);
2085
2086 } // handleEndElement(QName,boolean)
2087
2088 protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty){
2089
2090 // call handlers
2091 if (fDocumentHandler != null && !isEmpty) {
2092 // NOTE: The binding of the element doesn't actually happen
2093 // yet because the namespace binder does that. However,
2094 // if it does it before this point, then the endPrefix-
2095 // Mapping calls get made too soon! As long as the
2096 // rawnames match, we know it'll have a good binding,
2097 // so we can just use the current element. -Ac
2098 fDocumentHandler.endElement(fCurrentElement, augs);
2099 }
2100 }
2101
2102 // returns whether a character is space according to the
2103 // version of XML this validator supports.
2104 protected boolean isSpace(int c) {
2105 return XMLChar.isSpace(c);
2106 } // isSpace(int): boolean
2107
2108 public boolean characterData(String data, Augmentations augs) {
2109 characters(new XMLString(data.toCharArray(), 0, data.length()), augs);
2110 return true;
2111 }
2112
2113 } // class XMLDTDValidator