KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2003 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  * @author Michael Glavassevich, IBM
102  *
103  * @version $Id: XML11NSDocumentScannerImpl.java,v 1.11 2004/04/30 15:36:38 mrglavas Exp $
104  */

105 public class XML11NSDocumentScannerImpl extends XML11DocumentScannerImpl {
106
107     /**
108      * If is true, the dtd validator is no longer in the pipeline
109      * and the scanner should bind namespaces
110      */

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

117     protected boolean fPerformValidation;
118
119     // private data
120
//
121

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

132     private boolean fSawSpace;
133
134     /**
135      * The scanner is responsible for removing DTD validator
136      * from the pipeline if it is not needed.
137      *
138      * @param validator the DTD validator from the pipeline
139      */

140     public void setDTDValidator(XMLDTDValidatorFilter validator) {
141         fDTDValidator = validator;
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() throws IOException JavaDoc, XNIException {
166         if (DEBUG_CONTENT_SCANNING)
167             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 local 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(
178                         XMLMessageFormatter.XML_DOMAIN,
179                         "MSG_GRAMMAR_NOT_FOUND",
180                         new Object JavaDoc[] { rawname },
181                         XMLErrorReporter.SEVERITY_ERROR);
182
183                     if (fDoctypeName == null
184                         || !fDoctypeName.equals(rawname)) {
185                         fErrorReporter.reportError(
186                             XMLMessageFormatter.XML_DOMAIN,
187                             "RootElementTypeMustMatchDoctypedecl",
188                             new Object JavaDoc[] { fDoctypeName, rawname },
189                             XMLErrorReporter.SEVERITY_ERROR);
190                     }
191                 }
192             }
193         }
194
195         // push element stack
196
fCurrentElement = fElementStack.pushElement(fElementQName);
197
198         // attributes
199
boolean empty = false;
200         fAttributes.removeAllAttributes();
201         do {
202             // spaces
203
boolean sawSpace = fEntityScanner.skipSpaces();
204
205             // end tag?
206
int c = fEntityScanner.peekChar();
207             if (c == '>') {
208                 fEntityScanner.scanChar();
209                 break;
210             } else if (c == '/') {
211                 fEntityScanner.scanChar();
212                 if (!fEntityScanner.skipChar('>')) {
213                     reportFatalError(
214                         "ElementUnterminated",
215                         new Object JavaDoc[] { rawname });
216                 }
217                 empty = true;
218                 break;
219             } else if (!isValidNameStartChar(c) || !sawSpace) {
220                 // Second chance. Check if this character is a high
221
// surrogate of a valid name start character.
222
if (!isValidNameStartHighSurrogate(c) || !sawSpace) {
223                     reportFatalError(
224                         "ElementUnterminated",
225                         new Object JavaDoc[] { rawname });
226                 }
227             }
228
229             // attributes
230
scanAttribute(fAttributes);
231             if (fSecurityManager != null && fAttributes.getLength() > fElementAttributeLimit){
232                 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
233                                              "ElementAttributeLimit",
234                                              new Object JavaDoc[]{rawname, new Integer JavaDoc(fAttributes.getLength()) },
235                                              XMLErrorReporter.SEVERITY_FATAL_ERROR );
236             }
237
238         } while (true);
239
240         if (fBindNamespaces) {
241             // REVISIT: is it required? forbit xmlns prefix for element
242
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
243                 fErrorReporter.reportError(
244                     XMLMessageFormatter.XMLNS_DOMAIN,
245                     "ElementXMLNSPrefix",
246                     new Object JavaDoc[] { fElementQName.rawname },
247                     XMLErrorReporter.SEVERITY_FATAL_ERROR);
248             }
249
250             // bind the element
251
String JavaDoc prefix =
252                 fElementQName.prefix != null
253                     ? fElementQName.prefix
254                     : XMLSymbols.EMPTY_STRING;
255             // assign uri to the element
256
fElementQName.uri = fNamespaceContext.getURI(prefix);
257             // make sure that object in the element stack is updated as well
258
fCurrentElement.uri = fElementQName.uri;
259
260             if (fElementQName.prefix == null && fElementQName.uri != null) {
261                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
262                 // making sure that the object in the element stack is updated too.
263
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
264             }
265             if (fElementQName.prefix != null && fElementQName.uri == null) {
266                 fErrorReporter.reportError(
267                     XMLMessageFormatter.XMLNS_DOMAIN,
268                     "ElementPrefixUnbound",
269                     new Object JavaDoc[] {
270                         fElementQName.prefix,
271                         fElementQName.rawname },
272                     XMLErrorReporter.SEVERITY_FATAL_ERROR);
273             }
274
275             // bind attributes (xmlns are already bound bellow)
276
int length = fAttributes.getLength();
277             for (int i = 0; i < length; i++) {
278                 fAttributes.getName(i, fAttributeQName);
279
280                 String JavaDoc aprefix =
281                     fAttributeQName.prefix != null
282                         ? fAttributeQName.prefix
283                         : XMLSymbols.EMPTY_STRING;
284                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
285                 // REVISIT: try removing the first "if" and see if it is faster.
286
//
287
if (fAttributeQName.uri != null
288                     && fAttributeQName.uri == uri) {
289                     continue;
290                 }
291                 if (aprefix != XMLSymbols.EMPTY_STRING) {
292                     fAttributeQName.uri = uri;
293                     if (uri == null) {
294                         fErrorReporter.reportError(
295                             XMLMessageFormatter.XMLNS_DOMAIN,
296                             "AttributePrefixUnbound",
297                             new Object JavaDoc[] {
298                                 fElementQName.rawname,
299                                 fAttributeQName.rawname,
300                                 aprefix },
301                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
302                     }
303                     fAttributes.setURI(i, uri);
304                 }
305             }
306
307             if (length > 1) {
308                 QName name = fAttributes.checkDuplicatesNS();
309                 if (name != null) {
310                     if (name.uri != null) {
311                         fErrorReporter.reportError(
312                             XMLMessageFormatter.XMLNS_DOMAIN,
313                             "AttributeNSNotUnique",
314                             new Object JavaDoc[] {
315                                 fElementQName.rawname,
316                                 name.localpart,
317                                 name.uri },
318                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
319                     } else {
320                         fErrorReporter.reportError(
321                             XMLMessageFormatter.XMLNS_DOMAIN,
322                             "AttributeNotUnique",
323                             new Object JavaDoc[] {
324                                 fElementQName.rawname,
325                                 name.rawname },
326                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
327                     }
328                 }
329             }
330         }
331
332         // call handler
333
if (fDocumentHandler != null) {
334             if (empty) {
335
336                 //decrease the markup depth..
337
fMarkupDepth--;
338
339                 // check that this element was opened in the same entity
340
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
341                     reportFatalError(
342                         "ElementEntityMismatch",
343                         new Object JavaDoc[] { fCurrentElement.rawname });
344                 }
345
346                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
347
348                 if (fBindNamespaces) {
349                     fNamespaceContext.popContext();
350                 }
351                 //pop the element off the stack..
352
fElementStack.popElement(fElementQName);
353             } else {
354                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
355             }
356         }
357
358         if (DEBUG_CONTENT_SCANNING)
359             System.out.println("<<< scanStartElement(): " + empty);
360         return empty;
361
362     } // scanStartElement():boolean
363

