KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > xml2 > DtdParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.xml2;
31
32 import com.caucho.util.*;
33 import com.caucho.vfs.Path;
34 import com.caucho.vfs.ReadStream;
35 import com.caucho.vfs.ReaderWriterStream;
36 import com.caucho.vfs.Vfs;
37 import com.caucho.vfs.WriteStream;
38 import com.caucho.xml2.readers.MacroReader;
39 import com.caucho.xml2.readers.Utf16Reader;
40 import com.caucho.xml2.readers.Utf8Reader;
41 import com.caucho.xml2.readers.XmlReader;
42
43 import org.w3c.dom.Document JavaDoc;
44 import org.w3c.dom.Node JavaDoc;
45 import org.xml.sax.InputSource JavaDoc;
46 import org.xml.sax.Locator JavaDoc;
47 import org.xml.sax.SAXException JavaDoc;
48 import org.xml.sax.SAXParseException JavaDoc;
49
50 import javax.xml.namespace.QName JavaDoc;
51 import java.io.FileNotFoundException JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.InputStream JavaDoc;
54 import java.util.*;
55 import java.util.logging.Level JavaDoc;
56
57 /**
58  * A configurable XML parser. Loose versions of XML and HTML are supported
59  * by changing the Policy object.
60  *
61  * <p>Normally, applications will use Xml, LooseXml, Html, or LooseHtml.
62  */

