KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > XMLNSDocumentScannerImpl


1 /*
2  * Copyright 1999-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl;
18
19 import java.io.IOException JavaDoc;
20
21 import org.apache.xerces.impl.dtd.XMLDTDValidatorFilter;
22 import org.apache.xerces.impl.msg.XMLMessageFormatter;
23 import org.apache.xerces.util.XMLAttributesImpl;
24 import org.apache.xerces.util.XMLSymbols;
25 import org.apache.xerces.xni.NamespaceContext;
26 import org.apache.xerces.xni.QName;
27 import org.apache.xerces.xni.XMLDocumentHandler;
28 import org.apache.xerces.xni.XNIException;
29 import org.apache.xerces.xni.parser.XMLComponentManager;
30 import org.apache.xerces.xni.parser.XMLConfigurationException;
31 import org.apache.xerces.xni.parser.XMLDocumentSource;
32
33 /**
34  * The scanner acts as the source for the document
35  * information which is communicated to the document handler.
36  *
37  * This class scans an XML document, checks if document has a DTD, and if
38  * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
39  * namespace binding.
40  *
41  * Note: This scanner should only be used when the namespace processing is on!
42  *
43  * <p>
44  * This component requires the following features and properties from the
45  * component manager that uses it:
46  * <ul>
47  * <li>http://xml.org/sax/features/namespaces {true} -- if the value of this
48  * feature is set to false this scanner must not be used.</li>
49  * <li>http://xml.org/sax/features/validation</li>
50  * <li>http://apache.org/xml/features/nonvalidating/load-external-dtd</li>
51  * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
52  * <li>http://apache.org/xml/features/scanner/notify-builtin-refs</li>
53  * <li>http://apache.org/xml/properties/internal/symbol-table</li>
54  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
55  * <li>http://apache.org/xml/properties/internal/entity-manager</li>
56  * <li>http://apache.org/xml/properties/internal/dtd-scanner</li>
57  * </ul>
58  *
59  * @xerces.internal
60  *
61  * @author Elena Litani, IBM
62  *
63  * @version $Id: XMLNSDocumentScannerImpl.java,v 1.25 2004/10/04 21:45:48 mrglavas Exp $
64  */

