KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > impl > XMLNSDocumentScannerImpl


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2002 The Apache Software Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 2002, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.impl;
59
60 import java.io.IOException JavaDoc;
61
62 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
63 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
64 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
65 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
66 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
67 import com.sun.org.apache.xerces.internal.xni.QName;
68 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
69 import com.sun.org.apache.xerces.internal.xni.XNIException;
70 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
71 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
72 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
73
74 /**
75  * The scanner acts as the source for the document
76  * information which is communicated to the document handler.
77  *
78  * This class scans an XML document, checks if document has a DTD, and if
79  * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
80  * namespace binding.
81  *
82  * Note: This scanner should only be used when the namespace processing is on!
83  *
84  * <p>
85  * This component requires the following features and properties from the
86  * component manager that uses it:
87  * <ul>
88  * <li>http://xml.org/sax/features/namespaces {true} -- if the value of this
89  * feature is set to false this scanner must not be used.</li>
90  * <li>http://xml.org/sax/features/validation</li>
91  * <li>http://apache.org/xml/features/nonvalidating/load-external-dtd</li>
92  * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
93  * <li>http://apache.org/xml/features/scanner/notify-builtin-refs</li>
94  * <li>http://apache.org/xml/properties/internal/symbol-table</li>
95  * <li>http://apache.org/xml/properties/internal/error-reporter</li>
96  * <li>http://apache.org/xml/properties/internal/entity-manager</li>
97  * <li>http://apache.org/xml/properties/internal/dtd-scanner</li>
98  * </ul>
99  *
100  * @author Elena Litani, IBM
101  *
102  * @version $Id: XMLNSDocumentScannerImpl.java,v 1.23 2004/04/30 15:36:38 mrglavas Exp $
103  */