63 public class DtdParser
64 {
65   private static final L10N L = new L10N(DtdParser.class);
66   
67   static HashMap<String JavaDoc,String JavaDoc> _attrTypes = new HashMap<String JavaDoc,String JavaDoc>();
68   static Entities _entities = new XmlEntities();
69   
70   private XmlParser _xmlParser;
71
72   
73   QAttributes _attributes;
74   QAttributes _nullAttributes;
75
76   boolean _inDtd;
77   boolean _strictComments = true;
78   
79   CharBuffer _text;
80   CharBuffer _eltName;
81   CharBuffer _cb;
82   CharBuffer _buf = new CharBuffer();
83   String JavaDoc _textFilename;
84   int _textLine;
85
86   char []_textBuffer = new char[1024];
87   int _textLength;
88   int _textCapacity = _textBuffer.length;
89   boolean _isIgnorableWhitespace;
90   boolean _isJspText;
91   
92   CharBuffer _name = new CharBuffer();
93   CharBuffer _nameBuffer = new CharBuffer();
94   
95   MacroReader _macro = new MacroReader();
96   int _macroIndex = 0;
97   int _macroLength = 0;
98   char []_macroBuffer;
99
100   QName JavaDoc []_elementNames = new QName JavaDoc[64];
101   NamespaceMap []_namespaces = new NamespaceMap[64];
102   int []_elementLines = new int[64];
103   int _elementTop;
104
105   NamespaceMap _namespaceMap;
106
107   ArrayList<String JavaDoc> _attrNames = new ArrayList<String JavaDoc>();
108   ArrayList<String JavaDoc> _attrValues = new ArrayList<String JavaDoc>();
109
110   ReadStream _is;
111   XmlReader _reader;
112   
113   String JavaDoc _extPublicId;
114   String JavaDoc _extSystemId;
115   
116   QName JavaDoc _activeNode;
117   QName JavaDoc _topNamespaceNode;
118   boolean _isTagStart;
119   boolean _stopOnIncludeEnd;
120   boolean _hasTopElement;
121   boolean _hasDoctype;
122   QDocumentType _dtd;
123
124   public DtdParser(XmlParser xmlParser, QDocumentType dtd)
125   {
126     _xmlParser = xmlParser;
127     _dtd = dtd;
128   }
129   
130
131   /**
132    * Parses the DTD.
133    *
134    * <pre>
135    * dtd-item ::= &lt!ELEMENT ... |
136    * &lt!ATTLIST ... |
137    * &lt!NOTATION ... |
138    * &lt!ENTITY ... |
139    * &lt!-- comment |
140    * &lt? pi |
141    * %pe-ref;
142    * </pre>
143    *
144    * @return the next character.
145    */

146   int parseDoctypeDecl(QDocumentType doctype)
147     throws IOException JavaDoc, SAXException JavaDoc
148   {
149     _hasDoctype = true;
150     int ch = 0;
151
152     for (ch = _xmlParser.skipWhitespace(read());
153      ch >= 0 && ch != ']';
154      ch = _xmlParser.skipWhitespace(read())) {
155       if (ch == '<') {
156     if ((ch = read()) == '!') {
157       if (XmlChar.isNameStart(ch = read())) {
158         ch = _xmlParser.parseName(_text, ch);
159         String JavaDoc name = _text.toString();
160
161         if (name.equals("ELEMENT"))
162           parseElementDecl(doctype);
163         else if (name.equals("ATTLIST"))
164           parseAttlistDecl(doctype);
165         else if (name.equals("NOTATION"))
166           parseNotationDecl(doctype);
167         else if (name.equals("ENTITY"))
168           parseEntityDecl(doctype);
169         else
170           throw error("unknown declaration '" + name + "'");
171       }
172       else if (ch == '-')
173         parseComment();
174       else if (ch == '[') {
175         ch = _xmlParser.parseName(_text, read());
176         String JavaDoc name = _text.toString();
177
178         if (name.equals("IGNORE")) {
179           parseIgnore();
180         }
181         else if (name.equals("INCLUDE")) {
182           parseIgnore();
183         }
184         else
185           throw error(L.l("unknown declaration '{0}'", name));
186       }
187     }
188     else if (ch == '?') {
189       parsePI();
190     }
191     else
192       throw error(L.l("expected markup at {0}", badChar(ch)));
193       }
194       else if (ch == '%') {
195     ch = _xmlParser.parseName(_buf, read());
196
197     if (ch != ';')
198       throw error(L.l("'%{0};' expects ';' at {1}. Parameter entities have a '%name;' syntax.", _buf, badChar(ch)));
199
200     addPEReference(_text, _buf.toString());
201       }
202       else {
203     throw error(L.l("expected '<' at {0}", badChar(ch)));
204       }
205
206       _text.clear();
207     }
208     _text.clear();
209
210     return read();
211   }
212
213   private int parseNameToken(CharBuffer name, int ch)
214     throws IOException JavaDoc, SAXException JavaDoc
215   {
216     name.clear();
217
218     if (! XmlChar.isNameChar(ch))
219       throw error(L.l("expected name at {0}", badChar(ch)));
220
221     for (; XmlChar.isNameChar(ch); ch = read())
222       name.append((char) ch);
223
224     return ch;
225   }
226
227   private void appendText(String JavaDoc s)
228   {
229     if (_text.length() == 0) {
230       _textFilename = getFilename();
231       _textLine = getLine();
232     }
233
234     _text.append(s);
235   }
236
237   private int parseCharacterReference()
238     throws IOException JavaDoc, SAXException JavaDoc
239   {
240     int ch = read();
241
242     int radix = 10;
243     if (ch == 'x') {
244       radix = 16;
245       ch = read();
246     }
247
248     int value = 0;
249     for (; ch != ';'; ch = read()) {
250       if (ch >= '0' && ch <= '9')
251     value = radix * value + ch - '0';
252       else if (radix == 16 && ch >= 'a' && ch <= 'f')
253     value = radix * value + ch - 'a' + 10;
254       else if (radix == 16 && ch >= 'A' && ch <= 'F')
255     value = radix * value + ch - 'A' + 10;
256       else
257     throw error(L.l("malformed entity ref at {0}", badChar(ch)));
258     }
259
260     if (value > 0xffff)
261       throw error(L.l("malformed entity ref at {0}", "" + value));
262
263     // xml/0072
264
if (! isChar(value))
265       throw error(L.l("illegal character ref at {0}", badChar(value)));
266
267     return value;
268   }
269
270   /**
271    * Parses an attribute value.
272    *
273    * <pre>
274    * value ::= '[^']*'
275    * ::= "[^"]*"
276    * ::= [^ />]*
277    * </pre>
278    *
279    * @param value the CharBuffer which will contain the value.
280    * @param ch the next character from the input stream.
281    * @param isGeneral true if general entities are allowed.
282    *
283    * @return the following character from the input stream
284    */

285   private int parseValue(CharBuffer value, int ch, boolean isGeneral)
286     throws IOException JavaDoc, SAXException JavaDoc
287   {
288     int end = ch;
289
290     value.clear();
291
292     if (end == '\'' || end == '"')
293       ch = read();
294     else {
295       value.append((char) end);
296       for (ch = read();
297            ch >= 0 && XmlChar.isNameChar(ch);
298            ch = read())
299         value.append((char) ch);
300       
301       throw error(L.l("XML attribute value must be quoted at '{0}'. XML attribute syntax is either attr=\"value\" or attr='value'.",
302                       value));
303     }
304
305     while (ch != -1 && (end != 0 && ch != end
306             || end == 0 && isAttributeChar(ch))) {
307       if (end == 0 && ch == '/') {
308     ch = read();
309     if (! isWhitespace(ch) && ch != '>') {
310       value.append('/');
311       value.append((char) ch);
312     }
313     else {
314           unread(ch);
315       return '/';
316     }
317       }
318       else if (ch == '&') {
319     if ((ch = read()) == '#')
320       value.append((char) parseCharacterReference());
321     else if (! isGeneral) {
322       value.append('&');
323       value.append((char) ch);
324     }
325         else if (XmlChar.isNameStart(ch)) {
326       ch = _xmlParser.parseName(_buf, ch);
327       String JavaDoc name = _buf.toString();
328
329       if (ch != ';')
330         throw error(L.l("expected '{0}' at {1}", ";", badChar(ch)));
331       else {
332         int lookup = _entities.getEntity(name);
333
334         if (lookup >= 0 && lookup <= 0xffff) {
335           ch = read();
336           value.append((char) lookup);
337           continue;
338         }
339             
340         QEntity entity = _dtd == null ? null : _dtd.getEntity(name);
341         if (entity != null && entity._value != null)
342           _xmlParser.setMacroAttr(entity._value);
343         else
344           throw error(L.l("expected local reference at '&{0};'", name));
345       }
346     }
347       }
348       else if (ch == '%' && ! isGeneral) {
349         ch = read();
350
351         if (! XmlChar.isNameStart(ch)) {
352           value.append('%');
353           continue;
354         }
355         else {
356           ch = _xmlParser.parseName(_buf, ch);
357
358           if (ch != ';')
359             throw error(L.l("expected '{0}' at {1}", ";", badChar(ch)));
360           else
361             addPEReference(value, _buf.toString());
362         }
363       }
364       else if (isGeneral) {
365         if (ch == '\r') {
366           ch = read();
367           if (ch != '\n') {
368             value.append('\n');
369             continue;
370           }
371         }
372         value.append((char) ch);
373       }
374       else if (ch == '\r') {
375     value.append(' ');
376         
377         if ((ch = read()) != '\n')
378           continue;
379       }
380       else if (ch == '\n')
381     value.append(' ');
382       else
383     value.append((char) ch);
384
385       ch = read();
386     }
387
388     if (end != 0)
389       ch = read();
390
391     return ch;
392   }
393
394   private boolean isAttributeChar(int ch)
395   {
396     switch (ch) {
397     case ' ': case '\t': case '\n': case '\r':
398       return false;
399     case '<': case '>': case '\'':case '"': case '=':
400       return false;
401     default:
402       return true;
403     }
404   }
405
406   private int parsePI()
407     throws IOException JavaDoc, SAXException JavaDoc
408   {
409     int ch;
410
411     ch = read();
412     if (! XmlChar.isNameStart(ch))
413       throw error(L.l("expected name after '<?' at {0}. Processing instructions expect a name like <?foo ... ?>", badChar(ch)));
414     ch = _xmlParser.parseName(_text, ch);
415
416     String JavaDoc piName = _text.toString();
417     if (! piName.equals("xml"))
418       return parsePITail(piName, ch);
419     else {
420       throw error(L.l("<?xml ... ?> occurs after content. The <?xml ... ?> prolog must be at the document start."));
421
422     }
423   }
424
425   private int parsePITail(String JavaDoc piName, int ch)
426     throws IOException JavaDoc, SAXException JavaDoc
427   {
428     ch = _xmlParser.skipWhitespace(ch);
429
430     _text.clear();
431     while (ch != -1) {
432       if (ch == '?') {
433         if ((ch = read()) == '>')
434           break;
435         else
436           _text.append('?');
437       } else {
438         _text.append((char) ch);
439         ch = read();
440       }
441     }
442
443     QProcessingInstruction pi;
444     pi = new QProcessingInstruction(piName, _text.toString());
445     pi._owner = _dtd._owner;
446     _dtd.appendChild(pi);
447
448     return read();
449   }
450
451   /**
452    * Parses a comment. The "&lt;!--" has already been read.
453    */

454   private void parseComment()
455     throws IOException JavaDoc, SAXException JavaDoc
456   {
457     int ch = read();
458
459     if (ch != '-')
460       throw error(L.l("expected comment at {0}", badChar(ch)));
461
462     ch = read();
463
464   comment:
465     while (ch != -1) {
466       if (ch == '-') {
467     ch = read();
468
469     while (ch == '-') {
470       if ((ch = read()) == '>')
471         break comment;
472       else if (_strictComments)
473         throw error(L.l("XML forbids '--' in comments"));
474       else if (ch == '-') {
475           }
476       else {
477         break;
478           }
479     }
480       } else if (! XmlChar.isChar(ch)) {
481         throw error(L.l("bad character {0}", hex(ch)));
482       } else {
483     ch = read();
484       }
485     }
486
487     QComment comment = new QComment(_buf.toString());
488     comment._owner = _dtd._owner;
489     _dtd.appendChild(comment);
490   }
491
492   /**
493    * Ignores content to the ']]>'
494    */

495   private void parseIgnore()
496     throws IOException JavaDoc, SAXException JavaDoc
497   {
498     int ch = read();
499
500     while (ch >= 0) {
501       if (ch != ']') {
502     ch = read();
503       }
504       else if ((ch = read()) != ']') {
505       }
506       else if ((ch = read()) == '>')
507     return;
508     }
509   }
510
511   private int parseContentSpec(QElementDef def, int ch)
512     throws IOException JavaDoc, SAXException JavaDoc
513   {
514     ch = expandPE(ch);
515     
516     if (XmlChar.isNameStart(ch)) {
517       ch = _xmlParser.parseName(_text, ch);
518       String JavaDoc name = _text.toString();
519
520       if (name.equals("EMPTY")) {
521     def._content = "EMPTY";
522     return ch;
523       }
524       else if (name.equals("ANY")) {
525     def._content = "ANY";
526     return ch;
527       }
528       else
529     throw error(L.l("expected EMPTY or ANY at '{0}'", name));
530     }
531     else if (ch != '(') {
532       throw error(L.l("expected grammar definition starting with '(' at {0}. <!ELEMENT> definitions have the syntax <!ELEMENT name - - (grammar)>", badChar(ch)));
533     }
534     else {
535       QContentParticle cp = new QContentParticle();
536       def._content = cp;
537
538       return parseContentParticle(cp, true);
539     }
540   }
541
542   /**
543    * Parses a content-particle, i.e. a grammer particle in the DTD
544    * regexp.
545    */

546   private int parseContentParticle(QContentParticle cp, boolean isTop)
547     throws IOException JavaDoc, SAXException JavaDoc
548   {
549     boolean hasCdata = false;
550     cp._separator = 0;
551     cp._repeat = 0;
552     int ch;
553
554     ch = expandPE(read());
555     
556     for (; ch != -1; ch = expandPE(ch)) {
557       if (ch == '(') {
558     QContentParticle child = new QContentParticle();
559     cp.addChild(child);
560     
561     ch = parseContentParticle(child, false);
562       }
563       else if (XmlChar.isNameStart(ch)) {
564     ch = _xmlParser.parseName(_text, ch);
565     cp.addChild(_text.toString());
566       }
567       else if (ch == '#') {
568     ch = _xmlParser.parseName(_text, read());
569     String JavaDoc name = _text.toString();
570
571     if (cp._children.size() != 0)
572       throw error(L.l("'#{0}' must occur first", name));
573     if (! isTop)
574       throw error(L.l("'#{0}' may only occur at top level", name));
575
576     if (name.equals("PCDATA"))
577       cp.addChild("#PCDATA");
578     else
579       throw error(L.l("illegal content particle at '#{0}'", name));
580
581     hasCdata = true;
582       }
583       else
584     throw error(L.l("expected content particle at {0}", badChar(ch)));
585
586       ch = expandPE(ch);
587
588       if (ch == '?' || ch == '*' || ch == '+') {
589         Object JavaDoc child = cp.getChild(cp.getChildSize() - 1);
590         if (child instanceof QContentParticle) {
591           QContentParticle cpChild = (QContentParticle) child;
592           cpChild._repeat = ch;
593         }
594         else {
595           QContentParticle cpChild = new QContentParticle();
596           cpChild.addChild(child);
597           cpChild._repeat = ch;
598           cp.setChild(cp.getChildSize() - 1, cpChild);
599         }
600
601         ch = expandPE(read());
602       }
603
604       if (ch == ')')
605     break;
606       else if (cp._separator == 0) {
607     if (ch == '|')
608       cp._separator = ch;
609     else if (hasCdata)
610       throw error(L.l("#PCDATA must be separated by '|' at {0}",
611                           badChar(ch)));
612     else if (ch == ',')
613       cp._separator = ch;
614     else
615       throw error(L.l("expected separator at {0}", badChar(ch)));
616
617     ch = read();
618       } else if (ch != cp._separator)
619     throw error(L.l("expected '{0}' at {1}",
620                         "" + (char) cp._separator, badChar(ch)));
621       else
622     ch = read();
623     }
624
625     ch = expandPE(read());
626
627     if (hasCdata && (ch == '+' || ch == '?'))
628       throw error(L.l("pcdata clause can not have {0}", badChar(ch)));
629     else if (ch == '*' || ch == '+' || ch == '?') {
630       cp._repeat = ch;
631       return read();
632     }
633     else
634       return ch;
635   }
636
637   private int expandPE(int ch)
638     throws IOException JavaDoc, SAXException JavaDoc
639   {
640     ch = _xmlParser.skipWhitespace(ch);
641     
642     while (ch == '%') {
643       parsePEReference();
644       ch = _xmlParser.skipWhitespace(read());
645     }
646
647     return ch;
648   }
649
650   /**
651    * Parses a PE reference %foo; and inserts the macro text to the input
652    * stream.
653    */

654   private void parsePEReference()
655     throws IOException JavaDoc, SAXException JavaDoc
656   {
657     int ch = _xmlParser.parseName(_buf, read());
658
659     if (ch != ';')
660       throw error(L.l("'%{0};' expects ';' at {1}. Parameter entities have a '%name;' syntax.", _buf, badChar(ch)));
661
662     addPEReference(_text, _buf.toString());
663   }
664
665   /**
666    * Expands the macro value of a PE reference.
667    */

668   private void addPEReference(CharBuffer value, String JavaDoc name)
669     throws IOException JavaDoc, SAXException JavaDoc
670   {
671     QEntity entity = _dtd.getParameterEntity(name);
672
673     if (entity == null && ! _dtd.isExternal())
674       throw error(L.l("'%{0};' is an unknown parameter entity. Parameter entities must be defined in an <!ENTITY> declaration before use.", name));
675     else if (entity != null && entity._value != null) {
676       _xmlParser.setMacro(entity._value);
677     }
678     else if (entity != null && entity.getSystemId() != null) {
679       _xmlParser.pushInclude(entity.getPublicId(), entity.getSystemId());
680     }
681     else {
682       value.append("%");
683       value.append(name);
684       value.append(";");
685     }
686   }
687
688   /**
689    * <!ELEMENT name contentspec>
690    */

691   private void parseElementDecl(QDocumentType doctype)
692     throws IOException JavaDoc, SAXException JavaDoc
693   {
694     int ch = _xmlParser.skipWhitespace(read());
695
696     ch = _xmlParser.parseName(_text, ch);
697     String JavaDoc name = _text.toString();
698
699     ch = _xmlParser.skipWhitespace(ch);
700
701     QElementDef def = _dtd.addElement(name);
702     def.setLocation(getSystemId(), getFilename(), getLine(), getColumn());
703
704     boolean needsStartTag = true;
705     boolean needsEndTag = true;
706
707     ch = parseContentSpec(def, ch);
708
709     ch = _xmlParser.skipWhitespace(ch);
710
711     if (ch != '>')
712       throw error(L.l("'<!ELEMENT' must close with '>' at {0}", badChar(ch)));
713   }
714
715   private static String JavaDoc toAttrDefault(CharBuffer text)
716   {
717     for (int i = 0; i < text.length(); i++) {
718       int ch = text.charAt(i);
719
720       if (ch == '"') {
721     text.delete(i, i + 1);
722     text.insert(i, "&#34;");
723     i--;
724       } else if (ch == '\'') {
725     text.delete(i, i + 1);
726     text.insert(i, "&#39;");
727     i--;
728       }
729     }
730
731     return text.toString();
732   }
733
734   /**
735    * <!ATTLIST name (attr type def)*>
736    */

737   private void parseAttlistDecl(QDocumentType doctype)
738     throws IOException JavaDoc, SAXException JavaDoc
739   {
740     int ch = _xmlParser.skipWhitespace(read());
741
742     ch = _xmlParser.parseName(_text, ch);
743     String JavaDoc name = _text.toString();
744
745     ch = _xmlParser.skipWhitespace(ch);
746
747     QElementDef def = _dtd.addElement(name);
748
749     while (XmlChar.isNameStart((ch = expandPE(ch)))) {
750       ch = _xmlParser.parseName(_text, ch);
751       String JavaDoc attrName = _text.toString();
752
753       String JavaDoc attrType = null;
754       ArrayList<String JavaDoc> enumeration = null;
755       ch = expandPE(ch);
756       if (ch == '(') {
757     attrType = "#ENUM";
758     enumeration = new ArrayList<String JavaDoc>();
759     do {
760       ch = expandPE(read());
761
762       ch = parseNameToken(_text, ch);
763       enumeration.add(_text.toString());
764
765       ch = expandPE(ch);
766     } while (ch == '|');
767
768     if (ch != ')')
769       throw error(L.l("expected '{0}' at {1}. <!ATTRLIST> enumerations definitions are enclosed in '(' ... ')'.", ")", badChar(ch)));
770     ch = read();
771       }
772       else {
773     ch = _xmlParser.parseName(_text, ch);
774     attrType = _text.toString();
775
776     if (attrType.equals("NOTATION")) {
777       enumeration = new ArrayList<String JavaDoc>();
778       ch = expandPE(ch);
779       if (ch != '(')
780             throw error(L.l("expected '{0}' at {1}", "(", badChar(ch)));
781
782       do {
783         ch = expandPE(read());
784
785         ch = _xmlParser.parseName(_text, ch);
786         enumeration.add(_text.toString());
787
788         ch = expandPE(ch);
789       } while (ch == '|');
790
791       if (ch != ')')
792         throw error(L.l("expected '{0}' at {1}", ")", badChar(ch)));
793       ch = read();
794     }
795     else if (_attrTypes.get(attrType) != null) {
796     }
797         else
798       throw error(L.l("expected attribute type at '{0}'", attrType));
799       }
800
801       ch = _xmlParser.skipWhitespace(ch);
802       String JavaDoc qualifier = null;
803       String JavaDoc attrDefault = null;
804       if (ch == '#') {
805     ch = _xmlParser.parseName(_text, read());
806     qualifier = "#" + _text.toString();
807
808     if (qualifier.equals("#IMPLIED")) {
809     }
810     else if (qualifier.equals("#REQUIRED")) {
811     }
812     else if (qualifier.equals("#FIXED")) {
813       ch = _xmlParser.skipWhitespace(ch);
814       ch = parseValue(_text, ch, false);
815       attrDefault = _text.toString();
816     } else
817       throw error(L.l("expected attribute default at '{0}'",
818                       qualifier));
819       }
820       else if (ch != '>') {
821     ch = parseValue(_text, ch, false);
822     attrDefault = _text.toString();
823       }
824
825       def.addAttribute(attrName, attrType, enumeration,
826                        qualifier, attrDefault);
827       if (attrType != null && attrType.equals("ID"))
828     doctype.setElementId(name, attrName);
829
830       ch = _xmlParser.skipWhitespace(ch);
831     }
832
833     if (ch != '>')
834       throw error(L.l("expected '{0}' at {1}", ">", badChar(ch)));
835   }
836
837   /**
838    * <!NOTATION name systemId publicId>
839    */

840   private void parseNotationDecl(QDocumentType doctype)
841     throws IOException JavaDoc, SAXException JavaDoc
842   {
843     int ch = _xmlParser.skipWhitespace(read());
844
845     ch = _xmlParser.parseName(_text, ch);
846     String JavaDoc name = _text.toString();
847
848     ch = _xmlParser.skipWhitespace(ch);
849     ch = _xmlParser.parseName(_text, ch);
850     String JavaDoc key = _text.toString();
851
852     ch = _xmlParser.skipWhitespace(ch);
853     ch = parseValue(_text, ch, false);
854     String JavaDoc id = _text.toString();
855
856     ch = _xmlParser.skipWhitespace(ch);
857
858     QNotation notation;
859
860     if (key.equals("PUBLIC")) {
861       String JavaDoc systemId = null;
862
863       if (ch == '"' || ch == '\'') {
864     ch = parseValue(_text, ch, false);
865     ch = _xmlParser.skipWhitespace(ch);
866     systemId = _text.toString();
867       }
868
869       notation = new QNotation(name, id, systemId);
870       notation._owner = doctype._owner;
871       notation.setLocation(getSystemId(), getFilename(), getLine(), getColumn());
872     }
873     else if (key.equals("SYSTEM")) {
874       notation = new QNotation(name, null, id);
875       notation._owner = doctype._owner;
876       notation.setLocation(getSystemId(), getFilename(), getLine(), getColumn());
877     }
878     else
879       throw error(L.l("expected PUBLIC or SYSTEM at '{0}'", key));
880     
881     doctype.addNotation(notation);
882     doctype.appendChild(notation);
883
884     if (ch != '>')
885       throw error(L.l("expected '{0}' at {1}", ">", badChar(ch)));
886   }
887
888   /**
889    * externalID ::= PUBLIC publicId systemId
890    * ::= SYSTEM systemId
891    */

892   private int parseExternalID(int ch)
893     throws IOException JavaDoc, SAXException JavaDoc
894   {
895     ch = _xmlParser.parseName(_text, ch);
896     String JavaDoc key = _text.toString();
897     ch = _xmlParser.skipWhitespace(ch);
898
899     _extSystemId = null;
900     _extPublicId = null;
901     if (key.equals("PUBLIC")) {
902       ch = parseValue(_text, ch, false);
903       _extPublicId = _text.toString();
904       ch = _xmlParser.skipWhitespace(ch);
905
906       if (_extPublicId.indexOf('&') > 0)
907     throw error(L.l("Illegal character '&' in PUBLIC identifier '{0}'",
908             _extPublicId));
909
910       ch = parseValue(_text, ch, false);
911       ch = _xmlParser.skipWhitespace(ch);
912       _extSystemId = _text.toString();
913     }
914     else if (key.equals("SYSTEM")) {
915       ch = parseValue(_text, ch, false);
916       _extSystemId = _text.toString();
917     }
918     else
919       throw error(L.l("expected PUBLIC or SYSTEM at '{0}'", key));
920
921     return ch;
922   }
923
924   /**
925    * <!ENTITY name systemId publicId>
926    */

927   private void parseEntityDecl(QDocumentType doctype)
928     throws IOException JavaDoc, SAXException JavaDoc
929   {
930     int ch = _xmlParser.skipWhitespace(read());
931
932     boolean isPe = ch == '%';
933
934     if (isPe)
935       ch = _xmlParser.skipWhitespace(read());
936
937     ch = _xmlParser.parseName(_text, ch);
938     String JavaDoc name = _text.toString();
939
940     ch = _xmlParser.skipWhitespace(ch);
941
942     QEntity entity;
943     if (ch == '"' || ch == '\'') {
944       ch = parseValue(_text, ch, false);
945       
946       entity = new QEntity(name, _text.toString(), null, null);
947       entity._owner = doctype._owner;
948       entity.setLocation(getSystemId(), getFilename(), getLine(), getColumn());
949     }
950     else {
951       ch = parseExternalID(ch);
952
953       entity = new QEntity(name, null, _extPublicId, _extSystemId);
954       entity._owner = doctype._owner;
955       entity.setLocation(getSystemId(), getFilename(), getLine(), getColumn());
956
957       ch = _xmlParser.skipWhitespace(ch);
958       if (! isPe && XmlChar.isNameStart(ch)) {
959     ch = _xmlParser.parseName(_text, ch);
960     String JavaDoc key = _text.toString();
961     if (key.equals("NDATA")) {
962       ch = _xmlParser.skipWhitespace(ch);
963       ch = _xmlParser.parseName(_text, ch);
964
965       String JavaDoc ndata = _text.toString();
966
967       entity._ndata = ndata;
968     } else
969       throw error(L.l("expected 'NDATA' at '{0}'", key));
970       }
971     }
972       
973     entity._isPe = isPe;
974
975     if (isPe)
976       doctype.addParameterEntity(entity);
977     else
978       doctype.addEntity(entity);
979
980     doctype.appendChild(entity);
981
982     ch = _xmlParser.skipWhitespace(ch);
983
984     if (ch != '>')
985       throw error(L.l("expected '>' at {0}", badChar(ch)));
986   }
987
988   private boolean isWhitespace(int ch)
989   {
990     return ch <= 0x20 && (ch == 0x20 || ch == 0x9 || ch == 0xa || ch == 0xd);
991   }
992
993   private boolean isChar(int ch)
994   {
995     return (ch >= 0x20 && ch <= 0xd7ff ||
996         ch == 0x9 ||
997         ch == 0xa ||
998         ch == 0xd ||
999         ch >= 0xe000 && ch <= 0xfffd);
1000  }
1001
1002  /**
1003   * Returns the hex representation of a byte.
1004   */

1005  private static String JavaDoc hex(int value)
1006  {
1007    CharBuffer cb = CharBuffer.allocate();
1008
1009    for (int b = 3; b >= 0; b--) {
1010      int v = (value >> (4 * b)) & 0xf;
1011      if (v < 10)
1012    cb.append((char) (v + '0'));
1013      else
1014    cb.append((char) (v - 10 + 'a'));
1015    }
1016
1017    return cb.close();
1018  }
1019
1020  private int read()
1021    throws IOException JavaDoc, SAXException JavaDoc
1022  {
1023    return _xmlParser.read();
1024  }
1025
1026  public void unread(int ch)
1027  {
1028    _xmlParser.unread(ch);
1029  }
1030
1031  private String JavaDoc getSystemId()
1032  {
1033    return _xmlParser.getSystemId();
1034  }
1035
1036  private String JavaDoc getFilename()
1037  {
1038    return _xmlParser.getFilename();
1039  }
1040
1041  private XmlParseException error(String JavaDoc msg)
1042  {
1043    return _xmlParser.error(msg);
1044  }
1045
1046  private int getLine()
1047  {
1048    return _xmlParser.getLine();
1049  }
1050
1051  private int getColumn()
1052  {
1053    return _xmlParser.getColumn();
1054  }
1055
1056  private String JavaDoc badChar(int ch)
1057  {
1058    return _xmlParser.badChar(ch);
1059  }
1060  
1061  static {
1062    _attrTypes.put("CDATA", "CDATA");
1063    _attrTypes.put("ID", "ID");
1064    _attrTypes.put("IDREF", "IDREF");
1065    _attrTypes.put("IDREFS", "IDREFS");
1066    _attrTypes.put("ENTITY", "ENTITY");
1067    _attrTypes.put("ENTITIES", "ENTITIES");
1068    _attrTypes.put("NMTOKEN", "NMTOKEN");
1069    _attrTypes.put("NMTOKENS", "NMTOKENS");
1070  }
1071}
1072
Popular Tags