65 public class XMLNSDocumentScannerImpl
66 extends XMLDocumentScannerImpl {
67
68     /** If is true, the dtd validator is no longer in the pipeline
69       * and the scanner should bind namespaces */

70     protected boolean fBindNamespaces;
71
72     /** If validating parser, make sure we report an error in the
73       * scanner if DTD grammar is missing.*/

74     protected boolean fPerformValidation;
75
76     // private data
77
//
78

79     /** DTD validator */
80     private XMLDTDValidatorFilter fDTDValidator;
81     
82     /**
83      * Saw spaces after element name or between attributes.
84      *
85      * This is reserved for the case where scanning of a start element spans
86      * several methods, as is the case when scanning the start of a root element
87      * where a DTD external subset may be read after scanning the element name.
88      */

89     private boolean fSawSpace;
90
91
92     /**
93      * The scanner is responsible for removing DTD validator
94      * from the pipeline if it is not needed.
95      *
96      * @param previous The filter component before DTDValidator
97      * @param dtdValidator
98      * The DTDValidator
99      * @param next The documentHandler after the DTDValidator
100      */

101     public void setDTDValidator(XMLDTDValidatorFilter dtd){
102         fDTDValidator = dtd;
103     }
104
105     /**
106      * Scans a start element. This method will handle the binding of
107      * namespace information and notifying the handler of the start
108      * of the element.
109      * <p>
110      * <pre>
111      * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
112      * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
113      * </pre>
114      * <p>
115      * <strong>Note:</strong> This method assumes that the leading
116      * '&lt;' character has been consumed.
117      * <p>
118      * <strong>Note:</strong> This method uses the fElementQName and
119      * fAttributes variables. The contents of these variables will be
120      * destroyed. The caller should copy important information out of
121      * these variables before calling this method.
122      *
123      * @return True if element is empty. (i.e. It matches
124      * production [44].
125      */

126     protected boolean scanStartElement()
127     throws IOException JavaDoc, XNIException {
128         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElementNS()");
129
130         // Note: namespace processing is on by default
131
fEntityScanner.scanQName(fElementQName);
132         // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
133
String JavaDoc rawname = fElementQName.rawname;
134         if (fBindNamespaces) {
135             fNamespaceContext.pushContext();
136             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
137                 if (fPerformValidation) {
138                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
139                                                "MSG_GRAMMAR_NOT_FOUND",
140                                                new Object JavaDoc[]{ rawname},
141                                                XMLErrorReporter.SEVERITY_ERROR);
142
143                     if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
144                         fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
145                                                     "RootElementTypeMustMatchDoctypedecl",
146                                                     new Object JavaDoc[]{fDoctypeName, rawname},
147                                                     XMLErrorReporter.SEVERITY_ERROR);
148                     }
149                 }
150             }
151         }
152
153         // push element stack
154
fCurrentElement = fElementStack.pushElement(fElementQName);
155
156         // attributes
157
boolean empty = false;
158         fAttributes.removeAllAttributes();
159         do {
160             // spaces
161
boolean sawSpace = fEntityScanner.skipSpaces();
162
163             // end tag?
164
int c = fEntityScanner.peekChar();
165             if (c == '>') {
166                 fEntityScanner.scanChar();
167                 break;
168             }
169             else if (c == '/') {
170                 fEntityScanner.scanChar();
171                 if (!fEntityScanner.skipChar('>')) {
172                     reportFatalError("ElementUnterminated",
173                                      new Object JavaDoc[]{rawname});
174                 }
175                 empty = true;
176                 break;
177             }
178             else if (!isValidNameStartChar(c) || !sawSpace) {
179                 reportFatalError("ElementUnterminated", new Object JavaDoc[]{rawname});
180             }
181
182             // attributes
183
scanAttribute(fAttributes);
184
185         } while (true);
186
187         if (fBindNamespaces) {
188             // REVISIT: is it required? forbit xmlns prefix for element
189
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
190                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
191                                            "ElementXMLNSPrefix",
192                                            new Object JavaDoc[]{fElementQName.rawname},
193                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
194             }
195
196             // bind the element
197
String JavaDoc prefix = fElementQName.prefix != null
198                             ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
199             // assign uri to the element
200
fElementQName.uri = fNamespaceContext.getURI(prefix);
201             // make sure that object in the element stack is updated as well
202
fCurrentElement.uri = fElementQName.uri;
203
204             if (fElementQName.prefix == null && fElementQName.uri != null) {
205                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
206                 // making sure that the object in the element stack is updated too.
207
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
208             }
209             if (fElementQName.prefix != null && fElementQName.uri == null) {
210                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
211                                            "ElementPrefixUnbound",
212                                            new Object JavaDoc[]{fElementQName.prefix, fElementQName.rawname},
213                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
214             }
215
216             // bind attributes (xmlns are already bound bellow)
217
int length = fAttributes.getLength();
218             // fLength = 0; //initialize structure
219
for (int i = 0; i < length; i++) {
220                 fAttributes.getName(i, fAttributeQName);
221
222                 String JavaDoc aprefix = fAttributeQName.prefix != null
223                                  ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
224                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
225                 // REVISIT: try removing the first "if" and see if it is faster.
226
//
227
if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
228                     // checkDuplicates(fAttributeQName, fAttributes);
229
continue;
230                 }
231                 if (aprefix != XMLSymbols.EMPTY_STRING) {
232                     fAttributeQName.uri = uri;
233                     if (uri == null) {
234                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
235                                                    "AttributePrefixUnbound",
236                                                    new Object JavaDoc[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
237                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
238                     }
239                     fAttributes.setURI(i, uri);
240                     // checkDuplicates(fAttributeQName, fAttributes);
241
}
242             }
243             
244             if (length > 1) {
245                 QName name = fAttributes.checkDuplicatesNS();
246                 if (name != null) {
247                     if (name.uri != null) {
248                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
249                                                    "AttributeNSNotUnique",
250                                                    new Object JavaDoc[]{fElementQName.rawname, name.localpart, name.uri},
251                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
252                     }
253                     else {
254                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
255                                                    "AttributeNotUnique",
256                                                    new Object JavaDoc[]{fElementQName.rawname, name.rawname},
257                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
258                     }
259                 }
260             }
261         }
262
263
264         // call handler
265
if (fDocumentHandler != null) {
266             if (empty) {
267
268                 //decrease the markup depth..
269
fMarkupDepth--;
270
271                 // check that this element was opened in the same entity
272
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
273                     reportFatalError("ElementEntityMismatch",
274                                      new Object JavaDoc[]{fCurrentElement.rawname});
275                 }
276
277                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
278
279                 if (fBindNamespaces) {
280                     fNamespaceContext.popContext();
281                 }
282                 //pop the element off the stack..
283
fElementStack.popElement(fElementQName);
284             } else {
285                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
286             }
287         }
288
289         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty);
290         return empty;
291
292     } // scanStartElement():boolean
293

