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 ::= <!ELEMENT ... | * <!ATTLIST ... | * <!NOTATION ... | * <!ENTITY ... | * <!-- comment | * <? 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 "<!--" 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 + -
显示快捷键?