104 public class XMLNSDocumentScannerImpl
105 extends XMLDocumentScannerImpl {
106
107     /** If is true, the dtd validator is no longer in the pipeline
108       * and the scanner should bind namespaces */

109     protected boolean fBindNamespaces;
110
111     /** If validating parser, make sure we report an error in the
112       * scanner if DTD grammar is missing.*/

113     protected boolean fPerformValidation;
114
115     // private data
116
//
117

118     /** DTD validator */
119     private XMLDTDValidatorFilter fDTDValidator;
120     
121     /**
122      * Saw spaces after element name or between attributes.
123      *
124      * This is reserved for the case where scanning of a start element spans
125      * several methods, as is the case when scanning the start of a root element
126      * where a DTD external subset may be read after scanning the element name.
127      */

128     private boolean fSawSpace;
129
130
131     /**
132      * The scanner is responsible for removing DTD validator
133      * from the pipeline if it is not needed.
134      *
135      * @param previous The filter component before DTDValidator
136      * @param dtdValidator
137      * The DTDValidator
138      * @param next The documentHandler after the DTDValidator
139      */

140     public void setDTDValidator(XMLDTDValidatorFilter dtd){
141         fDTDValidator = dtd;
142     }
143
144     /**
145      * Scans a start element. This method will handle the binding of
146      * namespace information and notifying the handler of the start
147      * of the element.
148      * <p>
149      * <pre>
150      * [44] EmptyElemTag ::= '&lt;' Name (S Attribute)* S? '/>'
151      * [40] STag ::= '&lt;' Name (S Attribute)* S? '>'
152      * </pre>
153      * <p>
154      * <strong>Note:</strong> This method assumes that the leading
155      * '&lt;' character has been consumed.
156      * <p>
157      * <strong>Note:</strong> This method uses the fElementQName and
158      * fAttributes variables. The contents of these variables will be
159      * destroyed. The caller should copy important information out of
160      * these variables before calling this method.
161      *
162      * @return True if element is empty. (i.e. It matches
163      * production [44].
164      */

165     protected boolean scanStartElement()
166     throws IOException JavaDoc, XNIException {
167         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElementNS()");
168
169         // Note: namespace processing is on by default
170
fEntityScanner.scanQName(fElementQName);
171         // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
172
String JavaDoc rawname = fElementQName.rawname;
173         if (fBindNamespaces) {
174             fNamespaceContext.pushContext();
175             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
176                 if (fPerformValidation) {
177                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
178                                                "MSG_GRAMMAR_NOT_FOUND",
179                                                new Object JavaDoc[]{ rawname},
180                                                XMLErrorReporter.SEVERITY_ERROR);
181
182                     if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
183                         fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
184                                                     "RootElementTypeMustMatchDoctypedecl",
185                                                     new Object JavaDoc[]{fDoctypeName, rawname},
186                                                     XMLErrorReporter.SEVERITY_ERROR);
187                     }
188                 }
189             }
190         }
191
192         // push element stack
193
fCurrentElement = fElementStack.pushElement(fElementQName);
194
195         // attributes
196
boolean empty = false;
197         fAttributes.removeAllAttributes();
198         do {
199             // spaces
200
boolean sawSpace = fEntityScanner.skipSpaces();
201
202             // end tag?
203
int c = fEntityScanner.peekChar();
204             if (c == '>') {
205                 fEntityScanner.scanChar();
206                 break;
207             }
208             else if (c == '/') {
209                 fEntityScanner.scanChar();
210                 if (!fEntityScanner.skipChar('>')) {
211                     reportFatalError("ElementUnterminated",
212                                      new Object JavaDoc[]{rawname});
213                 }
214                 empty = true;
215                 break;
216             }
217             else if (!isValidNameStartChar(c) || !sawSpace) {
218                 reportFatalError("ElementUnterminated", new Object JavaDoc[]{rawname});
219             }
220
221             // attributes
222
scanAttribute(fAttributes);
223             if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
224                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
225                                              "ElementAttributeLimit",
226                                              new Object JavaDoc[]{rawname, new Integer JavaDoc(fAttributes.getLength()) },
227                                              XMLErrorReporter.SEVERITY_FATAL_ERROR );
228             }
229
230         } while (true);
231
232         if (fBindNamespaces) {
233             // REVISIT: is it required? forbit xmlns prefix for element
234
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
235                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
236                                            "ElementXMLNSPrefix",
237                                            new Object JavaDoc[]{fElementQName.rawname},
238                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
239             }
240
241             // bind the element
242
String JavaDoc prefix = fElementQName.prefix != null
243                             ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
244             // assign uri to the element
245
fElementQName.uri = fNamespaceContext.getURI(prefix);
246             // make sure that object in the element stack is updated as well
247
fCurrentElement.uri = fElementQName.uri;
248
249             if (fElementQName.prefix == null && fElementQName.uri != null) {
250                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
251                 // making sure that the object in the element stack is updated too.
252
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
253             }
254             if (fElementQName.prefix != null && fElementQName.uri == null) {
255                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
256                                            "ElementPrefixUnbound",
257                                            new Object JavaDoc[]{fElementQName.prefix, fElementQName.rawname},
258                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
259             }
260
261             // bind attributes (xmlns are already bound bellow)
262
int length = fAttributes.getLength();
263             // fLength = 0; //initialize structure
264
for (int i = 0; i < length; i++) {
265                 fAttributes.getName(i, fAttributeQName);
266
267                 String JavaDoc aprefix = fAttributeQName.prefix != null
268                                  ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
269                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
270                 // REVISIT: try removing the first "if" and see if it is faster.
271
//
272
if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
273                     // checkDuplicates(fAttributeQName, fAttributes);
274
continue;
275                 }
276                 if (aprefix != XMLSymbols.EMPTY_STRING) {
277                     fAttributeQName.uri = uri;
278                     if (uri == null) {
279                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
280                                                    "AttributePrefixUnbound",
281                                                    new Object JavaDoc[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
282                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
283                     }
284                     fAttributes.setURI(i, uri);
285                     // checkDuplicates(fAttributeQName, fAttributes);
286
}
287             }
288             
289             if (length > 1) {
290                 QName name = fAttributes.checkDuplicatesNS();
291                 if (name != null) {
292                     if (name.uri != null) {
293                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
294                                                    "AttributeNSNotUnique",
295                                                    new Object JavaDoc[]{fElementQName.rawname, name.localpart, name.uri},
296                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
297                     }
298                     else {
299                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
300                                                    "AttributeNotUnique",
301                                                    new Object JavaDoc[]{fElementQName.rawname, name.rawname},
302                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
303                     }
304                 }
305             }
306         }
307
308
309         // call handler
310
if (fDocumentHandler != null) {
311             if (empty) {
312
313                 //decrease the markup depth..
314
fMarkupDepth--;
315
316                 // check that this element was opened in the same entity
317
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
318                     reportFatalError("ElementEntityMismatch",
319                                      new Object JavaDoc[]{fCurrentElement.rawname});
320                 }
321
322                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
323
324                 if (fBindNamespaces) {
325                     fNamespaceContext.popContext();
326                 }
327                 //pop the element off the stack..
328
fElementStack.popElement(fElementQName);
329             } else {
330                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
331             }
332         }
333
334         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty);
335         return empty;
336
337     } // scanStartElement():boolean
338