294     /**
295      * Scans the name of an element in a start or empty tag.
296      *
297      * @see #scanStartElement()
298      */

299     protected void scanStartElementName ()
300         throws IOException JavaDoc, XNIException {
301         // Note: namespace processing is on by default
302
fEntityScanner.scanQName(fElementQName);
303         // Must skip spaces here because the DTD scanner
304
// would consume them at the end of the external subset.
305
fSawSpace = fEntityScanner.skipSpaces();
306     } // scanStartElementName()
307

308     /**
309      * Scans the remainder of a start or empty tag after the element name.
310      *
311      * @see #scanStartElement
312      * @return True if element is empty.
313      */

314     protected boolean scanStartElementAfterName()
315         throws IOException JavaDoc, XNIException {
316         
317         // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
318
String JavaDoc rawname = fElementQName.rawname;
319         if (fBindNamespaces) {
320             fNamespaceContext.pushContext();
321             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
322                 if (fPerformValidation) {
323                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
324                                                "MSG_GRAMMAR_NOT_FOUND",
325                                                new Object JavaDoc[]{ rawname},
326                                                XMLErrorReporter.SEVERITY_ERROR);
327
328                     if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
329                         fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
330                                                     "RootElementTypeMustMatchDoctypedecl",
331                                                     new Object JavaDoc[]{fDoctypeName, rawname},
332                                                     XMLErrorReporter.SEVERITY_ERROR);
333                     }
334                 }
335             }
336         }
337
338         // push element stack
339
fCurrentElement = fElementStack.pushElement(fElementQName);
340
341         // attributes
342
boolean empty = false;
343         fAttributes.removeAllAttributes();
344         do {
345             
346             // end tag?
347
int c = fEntityScanner.peekChar();
348             if (c == '>') {
349                 fEntityScanner.scanChar();
350                 break;
351             }
352             else if (c == '/') {
353                 fEntityScanner.scanChar();
354                 if (!fEntityScanner.skipChar('>')) {
355                     reportFatalError("ElementUnterminated",
356                                      new Object JavaDoc[]{rawname});
357                 }
358                 empty = true;
359                 break;
360             }
361             else if (!isValidNameStartChar(c) || !fSawSpace) {
362                 reportFatalError("ElementUnterminated", new Object JavaDoc[]{rawname});
363             }
364
365             // attributes
366
scanAttribute(fAttributes);
367             
368             // spaces
369
fSawSpace = fEntityScanner.skipSpaces();
370
371         } while (true);
372
373         if (fBindNamespaces) {
374             // REVISIT: is it required? forbit xmlns prefix for element
375
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
376                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
377                                            "ElementXMLNSPrefix",
378                                            new Object JavaDoc[]{fElementQName.rawname},
379                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
380             }
381
382             // bind the element
383
String JavaDoc prefix = fElementQName.prefix != null
384                             ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
385             // assign uri to the element
386
fElementQName.uri = fNamespaceContext.getURI(prefix);
387             // make sure that object in the element stack is updated as well
388
fCurrentElement.uri = fElementQName.uri;
389
390             if (fElementQName.prefix == null && fElementQName.uri != null) {
391                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
392                 // making sure that the object in the element stack is updated too.
393
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
394             }
395             if (fElementQName.prefix != null && fElementQName.uri == null) {
396                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
397                                            "ElementPrefixUnbound",
398                                            new Object JavaDoc[]{fElementQName.prefix, fElementQName.rawname},
399                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
400             }
401
402             // bind attributes (xmlns are already bound bellow)
403
int length = fAttributes.getLength();
404             // fLength = 0; //initialize structure
405
for (int i = 0; i < length; i++) {
406                 fAttributes.getName(i, fAttributeQName);
407
408                 String JavaDoc aprefix = fAttributeQName.prefix != null
409                                  ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
410                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
411                 // REVISIT: try removing the first "if" and see if it is faster.
412
//
413
if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
414                     // checkDuplicates(fAttributeQName, fAttributes);
415
continue;
416                 }
417                 if (aprefix != XMLSymbols.EMPTY_STRING) {
418                     fAttributeQName.uri = uri;
419                     if (uri == null) {
420                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
421                                                    "AttributePrefixUnbound",
422                                                    new Object JavaDoc[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
423                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
424                     }
425                     fAttributes.setURI(i, uri);
426                     // checkDuplicates(fAttributeQName, fAttributes);
427
}
428             }
429             
430             if (length > 1) {
431                 QName name = fAttributes.checkDuplicatesNS();
432                 if (name != null) {
433                     if (name.uri != null) {
434                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
435                                                    "AttributeNSNotUnique",
436                                                    new Object JavaDoc[]{fElementQName.rawname, name.localpart, name.uri},
437                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
438                     }
439                     else {
440                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
441                                                    "AttributeNotUnique",
442                                                    new Object JavaDoc[]{fElementQName.rawname, name.rawname},
443                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
444                     }
445                 }
446             }
447         }
448
449
450         // call handler
451
if (fDocumentHandler != null) {
452             if (empty) {
453
454                 //decrease the markup depth..
455
fMarkupDepth--;
456
457                 // check that this element was opened in the same entity
458
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
459                     reportFatalError("ElementEntityMismatch",
460                                      new Object JavaDoc[]{fCurrentElement.rawname});
461                 }
462
463                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
464
465                 if (fBindNamespaces) {
466                     fNamespaceContext.popContext();
467                 }
468                 //pop the element off the stack..
469
fElementStack.popElement(fElementQName);
470             } else {
471                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
472             }
473         }
474
475         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty);
476         return empty;
477     } // scanStartElementAfterName()
478