364     /**
365      * Scans the name of an element in a start or empty tag.
366      *
367      * @see #scanStartElement()
368      */

369     protected void scanStartElementName ()
370         throws IOException JavaDoc, XNIException {
371         // Note: namespace processing is on by default
372
fEntityScanner.scanQName(fElementQName);
373         // Must skip spaces here because the DTD scanner
374
// would consume them at the end of the external subset.
375
fSawSpace = fEntityScanner.skipSpaces();
376     } // scanStartElementName()
377

378     /**
379      * Scans the remainder of a start or empty tag after the element name.
380      *
381      * @see #scanStartElement
382      * @return True if element is empty.
383      */

384     protected boolean scanStartElementAfterName()
385         throws IOException JavaDoc, XNIException {
386
387         // REVISIT - [Q] Why do we need this local variable? -- mrglavas
388
String JavaDoc rawname = fElementQName.rawname;
389         if (fBindNamespaces) {
390             fNamespaceContext.pushContext();
391             if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
392                 if (fPerformValidation) {
393                     fErrorReporter.reportError(
394                         XMLMessageFormatter.XML_DOMAIN,
395                         "MSG_GRAMMAR_NOT_FOUND",
396                         new Object JavaDoc[] { rawname },
397                         XMLErrorReporter.SEVERITY_ERROR);
398
399                     if (fDoctypeName == null
400                         || !fDoctypeName.equals(rawname)) {
401                         fErrorReporter.reportError(
402                             XMLMessageFormatter.XML_DOMAIN,
403                             "RootElementTypeMustMatchDoctypedecl",
404                             new Object JavaDoc[] { fDoctypeName, rawname },
405                             XMLErrorReporter.SEVERITY_ERROR);
406                     }
407                 }
408             }
409         }
410
411         // push element stack
412
fCurrentElement = fElementStack.pushElement(fElementQName);
413
414         // attributes
415
boolean empty = false;
416         fAttributes.removeAllAttributes();
417         do {
418             
419             // end tag?
420
int c = fEntityScanner.peekChar();
421             if (c == '>') {
422                 fEntityScanner.scanChar();
423                 break;
424             } else if (c == '/') {
425                 fEntityScanner.scanChar();
426                 if (!fEntityScanner.skipChar('>')) {
427                     reportFatalError(
428                         "ElementUnterminated",
429                         new Object JavaDoc[] { rawname });
430                 }
431                 empty = true;
432                 break;
433             } else if (!isValidNameStartChar(c) || !fSawSpace) {
434                 // Second chance. Check if this character is a high
435
// surrogate of a valid name start character.
436
if (!isValidNameStartHighSurrogate(c) || !fSawSpace) {
437                     reportFatalError(
438                         "ElementUnterminated",
439                         new Object JavaDoc[] { rawname });
440                 }
441             }
442
443             // attributes
444
scanAttribute(fAttributes);
445             
446             // spaces
447
fSawSpace = fEntityScanner.skipSpaces();
448
449         } while (true);
450
451         if (fBindNamespaces) {
452             // REVISIT: is it required? forbit xmlns prefix for element
453
if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
454                 fErrorReporter.reportError(
455                     XMLMessageFormatter.XMLNS_DOMAIN,
456                     "ElementXMLNSPrefix",
457                     new Object JavaDoc[] { fElementQName.rawname },
458                     XMLErrorReporter.SEVERITY_FATAL_ERROR);
459             }
460
461             // bind the element
462
String JavaDoc prefix =
463                 fElementQName.prefix != null
464                     ? fElementQName.prefix
465                     : XMLSymbols.EMPTY_STRING;
466             // assign uri to the element
467
fElementQName.uri = fNamespaceContext.getURI(prefix);
468             // make sure that object in the element stack is updated as well
469
fCurrentElement.uri = fElementQName.uri;
470
471             if (fElementQName.prefix == null && fElementQName.uri != null) {
472                 fElementQName.prefix = XMLSymbols.EMPTY_STRING;
473                 // making sure that the object in the element stack is updated too.
474
fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
475             }
476             if (fElementQName.prefix != null && fElementQName.uri == null) {
477                 fErrorReporter.reportError(
478                     XMLMessageFormatter.XMLNS_DOMAIN,
479                     "ElementPrefixUnbound",
480                     new Object JavaDoc[] {
481                         fElementQName.prefix,
482                         fElementQName.rawname },
483                     XMLErrorReporter.SEVERITY_FATAL_ERROR);
484             }
485
486             // bind attributes (xmlns are already bound bellow)
487
int length = fAttributes.getLength();
488             for (int i = 0; i < length; i++) {
489                 fAttributes.getName(i, fAttributeQName);
490
491                 String JavaDoc aprefix =
492                     fAttributeQName.prefix != null
493                         ? fAttributeQName.prefix
494                         : XMLSymbols.EMPTY_STRING;
495                 String JavaDoc uri = fNamespaceContext.getURI(aprefix);
496                 // REVISIT: try removing the first "if" and see if it is faster.
497
//
498
if (fAttributeQName.uri != null
499                     && fAttributeQName.uri == uri) {
500                     continue;
501                 }
502                 if (aprefix != XMLSymbols.EMPTY_STRING) {
503                     fAttributeQName.uri = uri;
504                     if (uri == null) {
505                         fErrorReporter.reportError(
506                             XMLMessageFormatter.XMLNS_DOMAIN,
507                             "AttributePrefixUnbound",
508                             new Object JavaDoc[] {
509                                 fElementQName.rawname,
510                                 fAttributeQName.rawname,
511                                 aprefix },
512                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
513                     }
514                     fAttributes.setURI(i, uri);
515                 }
516             }
517
518             if (length > 1) {
519                 QName name = fAttributes.checkDuplicatesNS();
520                 if (name != null) {
521                     if (name.uri != null) {
522                         fErrorReporter.reportError(
523                             XMLMessageFormatter.XMLNS_DOMAIN,
524                             "AttributeNSNotUnique",
525                             new Object JavaDoc[] {
526                                 fElementQName.rawname,
527                                 name.localpart,
528                                 name.uri },
529                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
530                     } else {
531                         fErrorReporter.reportError(
532                             XMLMessageFormatter.XMLNS_DOMAIN,
533                             "AttributeNotUnique",
534                             new Object JavaDoc[] {
535                                 fElementQName.rawname,
536                                 name.rawname },
537                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
538                     }
539                 }
540             }
541         }
542
543         // call handler
544
if (fDocumentHandler != null) {
545             if (empty) {
546
547                 //decrease the markup depth..
548
fMarkupDepth--;
549
550                 // check that this element was opened in the same entity
551
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
552                     reportFatalError(
553                         "ElementEntityMismatch",
554                         new Object JavaDoc[] { fCurrentElement.rawname });
555                 }
556
557                 fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
558
559                 if (fBindNamespaces) {
560                     fNamespaceContext.popContext();
561                 }
562                 //pop the element off the stack..
563
fElementStack.popElement(fElementQName);
564             } else {
565                 fDocumentHandler.startElement(fElementQName, fAttributes, null);
566             }
567         }
568
569         if (DEBUG_CONTENT_SCANNING)
570             System.out.println("<<< scanStartElementAfterName(): " + empty);
571         return empty;
572         
573     } // scanStartElementAfterName()
574