339     /**
340      * Scans the name of an element in a start or empty tag.
341      *
342      * @see #scanStartElement()
343      */

344     protected void scanStartElementName ()
345         throws IOException JavaDoc, XNIException {
346         // Note: namespace processing is on by default
347
fEntityScanner.scanQName(fElementQName);
348         // Must skip spaces here because the DTD scanner
349
// would consume them at the end of the external subset.
350
fSawSpace = fEntityScanner.skipSpaces();
351     } // scanStartElementName()
352

353     /**
354      * Scans the remainder of a start or empty tag after the element name.
355      *
356      * @see #scanStartElement
357      * @return True if element is empty.
358      */

359     protected boolean scanStartElementAfterName()
360         throws IOException JavaDoc, XNIException {
361         
362         // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
363
String JavaDoc rawname = fElementQName.rawname;
364         if (fBindNamespaces) {
365             fNamespaceContext.pushContext();
366             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
367                 if (fPerformValidation) {
368                     fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
369                                                "MSG_GRAMMAR_NOT_FOUND",
370                                                new Object JavaDoc[]{ rawname},
371                                                XMLErrorReporter.SEVERITY_ERROR);
372
373                     if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
374                         fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
375                                                     "RootElementTypeMustMatchDoctypedecl",
376                                                     new Object JavaDoc[]{fDoctypeName, rawname},
377                                                     XMLErrorReporter.SEVERITY_ERROR);
378                     }
379                 }
380             }
381         }
382
383         // push element stack
384
fCurrentElement = fElementStack.pushElement(fElementQName);
385
386         // attributes
387
boolean empty = false;
388         fAttributes.removeAllAttributes();
389         do {
390             
391             // end tag?
392
int c = fEntityScanner.peekChar();
393             if (c == '>') {
394                 fEntityScanner.scanChar();
395                 break;
396             }
397             else if (c == '/') {
398                 fEntityScanner.scanChar();
399                 if (!fEntityScanner.skipChar('>')) {
400                     reportFatalError("ElementUnterminated",
401                                      new Object JavaDoc[]{rawname});
402                 }
403                 empty = true;
404                 break;
405             }
406             else if (!isValidNameStartChar(c) || !fSawSpace) {
407                 reportFatalError("ElementUnterminated", new Object JavaDoc[]{rawname});
408             }
409
410             // attributes
411
scanAttribute(fAttributes);
412             
413             // spaces
414
fSawSpace = fEntityScanner.skipSpaces();
415
416         } while (true);
417
418         if (fBindNamespaces) {
419             // REVISIT: is it required? forbit xmlns prefix for element
420
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
421                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
422                                            "ElementXMLNSPrefix",
423                                            new Object JavaDoc[]{fElementQName.rawname},
424                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
425             }
426
427             // bind the element
428
String JavaDoc prefix = fElementQName.prefix != null
429                             ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
430             // assign uri to the element
431
fElementQName.uri = fNamespaceContext.getURI(prefix);
432             // make sure that object in the element stack is updated as well
433
fCurrentElement.uri = fElementQName.uri;
434
435             if (fElementQName.prefix == null && fElementQName.uri != null) {
436                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
437                 // making sure that the object in the element stack is updated too.
438
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
439             }
440             if (fElementQName.prefix != null && fElementQName.uri == null) {
441                 fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
442                                            "ElementPrefixUnbound",
443                                            new Object JavaDoc[]{fElementQName.prefix, fElementQName.rawname},
444                                            XMLErrorReporter.SEVERITY_FATAL_ERROR);
445             }
446
447             // bind attributes (xmlns are already bound bellow)
448
int length = fAttributes.getLength();
449             // fLength = 0; //initialize structure
450
for (int i = 0; i < length; i++) {
451                 fAttributes.getName(i, fAttributeQName);
452
453                 String JavaDoc aprefix = fAttributeQName.prefix != null
454                                  ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
455                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
456                 // REVISIT: try removing the first "if" and see if it is faster.
457
//
458
if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
459                     // checkDuplicates(fAttributeQName, fAttributes);
460
continue;
461                 }
462                 if (aprefix != XMLSymbols.EMPTY_STRING) {
463                     fAttributeQName.uri = uri;
464                     if (uri == null) {
465                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
466                                                    "AttributePrefixUnbound",
467                                                    new Object JavaDoc[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
468                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
469                     }
470                     fAttributes.setURI(i, uri);
471                     // checkDuplicates(fAttributeQName, fAttributes);
472
}
473             }
474             
475             if (length > 1) {
476                 QName name = fAttributes.checkDuplicatesNS();
477                 if (name != null) {
478                     if (name.uri != null) {
479                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
480                                                    "AttributeNSNotUnique",
481                                                    new Object JavaDoc[]{fElementQName.rawname, name.localpart, name.uri},
482                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
483                     }
484                     else {
485                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
486                                                    "AttributeNotUnique",
487                                                    new Object JavaDoc[]{fElementQName.rawname, name.rawname},
488                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
489                     }
490                 }
491             }
492         }
493
494
495         // call handler
496
if (fDocumentHandler != null) {
497             if (empty) {
498
499                 //decrease the markup depth..
500
fMarkupDepth--;
501
502                 // check that this element was opened in the same entity
503
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
504                     reportFatalError("ElementEntityMismatch",
505                                      new Object JavaDoc[]{fCurrentElement.rawname});
506                 }
507
508                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
509
510                 if (fBindNamespaces) {
511                     fNamespaceContext.popContext();
512                 }
513                 //pop the element off the stack..
514
fElementStack.popElement(fElementQName);
515             } else {
516                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
517             }
518         }
519
520         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty);
521         return empty;
522     } // scanStartElementAfterName()
523