479     /**
480      * Scans an attribute.
481      * <p>
482      * <pre>
483      * [41] Attribute ::= Name Eq AttValue
484      * </pre>
485      * <p>
486      * <strong>Note:</strong> This method assumes that the next
487      * character on the stream is the first character of the attribute
488      * name.
489      * <p>
490      * <strong>Note:</strong> This method uses the fAttributeQName and
491      * fQName variables. The contents of these variables will be
492      * destroyed.
493      *
494      * @param attributes The attributes list for the scanned attribute.
495      */

496     protected void scanAttribute(XMLAttributesImpl attributes)
497     throws IOException JavaDoc, XNIException {
498         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()");
499
500         // name
501
fEntityScanner.scanQName(fAttributeQName);
502
503         // equals
504
fEntityScanner.skipSpaces();
505         if (!fEntityScanner.skipChar('=')) {
506             reportFatalError("EqRequiredInAttribute",
507                              new Object JavaDoc[]{fCurrentElement.rawname,fAttributeQName.rawname});
508         }
509         fEntityScanner.skipSpaces();
510
511         // content
512
int attrIndex;
513        
514         if (fBindNamespaces) {
515             attrIndex = attributes.getLength();
516             attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
517         }
518         else {
519             int oldLen = attributes.getLength();
520             attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
521             
522             // WFC: Unique Att Spec
523
if (oldLen == attributes.getLength()) {
524                 reportFatalError("AttributeNotUnique",
525                                  new Object JavaDoc[]{fCurrentElement.rawname,
526                                  fAttributeQName.rawname});
527             }
528         }
529
530         //REVISIT: one more case needs to be included: external PE and standalone is no
531
boolean isVC = fHasExternalDTD && !fStandalone;
532
533         // Scan attribute value and return true if the non-normalized and normalized value are the same
534
boolean isSameNormalizedAttr = scanAttributeValue(this.fTempString, fTempString2,
535                 fAttributeQName.rawname, isVC, fCurrentElement.rawname);
536         
537         String JavaDoc value = fTempString.toString();
538         attributes.setValue(attrIndex, value);
539         // If the non-normalized and normalized value are the same, avoid creating a new string.
540
if (!isSameNormalizedAttr) {
541             attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
542         }
543         attributes.setSpecified(attrIndex, true);
544
545         // record namespace declarations if any.
546
if (fBindNamespaces) {
547             
548             String JavaDoc localpart = fAttributeQName.localpart;
549             String JavaDoc prefix = fAttributeQName.prefix != null
550                             ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
551             // when it's of form xmlns="..." or xmlns:prefix="...",
552
// it's a namespace declaration. but prefix:xmlns="..." isn't.
553
if (prefix == XMLSymbols.PREFIX_XMLNS ||
554                 prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
555
556                 // get the internalized value of this attribute
557
String JavaDoc uri = fSymbolTable.addSymbol(value);
558
559                 // 1. "xmlns" can't be bound to any namespace
560
if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
561                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
562                                                "CantBindXMLNS",
563                                                new Object JavaDoc[]{fAttributeQName},
564                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
565                 }
566
567                 // 2. the namespace for "xmlns" can't be bound to any prefix
568
if (uri == NamespaceContext.XMLNS_URI) {
569                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
570                                                "CantBindXMLNS",
571                                                new Object JavaDoc[]{fAttributeQName},
572                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
573                 }
574
575                 // 3. "xml" can't be bound to any other namespace than it's own
576
if (localpart == XMLSymbols.PREFIX_XML) {
577                     if (uri != NamespaceContext.XML_URI) {
578                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
579                                                    "CantBindXML",
580                                                    new Object JavaDoc[]{fAttributeQName},
581                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
582                     }
583                 }
584                 // 4. the namespace for "xml" can't be bound to any other prefix
585
else {
586                     if (uri ==NamespaceContext.XML_URI) {
587                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
588                                                    "CantBindXML",
589                                                    new Object JavaDoc[]{fAttributeQName},
590                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
591                     }
592                 }
593
594                 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
595
596                 // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
597
// We should only report an error if there is a prefix,
598
// that is, the local part is not "xmlns". -SG
599
if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
600                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
601                                                "EmptyPrefixedAttName",
602                                                new Object JavaDoc[]{fAttributeQName},
603                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
604                 }
605
606                 // declare prefix in context
607
fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
608                 // bind namespace attribute to a namespace
609
attributes.setURI(attrIndex, fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS));
610
611             }
612             else {
613                 // attempt to bind attribute
614
if (fAttributeQName.prefix != null) {
615                     attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
616                 }
617             }
618         }
619
620         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()");
621     } // scanAttribute(XMLAttributes)
622