575     /**
576      * Scans an attribute.
577      * <p>
578      * <pre>
579      * [41] Attribute ::= Name Eq AttValue
580      * </pre>
581      * <p>
582      * <strong>Note:</strong> This method assumes that the next
583      * character on the stream is the first character of the attribute
584      * name.
585      * <p>
586      * <strong>Note:</strong> This method uses the fAttributeQName and
587      * fQName variables. The contents of these variables will be
588      * destroyed.
589      *
590      * @param attributes The attributes list for the scanned attribute.
591      */

592     protected void scanAttribute(XMLAttributesImpl attributes)
593         throws IOException JavaDoc, XNIException {
594         if (DEBUG_CONTENT_SCANNING)
595             System.out.println(">>> scanAttribute()");
596
597         // name
598
fEntityScanner.scanQName(fAttributeQName);
599
600         // equals
601
fEntityScanner.skipSpaces();
602         if (!fEntityScanner.skipChar('=')) {
603             reportFatalError(
604                 "EqRequiredInAttribute",
605                 new Object JavaDoc[] {
606                     fCurrentElement.rawname,
607                     fAttributeQName.rawname });
608         }
609         fEntityScanner.skipSpaces();
610
611         // content
612
int attrIndex;
613
614         if (fBindNamespaces) {
615             attrIndex = attributes.getLength();
616             attributes.addAttributeNS(
617                 fAttributeQName,
618                 XMLSymbols.fCDATASymbol,
619                 null);
620         } else {
621             int oldLen = attributes.getLength();
622             attrIndex =
623                 attributes.addAttribute(
624                     fAttributeQName,
625                     XMLSymbols.fCDATASymbol,
626                     null);
627
628             // WFC: Unique Att Spec
629
if (oldLen == attributes.getLength()) {
630                 reportFatalError(
631                     "AttributeNotUnique",
632                     new Object JavaDoc[] {
633                         fCurrentElement.rawname,
634                         fAttributeQName.rawname });
635             }
636         }
637
638         //REVISIT: one more case needs to be included: external PE and standalone is no
639
boolean isVC = fHasExternalDTD && !fStandalone;
640
641         // REVISIT: it seems that this function should not take attributes, and length
642
scanAttributeValue(
643             this.fTempString,
644             fTempString2,
645             fAttributeQName.rawname,
646             isVC,
647             fCurrentElement.rawname);
648         String JavaDoc value = fTempString.toString();
649         attributes.setValue(attrIndex, value);
650         attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
651         attributes.setSpecified(attrIndex, true);
652
653         // record namespace declarations if any.
654
if (fBindNamespaces) {
655
656             String JavaDoc localpart = fAttributeQName.localpart;
657             String JavaDoc prefix =
658                 fAttributeQName.prefix != null
659                     ? fAttributeQName.prefix
660                     : XMLSymbols.EMPTY_STRING;
661             // when it's of form xmlns="..." or xmlns:prefix="...",
662
// it's a namespace declaration. but prefix:xmlns="..." isn't.
663
if (prefix == XMLSymbols.PREFIX_XMLNS
664                 || prefix == XMLSymbols.EMPTY_STRING
665                 && localpart == XMLSymbols.PREFIX_XMLNS) {
666
667                 // get the internalized value of this attribute
668
String JavaDoc uri = fSymbolTable.addSymbol(value);
669
670                 // 1. "xmlns" can't be bound to any namespace
671
if (prefix == XMLSymbols.PREFIX_XMLNS
672                     && localpart == XMLSymbols.PREFIX_XMLNS) {
673                     fErrorReporter.reportError(
674                         XMLMessageFormatter.XMLNS_DOMAIN,
675                         "CantBindXMLNS",
676                         new Object JavaDoc[] { fAttributeQName },
677                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
678                 }
679
680                 // 2. the namespace for "xmlns" can't be bound to any prefix
681
if (uri == NamespaceContext.XMLNS_URI) {
682                     fErrorReporter.reportError(
683                         XMLMessageFormatter.XMLNS_DOMAIN,
684                         "CantBindXMLNS",
685                         new Object JavaDoc[] { fAttributeQName },
686                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
687                 }
688
689                 // 3. "xml" can't be bound to any other namespace than it's own
690
if (localpart == XMLSymbols.PREFIX_XML) {
691                     if (uri != NamespaceContext.XML_URI) {
692                         fErrorReporter.reportError(
693                             XMLMessageFormatter.XMLNS_DOMAIN,
694                             "CantBindXML",
695                             new Object JavaDoc[] { fAttributeQName },
696                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
697                     }
698                 }
699                 // 4. the namespace for "xml" can't be bound to any other prefix
700
else {
701                     if (uri == NamespaceContext.XML_URI) {
702                         fErrorReporter.reportError(
703                             XMLMessageFormatter.XMLNS_DOMAIN,
704                             "CantBindXML",
705                             new Object JavaDoc[] { fAttributeQName },
706                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
707                     }
708                 }
709
710                 prefix =
711                     localpart != XMLSymbols.PREFIX_XMLNS
712                         ? localpart
713                         : XMLSymbols.EMPTY_STRING;
714
715                 // Declare prefix in context. Removing the association between a prefix and a
716
// namespace name is permitted in XML 1.1, so if the uri value is the empty string,
717
// the prefix is being unbound. -- mrglavas
718
fNamespaceContext.declarePrefix(
719                     prefix,
720                     uri.length() != 0 ? uri : null);
721                 // bind namespace attribute to a namespace
722
attributes.setURI(
723                     attrIndex,
724                     fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS));
725
726             } else {
727                 // attempt to bind attribute
728
if (fAttributeQName.prefix != null) {
729                     attributes.setURI(
730                         attrIndex,
731                         fNamespaceContext.getURI(fAttributeQName.prefix));
732                 }
733             }
734         }
735
736         if (DEBUG_CONTENT_SCANNING)
737             System.out.println("<<< scanAttribute()");
738     } // scanAttribute(XMLAttributes)
739

740     /**
741      * Scans an end element.
742      * <p>
743      * <pre>
744      * [42] ETag ::= '&lt;/' Name S? '>'
745      * </pre>
746      * <p>
747      * <strong>Note:</strong> This method uses the fElementQName variable.
748      * The contents of this variable will be destroyed. The caller should
749      * copy the needed information out of this variable before calling
750      * this method.
751      *
752      * @return The element depth.
753      */

754     protected int scanEndElement() throws IOException JavaDoc, XNIException {
755         if (DEBUG_CONTENT_SCANNING)
756             System.out.println(">>> scanEndElement()");
757
758         // pop context
759
fElementStack.popElement(fElementQName);
760
761         // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
762
//In scanners most of the time is consumed on checks done for XML characters, we can
763
// optimize on it and avoid the checks done for endElement,
764
//we will also avoid symbol table lookup - neeraj.bajaj@sun.com
765

766         // this should work both for namespace processing true or false...
767

768         //REVISIT: if the string is not the same as expected.. we need to do better error handling..
769
//We can skip this for now... In any case if the string doesn't match -- document is not well formed.
770
if (!fEntityScanner.skipString(fElementQName.rawname)) {
771             reportFatalError(
772                 "ETagRequired",
773                 new Object JavaDoc[] { fElementQName.rawname });
774         }
775
776         // end
777
fEntityScanner.skipSpaces();
778         if (!fEntityScanner.skipChar('>')) {
779             reportFatalError(
780                 "ETagUnterminated",
781                 new Object JavaDoc[] { fElementQName.rawname });
782         }
783         fMarkupDepth--;
784
785         //we have increased the depth for two markup "<" characters
786
fMarkupDepth--;
787
788         // check that this element was opened in the same entity
789
if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
790             reportFatalError(
791                 "ElementEntityMismatch",
792                 new Object JavaDoc[] { fCurrentElement.rawname });
793         }
794
795         // call handler
796
if (fDocumentHandler != null) {
797
798             fDocumentHandler.endElement(fElementQName, null);
799             if (fBindNamespaces) {
800                 fNamespaceContext.popContext();
801             }
802
803         }
804
805         return fMarkupDepth;
806
807     } // scanEndElement():int
808

809     public void reset(XMLComponentManager componentManager)
810         throws XMLConfigurationException {
811
812         super.reset(componentManager);
813         fPerformValidation = false;
814         fBindNamespaces = false;
815     }
816
817     /** Creates a content dispatcher. */
818     protected Dispatcher createContentDispatcher() {
819         return new NS11ContentDispatcher();
820     } // createContentDispatcher():Dispatcher
821

822     /**
823      * Dispatcher to handle content scanning.
824      */

825     protected final class NS11ContentDispatcher extends ContentDispatcher {
826         /**
827          * Scan for root element hook. This method is a hook for
828          * subclasses to add code that handles scanning for the root
829          * element. This method will also attempt to remove DTD validator
830          * from the pipeline, if there is no DTD grammar. If DTD validator
831          * is no longer in the pipeline bind namespaces in the scanner.
832          *
833          *
834          * @return True if the caller should stop and return true which
835          * allows the scanner to switch to a new scanning
836          * dispatcher. A return value of false indicates that
837          * the content dispatcher should continue as normal.
838          */

839         protected boolean scanRootElementHook()
840             throws IOException JavaDoc, XNIException {
841             
842             if (fExternalSubsetResolver != null && !fSeenDoctypeDecl
843                 && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) {
844                 scanStartElementName();
845                 resolveExternalSubsetAndRead();
846                 reconfigurePipeline();
847                 if (scanStartElementAfterName()) {
848                     setScannerState(SCANNER_STATE_TRAILING_MISC);
849                     setDispatcher(fTrailingMiscDispatcher);
850                     return true;
851                 }
852             }
853             else {
854                 reconfigurePipeline();
855                 if (scanStartElement()) {
856                     setScannerState(SCANNER_STATE_TRAILING_MISC);
857                     setDispatcher(fTrailingMiscDispatcher);
858                     return true;
859                 }
860             }
861             return false;
862
863         } // scanRootElementHook():boolean
864

865         /**
866          * Re-configures pipeline by removing the DTD validator
867          * if no DTD grammar exists. If no validator exists in the
868          * pipeline or there is no DTD grammar, namespace binding
869          * is performed by the scanner in the enclosing class.
870          */

871         private void reconfigurePipeline() {
872             if (fDTDValidator == null) {
873                 fBindNamespaces = true;
874             }
875             else if (!fDTDValidator.hasGrammar()) {
876                 fBindNamespaces = true;
877                 fPerformValidation = fDTDValidator.validate();
878                 // re-configure pipeline
879
XMLDocumentSource source = fDTDValidator.getDocumentSource();
880                 XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
881                 source.setDocumentHandler(handler);
882                 if (handler != null)
883                     handler.setDocumentSource(source);
884                 fDTDValidator.setDocumentSource(null);
885                 fDTDValidator.setDocumentHandler(null);
886             }
887         } // reconfigurePipeline()
888
}
889 }
890
Popular Tags