524     /**
525      * Scans an attribute.
526      * <p>
527      * <pre>
528      * [41] Attribute ::= Name Eq AttValue
529      * </pre>
530      * <p>
531      * <strong>Note:</strong> This method assumes that the next
532      * character on the stream is the first character of the attribute
533      * name.
534      * <p>
535      * <strong>Note:</strong> This method uses the fAttributeQName and
536      * fQName variables. The contents of these variables will be
537      * destroyed.
538      *
539      * @param attributes The attributes list for the scanned attribute.
540      */

541     protected void scanAttribute(XMLAttributesImpl attributes)
542     throws IOException JavaDoc, XNIException {
543         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()");
544
545         // name
546
fEntityScanner.scanQName(fAttributeQName);
547
548         // equals
549
fEntityScanner.skipSpaces();
550         if (!fEntityScanner.skipChar('=')) {
551             reportFatalError("EqRequiredInAttribute",
552                              new Object JavaDoc[]{fCurrentElement.rawname,fAttributeQName.rawname});
553         }
554         fEntityScanner.skipSpaces();
555
556         // content
557
int attrIndex;
558        
559         if (fBindNamespaces) {
560             attrIndex = attributes.getLength();
561             attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
562         }
563         else {
564             int oldLen = attributes.getLength();
565             attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
566             
567             // WFC: Unique Att Spec
568
if (oldLen == attributes.getLength()) {
569                 reportFatalError("AttributeNotUnique",
570                                  new Object JavaDoc[]{fCurrentElement.rawname,
571                                  fAttributeQName.rawname});
572             }
573         }
574
575         //REVISIT: one more case needs to be included: external PE and standalone is no
576
boolean isVC = fHasExternalDTD && !fStandalone;
577
578         scanAttributeValue(this.fTempString, fTempString2,
579                            fAttributeQName.rawname, isVC,
580                            fCurrentElement.rawname);
581         String JavaDoc value = fTempString.toString();
582         attributes.setValue(attrIndex, value);
583         attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
584         attributes.setSpecified(attrIndex, true);
585
586         // record namespace declarations if any.
587
if (fBindNamespaces) {
588             
589             String JavaDoc localpart = fAttributeQName.localpart;
590             String JavaDoc prefix = fAttributeQName.prefix != null
591                             ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
592             // when it's of form xmlns="..." or xmlns:prefix="...",
593
// it's a namespace declaration. but prefix:xmlns="..." isn't.
594
if (prefix == XMLSymbols.PREFIX_XMLNS ||
595                 prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
596
597                 // get the internalized value of this attribute
598
String JavaDoc uri = fSymbolTable.addSymbol(value);
599
600                 // 1. "xmlns" can't be bound to any namespace
601
if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
602                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
603                                                "CantBindXMLNS",
604                                                new Object JavaDoc[]{fAttributeQName},
605                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
606                 }
607
608                 // 2. the namespace for "xmlns" can't be bound to any prefix
609
if (uri == NamespaceContext.XMLNS_URI) {
610                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
611                                                "CantBindXMLNS",
612                                                new Object JavaDoc[]{fAttributeQName},
613                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
614                 }
615
616                 // 3. "xml" can't be bound to any other namespace than it's own
617
if (localpart == XMLSymbols.PREFIX_XML) {
618                     if (uri != NamespaceContext.XML_URI) {
619                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
620                                                    "CantBindXML",
621                                                    new Object JavaDoc[]{fAttributeQName},
622                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
623                     }
624                 }
625                 // 4. the namespace for "xml" can't be bound to any other prefix
626
else {
627                     if (uri ==NamespaceContext.XML_URI) {
628                         fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
629                                                    "CantBindXML",
630                                                    new Object JavaDoc[]{fAttributeQName},
631                                                    XMLErrorReporter.SEVERITY_FATAL_ERROR);
632                     }
633                 }
634
635                 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
636
637                 // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
638
// We should only report an error if there is a prefix,
639
// that is, the local part is not "xmlns". -SG
640
if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
641                     fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
642                                                "EmptyPrefixedAttName",
643                                                new Object JavaDoc[]{fAttributeQName},
644                                                XMLErrorReporter.SEVERITY_FATAL_ERROR);
645                 }
646
647                 // declare prefix in context
648
fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
649                 // bind namespace attribute to a namespace
650
attributes.setURI(attrIndex, fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS));
651
652             }
653             else {
654                 // attempt to bind attribute
655
if (fAttributeQName.prefix != null) {
656                     attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
657                 }
658             }
659         }
660
661         if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()");
662     } // scanAttribute(XMLAttributes)
663