623
624
625     /**
626      * Scans an end element.
627      * <p>
628      * <pre>
629      * [42] ETag ::= '&lt;/' Name S? '>'
630      * </pre>
631      * <p>
632      * <strong>Note:</strong> This method uses the fElementQName variable.
633      * The contents of this variable will be destroyed. The caller should
634      * copy the needed information out of this variable before calling
635      * this method.
636      *
637      * @return The element depth.
638      */

639     protected int scanEndElement() throws IOException JavaDoc, XNIException {
640         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()");
641
642         // pop context
643
fElementStack.popElement(fElementQName) ;
644
645         // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
646
//In scanners most of the time is consumed on checks done for XML characters, we can
647
// optimize on it and avoid the checks done for endElement,
648
//we will also avoid symbol table lookup - neeraj.bajaj@sun.com
649

650         // this should work both for namespace processing true or false...
651

652         //REVISIT: if the string is not the same as expected.. we need to do better error handling..
653
//We can skip this for now... In any case if the string doesn't match -- document is not well formed.
654
if (!fEntityScanner.skipString(fElementQName.rawname)) {
655             reportFatalError("ETagRequired", new Object JavaDoc[]{fElementQName.rawname});
656         }
657
658         // end
659
fEntityScanner.skipSpaces();
660         if (!fEntityScanner.skipChar('>')) {
661             reportFatalError("ETagUnterminated",
662                              new Object JavaDoc[]{fElementQName.rawname});
663         }
664         fMarkupDepth--;
665
666         //we have increased the depth for two markup "<" characters
667
fMarkupDepth--;
668
669         // check that this element was opened in the same entity
670
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
671             reportFatalError("ElementEntityMismatch",
672                              new Object JavaDoc[]{fCurrentElement.rawname});
673         }
674
675         // call handler
676
if (fDocumentHandler != null ) {
677
678             fDocumentHandler.endElement(fElementQName, null);
679             if (fBindNamespaces) {
680                 fNamespaceContext.popContext();
681             }
682
683         }
684
685         return fMarkupDepth;
686
687     } // scanEndElement():int
688

