XmlParser.java
上传用户:haojie1228
上传日期:2022-08-08
资源大小:347k
文件大小:13k
源码类别:

通讯/手机编程

开发平台:

Java

  1. /* kXML
  2.  *
  3.  * The contents of this file are subject to the Enhydra Public License
  4.  * Version 1.1 (the "License"); you may not use this file except in
  5.  * compliance with the License. You may obtain a copy of the License
  6.  * on the Enhydra web site ( http://www.enhydra.org/ ).
  7.  *
  8.  * Software distributed under the License is distributed on an "AS IS"
  9.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  10.  * the License for the specific terms governing rights and limitations
  11.  * under the License.
  12.  *
  13.  * The Initial Developer of kXML is Stefan Haustein. Copyright (C)
  14.  * 2000, 2001 Stefan Haustein, D-46045 Oberhausen (Rhld.),
  15.  * Germany. All Rights Reserved.
  16.  *
  17.  * Contributor(s): Paul Palaszewski, Wilhelm Fitzpatrick, 
  18.  *                 Eric Foster-Johnson, Michael Angel, Jan Andrle
  19.  *
  20.  * */
  21. package org.kxml.parser;
  22. import java.io.*;
  23. import java.util.*;
  24. import org.kxml.*;
  25. import org.kxml.io.ParseException;
  26. /** A simple, pull based "Common XML" parser. Attention: This class has
  27.     been renamed from DefaultParser for consitency with the org.kxml.io
  28.     package. */
  29. public class XmlParser extends AbstractXmlParser {
  30.     static final String UNEXPECTED_EOF = "Unexpected EOF"; 
  31.     
  32.     char [] buf;
  33.     boolean eof;
  34.     int bufPos;
  35.     int bufCount;
  36.     Reader reader;
  37.     boolean relaxed;
  38.     int line = 1;
  39.     int column = 1;
  40.     
  41.     Vector qNames = new Vector ();
  42.     
  43.     boolean immediateClose = false;
  44.     StartTag current;
  45.     
  46.     /** The next event. May be null at startup. */
  47.     protected ParseEvent next;
  48.     
  49.     int peekChar () throws IOException {
  50. if (eof) return -1;
  51. if (bufPos >= bufCount) {
  52.             if (buf.length == 1) {
  53.                 int c = reader.read ();
  54.                 if (c == -1) {
  55.                     eof = true;
  56.                     return -1;
  57.                 }
  58.                 bufCount = 1;
  59.                 buf [0] = (char) c;
  60.             }
  61.             else {
  62.                 bufCount = reader.read (buf, 0, buf.length);
  63.                 if (bufCount == -1) {
  64.                     eof = true;
  65.                     return -1;
  66.                 }
  67.             }
  68.     bufPos = 0;
  69. }
  70. return buf[bufPos];
  71.     }       
  72.     
  73.     int readChar () throws IOException {
  74.        int p = peekChar ();
  75.        bufPos++;
  76.        column++;
  77.        if (p == 10) {
  78.    line++;
  79.    column = 1;
  80.        }
  81.        return p;
  82.     }
  83.     
  84.     void skipWhitespace () throws IOException {
  85. while (!eof && peekChar () <= ' ')
  86.     readChar ();
  87.     }
  88.     
  89.     
  90.     
  91.     public String readName () throws IOException {
  92. int c = readChar ();
  93. if (c < 128 && c != '_' && c != ':' 
  94. && (c < 'a' || c > 'z')
  95. && (c < 'A' || c > 'Z'))
  96.     throw new DefaultParserException ("name expected!", null);
  97. StringBuffer buf = new StringBuffer ();
  98. buf.append ((char) c);
  99. while (!eof) {
  100.     c = peekChar ();
  101.     
  102.     if (c < 128 && c != '_' && c != '-' && c != ':' && c != '.' 
  103. && (c < '0' || c > '9')
  104. && (c < 'a' || c > 'z')
  105. && (c < 'A' || c > 'Z'))
  106. break;
  107.     
  108.     buf.append ((char) readChar ());
  109. }
  110. return buf.toString ();
  111.     }
  112.     
  113.     /** Reads chars to the given buffer until the given stopChar 
  114. is reached. The stopChar itself is not consumed. */
  115.     public StringBuffer readTo (char stopChar,
  116. StringBuffer buf) throws IOException {
  117. while (!eof && peekChar () != stopChar) 
  118.     buf.append ((char) readChar ());
  119. return buf;
  120.     }
  121.     /** creates a new Parser based on the give reader */
  122.     
  123.     class DefaultParserException extends ParseException {
  124. DefaultParserException (String msg, Exception chained) {
  125.     super (msg, chained, XmlParser.this.line, XmlParser.this.column);
  126. }
  127.     }
  128.     
  129.     
  130.     public XmlParser (Reader reader) throws IOException {
  131.         this (reader, 
  132.               Runtime.getRuntime ().freeMemory () >= 1048576 ? 8192 : 1);
  133.     }
  134.     public XmlParser (Reader reader, int bufSize) throws IOException {
  135. this.reader = reader; //new LookAheadReader (reader); 
  136.         buf = new char [bufSize];
  137.     }
  138.     
  139.     
  140.     public String resolveCharacterEntity (String name) throws IOException {
  141. throw new DefaultParserException ("Undefined: &"+name+";", null);
  142.     }
  143.     
  144.     
  145.     /* precondition: &lt;!- consumed */
  146.     
  147.     ParseEvent parseComment () throws IOException {
  148.        
  149. StringBuffer buf = new StringBuffer ();
  150. if (readChar () != '-') 
  151.     throw new DefaultParserException ("'-' expected", null);
  152. int cnt;
  153. int lst;
  154.     
  155. while (true) {
  156.     readTo ('-', buf);
  157.     
  158.     if (readChar () == -1) 
  159. throw new DefaultParserException (UNEXPECTED_EOF, null);
  160.     
  161.     cnt = 0;
  162.     do {
  163. lst = readChar ();
  164. cnt++;  // adds one more, but first is not cnted
  165.     }
  166.     while (lst == '-');
  167.     
  168.     if (lst == '>' && cnt >= 2) break;
  169.     
  170.     while (cnt-- > 0) 
  171. buf.append ('-');
  172.     
  173.     buf.append ((char) lst);
  174. }
  175. while (cnt-- > 2) 
  176.     buf.append ('-');
  177. return new ParseEvent (Xml.COMMENT, buf.toString ());
  178.     }
  179.     
  180.     /* precondition: &lt! consumed */ 
  181.     
  182.     
  183.     ParseEvent parseDoctype () throws IOException {
  184. StringBuffer buf = new StringBuffer ();
  185. int nesting = 1;
  186. while (true) {
  187.     int i = readChar ();
  188.     switch (i) {
  189.     case -1:
  190. throw new DefaultParserException (UNEXPECTED_EOF, null);
  191.     case '<': 
  192. nesting++;
  193. break;
  194.     case '>':
  195. if ((--nesting) == 0)
  196.     return new ParseEvent (Xml.DOCTYPE, buf.toString ());
  197. break;
  198.     }
  199.     buf.append ((char) i);
  200. }
  201.     }
  202.     
  203.     
  204.     ParseEvent parseCData () throws IOException {
  205. StringBuffer buf = readTo ('[', new StringBuffer ());
  206. if (!buf.toString ().equals ("CDATA")) 
  207.     throw new DefaultParserException ("Invalid CDATA start!", null);
  208. buf.setLength (0);
  209. readChar (); // skip '['
  210. int c0 = readChar ();
  211. int c1 = readChar ();
  212. while (true) {
  213.     int c2 = readChar ();
  214.     
  215.     if (c2 == -1) 
  216. throw new DefaultParserException (UNEXPECTED_EOF, null);
  217.     
  218.     if (c0 == ']' && c1 == ']' && c2 == '>') 
  219. break;
  220.     
  221.     buf.append ((char) c0);
  222.     c0 = c1;
  223.     c1 = c2;
  224. }
  225.     
  226. return new ParseEvent (Xml.TEXT, buf.toString ());
  227.     }
  228.     
  229.     
  230.     
  231.     /* precondition: &lt;/ consumed */
  232.     ParseEvent parseEndTag () throws IOException {
  233. skipWhitespace ();
  234. String name = readName ();
  235. skipWhitespace ();
  236. if (readChar () != '>') 
  237.     throw new DefaultParserException ("'>' expected", null);
  238. int last = qNames.size ();
  239. while (true) {
  240.     if (last == 0) {
  241. if (relaxed) return new ParseEvent (Xml.END_DOCUMENT, null);
  242. throw new DefaultParserException 
  243.     ("tagstack empty parsing </"+name+">", null);
  244.     }
  245.     String qName = (String) qNames.elementAt (--last);
  246.     qNames.removeElementAt (last);
  247.     
  248.     if (qName.equals (name)) break; 
  249.     if (!relaxed) throw new DefaultParserException 
  250. ("StartTag <"+qName
  251.  +"> does not match end tag </" + name + ">", null);
  252.     if (qName.toLowerCase ().equals (name.toLowerCase ())) break;
  253.     current = current.parent;
  254. }
  255. Tag result = new Tag 
  256.     (Xml.END_TAG, current, current.namespace, current.name);
  257. current = current.parent;
  258. return result;
  259.     }
  260.     
  261.     /** precondition: <? consumed */
  262.     
  263.     ParseEvent parsePI () throws IOException {
  264. StringBuffer buf = new StringBuffer ();
  265. readTo ('?', buf);
  266. readChar (); // ?
  267. while (peekChar () != '>') {
  268.     buf.append ('?');
  269.     
  270.     int r = readChar ();
  271.     if (r == -1) throw new DefaultParserException 
  272. (UNEXPECTED_EOF, null);
  273.     
  274.     buf.append ((char) r);
  275.     readTo ('?', buf);
  276.     readChar ();
  277. }
  278. readChar ();  // consume >
  279.     
  280. return new ParseEvent 
  281.     (Xml.PROCESSING_INSTRUCTION, buf.toString ());
  282.     }
  283.     
  284.     
  285.     StartTag parseStartTag () throws IOException {
  286. //current = new StartTag (current, reader, relaxed);
  287. //prefixMap = parent == null ? new PrefixMap () : parent.prefixMap;
  288. String qname = readName ();
  289. //System.out.println ("name: ("+name+")");
  290.         Vector attributes = null;
  291. immediateClose = false;
  292. while (true) { 
  293.     skipWhitespace ();
  294.     
  295.     int c = peekChar ();
  296.         
  297.     if (c == '/') {
  298. immediateClose = true;
  299. readChar ();
  300. skipWhitespace ();
  301. if (readChar () != '>') 
  302.     throw new DefaultParserException  
  303. ("illegal element termination", null);
  304. break;
  305.     }
  306.     
  307.     if (c == '>') { 
  308. readChar ();
  309. break;
  310.     }
  311.     
  312.     if (c == -1) 
  313. throw new DefaultParserException (UNEXPECTED_EOF, null); 
  314.     
  315.     String attrName = readName ();
  316.     
  317.     if (attrName.length() == 0)
  318. throw new DefaultParserException
  319.                     ("illegal char / attr", null);
  320.     
  321.     skipWhitespace ();
  322.     if (readChar () != '=') 
  323. throw new DefaultParserException 
  324.     ("Attribute name "+attrName
  325.      +"must be followed by '='!", null);
  326.     skipWhitespace ();
  327.     int delimiter = readChar ();
  328.     
  329.     if (delimiter != ''' && delimiter != '"') {
  330. if (!relaxed)
  331.     throw new DefaultParserException 
  332. ("<" + qname + ">: invalid delimiter: " 
  333.  + (char) delimiter, null);  
  334. delimiter = ' ';
  335.     }
  336.     
  337.     StringBuffer buf = new StringBuffer ();
  338.     readText (buf, (char) delimiter);
  339.     if (attributes == null) attributes = new Vector ();
  340.     attributes.addElement 
  341. (new Attribute (null, attrName, buf.toString ()));
  342.     
  343.     if (delimiter != ' ')
  344.     readChar ();  // skip endquote
  345. }       
  346. try {
  347.     current = new StartTag 
  348. (current, Xml.NO_NAMESPACE, qname, attributes, 
  349.  immediateClose, processNamespaces);
  350. }       
  351. catch (Exception e) {
  352.     throw new DefaultParserException (e.toString (), e);
  353. }
  354. //System.out.println ("tag: ("+next+")");
  355. if (!immediateClose)
  356.     qNames.addElement (qname);
  357. return current;
  358.     }
  359.     
  360.     
  361.     int readText (StringBuffer buf, char delimiter) throws IOException {
  362. int type = Xml.WHITESPACE;
  363. int nextChar;
  364. while (true) {
  365.     nextChar = peekChar ();
  366.     if (nextChar == -1 
  367. || nextChar == delimiter 
  368. || (delimiter == ' ' 
  369.     && (nextChar == '>' || nextChar < ' '))) break;
  370.     
  371.     readChar ();
  372.     
  373.     if (nextChar == '&') {
  374. String code = readTo (';', new StringBuffer ()).toString ();
  375. readChar ();
  376. if (code.charAt (0) == '#') {
  377.     nextChar = (code.charAt (1) == 'x' 
  378. ? Integer.parseInt (code.substring (2), 16) 
  379. : Integer.parseInt (code.substring (1)));
  380.     
  381.     if (nextChar > ' ') 
  382. type = Xml.TEXT;
  383.     
  384.     buf.append ((char) nextChar);           
  385. }
  386. else {
  387.     if (code.equals ("lt")) buf.append ('<');
  388.     else if (code.equals ("gt")) buf.append ('>');
  389.     else if (code.equals ("apos")) buf.append (''');
  390.     else if (code.equals ("quot")) buf.append ('"');
  391.     else if (code.equals ("amp")) buf.append ('&');
  392.     else buf.append (resolveCharacterEntity (code));
  393.     
  394.     type = Xml.TEXT;
  395. }
  396.     }
  397.     else {
  398. if (nextChar > ' ') 
  399.     type = Xml.TEXT;
  400. buf.append ((char) nextChar);
  401.     }
  402. }
  403. return type;
  404.     }    
  405.     
  406.     /** precondition: &lt; consumed */
  407.     ParseEvent parseSpecial () throws IOException {
  408.     switch  (peekChar ()) {
  409.     case -1: throw new DefaultParserException 
  410.         (UNEXPECTED_EOF, null); 
  411.     case '!':
  412.         readChar ();
  413.         switch (peekChar ()) {
  414.         case '-': 
  415.         readChar ();
  416.         return parseComment ();
  417.         case '[':
  418.         readChar ();
  419.         return parseCData ();
  420.         default: 
  421.             return parseDoctype ();
  422.         }
  423.         
  424.     case '?':
  425.         readChar ();
  426.         return parsePI ();
  427.     case '/': 
  428.         readChar ();
  429.         return parseEndTag ();
  430.     default: 
  431.         return parseStartTag ();
  432.     }
  433.     }
  434.     public ParseEvent read () throws IOException{
  435.     if (next == null) 
  436.         peek ();
  437.     ParseEvent result = next;
  438.     next = null;
  439.     return result;
  440.     }
  441.     public ParseEvent peek () throws IOException {
  442.     
  443.     if (next == null) {
  444.         
  445.         if (immediateClose) {
  446.         next = new Tag 
  447.             (Xml.END_TAG, current, current.namespace, current.name);
  448.         current = current.getParent ();
  449.         immediateClose = false;
  450.         }
  451.         else {
  452.         switch (peekChar ()) {
  453.             
  454.         case '<': 
  455.             readChar ();
  456.             next = parseSpecial ();
  457.             break;
  458.             
  459.         case -1: 
  460.             if (current != null && !relaxed) 
  461.             throw new DefaultParserException 
  462.                 ("End tag missing for: "+current, null);
  463.             next = new ParseEvent (Xml.END_DOCUMENT, null);
  464.             break;
  465.             
  466.         default: 
  467.             {
  468.             StringBuffer buf = new StringBuffer ();
  469.             int type = readText (buf, '<');
  470.             next = new ParseEvent (type, buf.toString ());
  471.             }
  472.         }
  473.         }
  474.     }
  475.     return next;
  476.     }    
  477.     /** default is false. Setting relaxed true
  478.     allows CHTML parsing */
  479.     public void setRelaxed (boolean relaxed) {
  480.     this.relaxed = relaxed;
  481.     }
  482.     public int getLineNumber () {
  483. return line;
  484.     }
  485.     public int getColumnNumber () {
  486. return column;
  487.     }
  488. }