dtdparser.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,072 行 · 第 1/2 页

JAVA
1,072
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * *   Free Software Foundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.xml2;import com.caucho.util.*;import com.caucho.vfs.Path;import com.caucho.vfs.ReadStream;import com.caucho.vfs.ReaderWriterStream;import com.caucho.vfs.Vfs;import com.caucho.vfs.WriteStream;import com.caucho.xml2.readers.MacroReader;import com.caucho.xml2.readers.Utf16Reader;import com.caucho.xml2.readers.Utf8Reader;import com.caucho.xml2.readers.XmlReader;import org.w3c.dom.Document;import org.w3c.dom.Node;import org.xml.sax.InputSource;import org.xml.sax.Locator;import org.xml.sax.SAXException;import org.xml.sax.SAXParseException;import javax.xml.namespace.QName;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import java.util.*;import java.util.logging.Level;/** * A configurable XML parser.  Loose versions of XML and HTML are supported * by changing the Policy object. * * <p>Normally, applications will use Xml, LooseXml, Html, or LooseHtml. */public class DtdParser{  private static final L10N L = new L10N(DtdParser.class);    static HashMap<String,String> _attrTypes = new HashMap<String,String>();  static Entities _entities = new XmlEntities();    private XmlParser _xmlParser;    QAttributes _attributes;  QAttributes _nullAttributes;  boolean _inDtd;  boolean _strictComments = true;    CharBuffer _text;  CharBuffer _eltName;  CharBuffer _cb;  CharBuffer _buf = new CharBuffer();  String _textFilename;  int _textLine;  char []_textBuffer = new char[1024];  int _textLength;  int _textCapacity = _textBuffer.length;  boolean _isIgnorableWhitespace;  boolean _isJspText;    CharBuffer _name = new CharBuffer();  CharBuffer _nameBuffer = new CharBuffer();    MacroReader _macro = new MacroReader();  int _macroIndex = 0;  int _macroLength = 0;  char []_macroBuffer;  QName []_elementNames = new QName[64];  NamespaceMap []_namespaces = new NamespaceMap[64];  int []_elementLines = new int[64];  int _elementTop;  NamespaceMap _namespaceMap;  ArrayList<String> _attrNames = new ArrayList<String>();  ArrayList<String> _attrValues = new ArrayList<String>();  ReadStream _is;  XmlReader _reader;    String _extPublicId;  String _extSystemId;    QName _activeNode;  QName _topNamespaceNode;  boolean _isTagStart;  boolean _stopOnIncludeEnd;  boolean _hasTopElement;  boolean _hasDoctype;  QDocumentType _dtd;  public DtdParser(XmlParser xmlParser, QDocumentType dtd)  {    _xmlParser = xmlParser;    _dtd = dtd;  }    /**   * Parses the DTD.   *   * <pre>   * dtd-item ::= &lt!ELEMENT ...  |   *              &lt!ATTLIST ...  |   *              &lt!NOTATION ... |   *              &lt!ENTITY ...   |   *              &lt!-- comment   |   *              &lt? pi          |   *              %pe-ref;   * </pre>   *   * @return the next character.   */  int parseDoctypeDecl(QDocumentType doctype)    throws IOException, SAXException  {    _hasDoctype = true;    int ch = 0;    for (ch = _xmlParser.skipWhitespace(read()); 	 ch >= 0 && ch != ']'; 	 ch = _xmlParser.skipWhitespace(read())) {      if (ch == '<') {	if ((ch = read()) == '!') {	  if (XmlChar.isNameStart(ch = read())) {	    ch = _xmlParser.parseName(_text, ch);	    String name = _text.toString();	    if (name.equals("ELEMENT"))	      parseElementDecl(doctype);	    else if (name.equals("ATTLIST"))	      parseAttlistDecl(doctype);	    else if (name.equals("NOTATION"))	      parseNotationDecl(doctype);	    else if (name.equals("ENTITY"))	      parseEntityDecl(doctype);	    else	      throw error("unknown declaration '" + name + "'");	  }	  else if (ch == '-')	    parseComment();	  else if (ch == '[') {	    ch = _xmlParser.parseName(_text, read());	    String name = _text.toString();	    if (name.equals("IGNORE")) {	      parseIgnore();	    }	    else if (name.equals("INCLUDE")) {	      parseIgnore();	    }	    else	      throw error(L.l("unknown declaration '{0}'", name));	  }	}	else if (ch == '?') {	  parsePI();	}	else 	  throw error(L.l("expected markup at {0}", badChar(ch)));      }      else if (ch == '%') {	ch = _xmlParser.parseName(_buf, read());	if (ch != ';')	  throw error(L.l("'%{0};' expects ';' at {1}.  Parameter entities have a '%name;' syntax.", _buf, badChar(ch)));	addPEReference(_text, _buf.toString());      }      else {	throw error(L.l("expected '<' at {0}", badChar(ch)));      }      _text.clear();    }    _text.clear();    return read();  }  private int parseNameToken(CharBuffer name, int ch)    throws IOException, SAXException  {    name.clear();    if (! XmlChar.isNameChar(ch))      throw error(L.l("expected name at {0}", badChar(ch)));    for (; XmlChar.isNameChar(ch); ch = read())      name.append((char) ch);    return ch;  }  private void appendText(String s)  {    if (_text.length() == 0) {      _textFilename = getFilename();      _textLine = getLine();    }    _text.append(s);  }  private int parseCharacterReference()    throws IOException, SAXException  {    int ch = read();    int radix = 10;    if (ch == 'x') {      radix = 16;      ch = read();    }    int value = 0;    for (; ch != ';'; ch = read()) {      if (ch >= '0' && ch <= '9')	value = radix * value + ch - '0';      else if (radix == 16 && ch >= 'a' && ch <= 'f')	value = radix * value + ch - 'a' + 10;      else if (radix == 16 && ch >= 'A' && ch <= 'F')	value = radix * value + ch - 'A' + 10;      else	throw error(L.l("malformed entity ref at {0}", badChar(ch)));    }    if (value > 0xffff)      throw error(L.l("malformed entity ref at {0}", "" + value));    // xml/0072    if (! isChar(value))      throw error(L.l("illegal character ref at {0}", badChar(value)));    return value;  }  /**   * Parses an attribute value.   *   * <pre>   * value ::= '[^']*'   *       ::= "[^"]*"   *       ::= [^ />]*   * </pre>   *   * @param value the CharBuffer which will contain the value.   * @param ch the next character from the input stream.   * @param isGeneral true if general entities are allowed.   *   * @return the following character from the input stream   */  private int parseValue(CharBuffer value, int ch, boolean isGeneral)    throws IOException, SAXException  {    int end = ch;    value.clear();    if (end == '\'' || end == '"')      ch = read();    else {      value.append((char) end);      for (ch = read();           ch >= 0 && XmlChar.isNameChar(ch);           ch = read())        value.append((char) ch);            throw error(L.l("XML attribute value must be quoted at '{0}'.  XML attribute syntax is either attr=\"value\" or attr='value'.",                      value));    }    while (ch != -1 && (end != 0 && ch != end			|| end == 0 && isAttributeChar(ch))) {      if (end == 0 && ch == '/') {	ch = read();	if (! isWhitespace(ch) && ch != '>') {	  value.append('/');	  value.append((char) ch);	}	else {          unread(ch);	  return '/';	}      }      else if (ch == '&') {	if ((ch = read()) == '#')	  value.append((char) parseCharacterReference());	else if (! isGeneral) {	  value.append('&');	  value.append((char) ch);	}        else if (XmlChar.isNameStart(ch)) {	  ch = _xmlParser.parseName(_buf, ch);	  String name = _buf.toString();	  if (ch != ';')	    throw error(L.l("expected '{0}' at {1}", ";", badChar(ch)));	  else {	    int lookup = _entities.getEntity(name);	    if (lookup >= 0 && lookup <= 0xffff) {	      ch = read();	      value.append((char) lookup);	      continue;	    }            	    QEntity entity = _dtd == null ? null : _dtd.getEntity(name);	    if (entity != null && entity._value != null)	      _xmlParser.setMacroAttr(entity._value);	    else	      throw error(L.l("expected local reference at '&{0};'", name));	  }	}      }      else if (ch == '%' && ! isGeneral) {        ch = read();        if (! XmlChar.isNameStart(ch)) {          value.append('%');          continue;        }        else {          ch = _xmlParser.parseName(_buf, ch);          if (ch != ';')            throw error(L.l("expected '{0}' at {1}", ";", badChar(ch)));          else            addPEReference(value, _buf.toString());        }      }       else if (isGeneral) {        if (ch == '\r') {          ch = read();          if (ch != '\n') {            value.append('\n');            continue;          }        }        value.append((char) ch);      }      else if (ch == '\r') {	value.append(' ');                if ((ch = read()) != '\n')          continue;      }      else if (ch == '\n')	value.append(' ');      else	value.append((char) ch);      ch = read();    }    if (end != 0)      ch = read();    return ch;  }  private boolean isAttributeChar(int ch)  {    switch (ch) {    case ' ': case '\t': case '\n': case '\r':      return false;    case '<': case '>': case '\'':case '"': case '=':      return false;    default:      return true;    }  }  private int parsePI()    throws IOException, SAXException  {    int ch;    ch = read();    if (! XmlChar.isNameStart(ch))      throw error(L.l("expected name after '<?' at {0}.  Processing instructions expect a name like <?foo ... ?>", badChar(ch)));    ch = _xmlParser.parseName(_text, ch);    String piName = _text.toString();    if (! piName.equals("xml"))      return parsePITail(piName, ch);    else {      throw error(L.l("<?xml ... ?> occurs after content.  The <?xml ... ?> prolog must be at the document start."));    }  }  private int parsePITail(String piName, int ch)    throws IOException, SAXException  {    ch = _xmlParser.skipWhitespace(ch);    _text.clear();    while (ch != -1) {      if (ch == '?') {        if ((ch = read()) == '>')          break;        else          _text.append('?');      } else {        _text.append((char) ch);        ch = read();      }    }    QProcessingInstruction pi;    pi = new QProcessingInstruction(piName, _text.toString());    pi._owner = _dtd._owner;    _dtd.appendChild(pi);    return read();  }  /**   * Parses a comment.  The "&lt;!--" has already been read.   */  private void parseComment()    throws IOException, SAXException  {    int ch = read();    if (ch != '-')      throw error(L.l("expected comment at {0}", badChar(ch)));    ch = read();  comment:    while (ch != -1) {      if (ch == '-') {	ch = read();	while (ch == '-') {	  if ((ch = read()) == '>')	    break comment;	  else if (_strictComments)	    throw error(L.l("XML forbids '--' in comments"));	  else if (ch == '-') {          }	  else {	    break;          }	}      } else if (! XmlChar.isChar(ch)) {        throw error(L.l("bad character {0}", hex(ch)));      } else {	ch = read();      }    }    QComment comment = new QComment(_buf.toString());    comment._owner = _dtd._owner;    _dtd.appendChild(comment);  }  /**   * Ignores content to the ']]>'   */  private void parseIgnore()    throws IOException, SAXException  {    int ch = read();    while (ch >= 0) {      if (ch != ']') {	ch = read();      }      else if ((ch = read()) != ']') {      }      else if ((ch = read()) == '>')	return;    }  }  private int parseContentSpec(QElementDef def, int ch)    throws IOException, SAXException  {    ch = expandPE(ch);        if (XmlChar.isNameStart(ch)) {      ch = _xmlParser.parseName(_text, ch);      String name = _text.toString();      if (name.equals("EMPTY")) {	def._content = "EMPTY";	return ch;      }      else if (name.equals("ANY")) {	def._content = "ANY";	return ch;      }      else	throw error(L.l("expected EMPTY or ANY at '{0}'", name));    }    else if (ch != '(') {      throw error(L.l("expected grammar definition starting with '(' at {0}.  <!ELEMENT> definitions have the syntax <!ELEMENT name - - (grammar)>", badChar(ch)));    }    else {      QContentParticle cp = new QContentParticle();      def._content = cp;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?