664
665
666     /**
667      * Scans an end element.
668      * <p>
669      * <pre>
670      * [42] ETag ::= '&lt;/' Name S? '>'
671      * </pre>
672      * <p>
673      * <strong>Note:</strong> This method uses the fElementQName variable.
674      * The contents of this variable will be destroyed. The caller should
675      * copy the needed information out of this variable before calling
676      * this method.
677      *
678      * @return The element depth.
679      */

680     protected int scanEndElement() throws IOException JavaDoc, XNIException {
681         if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()");
682
683         // pop context
684
fElementStack.popElement(fElementQName) ;
685
686         // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
687
//In scanners most of the time is consumed on checks done for XML characters, we can
688
// optimize on it and avoid the checks done for endElement,
689
//we will also avoid symbol table lookup - neeraj.bajaj@sun.com
690

691         // this should work both for namespace processing true or false...
692

693         //REVISIT: if the string is not the same as expected.. we need to do better error handling..
694
//We can skip this for now... In any case if the string doesn't match -- document is not well formed.
695
if (!fEntityScanner.skipString(fElementQName.rawname)) {
696             reportFatalError("ETagRequired", new Object JavaDoc[]{fElementQName.rawname});
697         }
698
699         // end
700
fEntityScanner.skipSpaces();
701         if (!fEntityScanner.skipChar('>')) {
702             reportFatalError("ETagUnterminated",
703                              new Object JavaDoc[]{fElementQName.rawname});
704         }
705         fMarkupDepth--;
706
707         //we have increased the depth for two markup "<" characters
708
fMarkupDepth--;
709
710         // check that this element was opened in the same entity
711
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
712             reportFatalError("ElementEntityMismatch",
713                              new Object JavaDoc[]{fCurrentElement.rawname});
714         }
715
716         // call handler
717
if (fDocumentHandler != null ) {
718
719             fDocumentHandler.endElement(fElementQName, null);
720             if (fBindNamespaces) {
721                 fNamespaceContext.popContext();
722             }
723
724         }
725
726         return fMarkupDepth;
727
728     } // scanEndElement():int
729