689
690     public void reset(XMLComponentManager componentManager)
691     throws XMLConfigurationException {
692
693         super.reset(componentManager);
694         fPerformValidation = false;
695         fBindNamespaces = false;
696     }
697
698     /** Creates a content dispatcher. */
699     protected Dispatcher createContentDispatcher() {
700         return new NSContentDispatcher();
701     } // createContentDispatcher():Dispatcher
702

703     /**
704      * Dispatcher to handle content scanning.
705      */

706     protected final class NSContentDispatcher
707         extends ContentDispatcher {
708         
709         /**
710          * Scan for root element hook. This method is a hook for
711          * subclasses to add code that handles scanning for the root
712          * element. This method will also attempt to remove DTD validator
713          * from the pipeline, if there is no DTD grammar. If DTD validator
714          * is no longer in the pipeline bind namespaces in the scanner.
715          *
716          *
717          * @return True if the caller should stop and return true which
718          * allows the scanner to switch to a new scanning
719          * dispatcher. A return value of false indicates that
720          * the content dispatcher should continue as normal.
721          */

722         protected boolean scanRootElementHook()
723             throws IOException JavaDoc, XNIException {
724        
725             if (fExternalSubsetResolver != null && !fSeenDoctypeDecl
726                 && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) {
727                 scanStartElementName();
728                 resolveExternalSubsetAndRead();
729                 reconfigurePipeline();
730                 if (scanStartElementAfterName()) {
731                     setScannerState(SCANNER_STATE_TRAILING_MISC);
732                     setDispatcher(fTrailingMiscDispatcher);
733                     return true;
734                 }
735             }
736             else {
737                 reconfigurePipeline();
738                 if (scanStartElement()) {
739                     setScannerState(SCANNER_STATE_TRAILING_MISC);
740                     setDispatcher(fTrailingMiscDispatcher);
741                     return true;
742                 }
743             }
744             return false;
745
746         } // scanRootElementHook():boolean
747

748         /**
749          * Re-configures pipeline by removing the DTD validator
750          * if no DTD grammar exists. If no validator exists in the
751          * pipeline or there is no DTD grammar, namespace binding
752          * is performed by the scanner in the enclosing class.
753          */

754         private void reconfigurePipeline() {
755             if (fDTDValidator == null) {
756                 fBindNamespaces = true;
757             }
758             else if (!fDTDValidator.hasGrammar()) {
759                 fBindNamespaces = true;
760                 fPerformValidation = fDTDValidator.validate();
761                 // re-configure pipeline
762
XMLDocumentSource source = fDTDValidator.getDocumentSource();
763                 XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
764                 source.setDocumentHandler(handler);
765                 if (handler != null)
766                     handler.setDocumentSource(source);
767                 fDTDValidator.setDocumentSource(null);
768                 fDTDValidator.setDocumentHandler(null);
769             }
770         } // reconfigurePipeline()
771
}
772
773 } // class XMLNSDocumentScannerImpl
774
Popular Tags