730
731     public void reset(XMLComponentManager componentManager)
732     throws XMLConfigurationException {
733
734         super.reset(componentManager);
735         fPerformValidation = false;
736         fBindNamespaces = false;
737     }
738
739     /** Creates a content dispatcher. */
740     protected Dispatcher createContentDispatcher() {
741         return new NSContentDispatcher();
742     } // createContentDispatcher():Dispatcher
743

744     /**
745      * Dispatcher to handle content scanning.
746      */

747     protected final class NSContentDispatcher
748         extends ContentDispatcher {
749         
750         /**
751          * Scan for root element hook. This method is a hook for
752          * subclasses to add code that handles scanning for the root
753          * element. This method will also attempt to remove DTD validator
754          * from the pipeline, if there is no DTD grammar. If DTD validator
755          * is no longer in the pipeline bind namespaces in the scanner.
756          *
757          *
758          * @return True if the caller should stop and return true which
759          * allows the scanner to switch to a new scanning
760          * dispatcher. A return value of false indicates that
761          * the content dispatcher should continue as normal.
762          */

763         protected boolean scanRootElementHook()
764             throws IOException JavaDoc, XNIException {
765        
766             if (fExternalSubsetResolver != null && !fSeenDoctypeDecl
767                 && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) {
768                 scanStartElementName();
769                 resolveExternalSubsetAndRead();
770                 reconfigurePipeline();
771                 if (scanStartElementAfterName()) {
772                     setScannerState(SCANNER_STATE_TRAILING_MISC);
773                     setDispatcher(fTrailingMiscDispatcher);
774                     return true;
775                 }
776             }
777             else {
778                 reconfigurePipeline();
779                 if (scanStartElement()) {
780                     setScannerState(SCANNER_STATE_TRAILING_MISC);
781                     setDispatcher(fTrailingMiscDispatcher);
782                     return true;
783                 }
784             }
785             return false;
786
787         } // scanRootElementHook():boolean
788

789         /**
790          * Re-configures pipeline by removing the DTD validator
791          * if no DTD grammar exists. If no validator exists in the
792          * pipeline or there is no DTD grammar, namespace binding
793          * is performed by the scanner in the enclosing class.
794          */

795         private void reconfigurePipeline() {
796             if (fDTDValidator == null) {
797                 fBindNamespaces = true;
798             }
799             else if (!fDTDValidator.hasGrammar()) {
800                 fBindNamespaces = true;
801                 fPerformValidation = fDTDValidator.validate();
802                 // re-configure pipeline
803
XMLDocumentSource source = fDTDValidator.getDocumentSource();
804                 XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
805                 source.setDocumentHandler(handler);
806                 if (handler != null)
807                     handler.setDocumentSource(source);
808                 fDTDValidator.setDocumentSource(null);
809                 fDTDValidator.setDocumentHandler(null);
810             }
811         } // reconfigurePipeline()
812
}
813
814 } // class XMLNSDocumentScannerImpl
815
Popular Tags