blob: b1b1b2cb08be5fb667d2cf0d41e5a3fc67ec18af [file] [log] [blame]
/*
* $Id$
*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Crimson" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
* http://www.sun.com. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xerces.tree;
import java.io.IOException;
import java.net.URL;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Vector;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.EntityReference;
import org.w3c.dom.DOMException;
import org.xml.sax.AttributeList;
import org.xml.sax.DocumentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.XMLReader;
import org.xml.sax.Attributes;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.ext.DeclHandler;
import org.apache.xerces.tree.AttributeListEx;
import org.apache.xerces.tree.DtdEventListener;
import org.apache.xerces.parsers.SAXParser;
import org.apache.xerces.tree.Resolver;
/**
* This class is a SAX DocumentHandler which converts a stream of parse
* events into an in-memory DOM document. After each <em>Parser.parse()</em>
* invocation returns, a resulting DOM Document may be accessed via the
* <em>getDocument</em> method. The parser and its builder should be used
* together; the builder may be used with only one parser at a time.
*
* <P> This builder optionally does XML namespace processing, reporting
* conformance problems as recoverable errors using the parser's error
* handler.
*
* <P> To customize the document, a powerful technique involves using
* an element factory specifying what element tags (from a given XML
* namespace) correspond to what implementation classes. Parse trees
* produced by such a builder can have nodes which add behaviors to
* achieve application-specific functionality, such as modifing the tree
* as it is parsed.
*
* <P> The object model here is that XML elements are polymorphic, with
* semantic intelligence embedded through customized internal nodes.
* Those nodes are created as the parse tree is built. Such trees now
* build on the W3C Document Object Model (DOM), and other models may be
* supported by the customized nodes. This allows both generic tools
* (understanding generic interfaces such as the DOM core) and specialized
* tools (supporting specialized behaviors, such as the HTML extensions
* to the DOM core; or for XSL elements) to share data structures.
*
* <P> Normally only "model" semantics are in document data structures,
* but "view" or "controller" semantics can be supported if desired.
*
* <P> Elements may choose to intercept certain parsing events directly.
* They do this by overriding the default implementations of methods
* in the <em>XmlReadable</em> interface. This is normally done to make
* the DOM tree represent application level modeling requirements, rather
* than matching an XML structure that may not be optimized appropriately.
*
* @author David Brownell
* @version $Revision$
*/
public class XmlDocumentBuilder implements
ContentHandler, DocumentHandler, LexicalHandler, DTDHandler, DeclHandler
{
// implicit predeclarations of "xml" namespace
private static final String
xmlURI = "http://www.w3.com/XML/1998/namespace";
// used during parsing
private XmlDocument document;
private Locator locator;
private ParseContextImpl context = new ParseContextImpl ();
private Locale locale = Locale.getDefault ();
private ElementFactory factory;
private SAXParser parser;
private Vector attrTmp = new Vector ();
private ParentNode elementStack [];
private int topOfStack;
private boolean inDTD;
private boolean inCDataSection;
private Doctype doctype;
private String publicId;
private String systemId;
private String internalSubset;
// parser modes
private boolean ignoringLexicalInfo = true;
private boolean disableNamespaces = true;
/**
* Default constructor is for use in conjunction with a SAX
* parser's <em>DocumentHandler</em> callback.
*/
public XmlDocumentBuilder () { }
/**
* Returns true (the default) if certain lexical information is
* automatically discarded when a DOM tree is built, producing
* smaller parse trees that are easier to use.
*/
public boolean isIgnoringLexicalInfo () {
return ignoringLexicalInfo;
}
/**
* Controls whether certain lexical information is discarded; by
* default, that information is discarded.
*
* <P> That information includes whitespace in element content which
* is ignorable (note that some nonvalidating XML parsers will not
* report that information); all comments; which text is found in
* CDATA sections; and boundaries of entity references.
*
* <P> "Ignorable whitespace" as reported by parsers is whitespace
* used to format XML markup. That is, all whitespace except that in
* "mixed" or ANY content models is ignorable. When it is discarded,
* pretty-printing may be necessary to make the document be readable
* again by humans.
*
* <P> Whitespace inside "mixed" and ANY content models needs different
* treatment, since it could be part of the document content. In such
* cases XML defines a <em>xml:space</em> attribute which applications
* should use to determine whether whitespace must be preserved (value
* of the attribute is <em>preserve</em>) or whether default behavior
* (such as eliminating leading and trailing space, and normalizing
* consecutive internal whitespace to a single space) is allowed.
*
* @param value true indicates that such lexical information should
* be discarded during parsing.
*/
public void setIgnoringLexicalInfo (boolean value) {
ignoringLexicalInfo = value;
}
/**
* Returns true if namespace conformance is not checked as the
* DOM tree is built.
*/
public boolean getDisableNamespaces () {
return disableNamespaces;
}
/**
* Controls whether namespace conformance is checked during DOM
* tree construction, or (the default) not. In this framework, the
* DOM Builder is responsible for enforcing all namespace constraints.
* When enabled, this makes constructing a DOM tree slightly slower.
* (However, at this time it can't enforce the requirement that
* parameter entity names not contain colons.)
*/
public void setDisableNamespaces (boolean value) {
disableNamespaces = value;
}
/**
* Sets the parser used by this builder.
*/
public void setParser (org.xml.sax.Parser p)
{
p.setDocumentHandler (this);
if (p instanceof SAXParser) {
parser = (SAXParser) p;
parser.setDTDHandler (new DtdListener ());
} else
parser = null;
}
/**
* Returns the parser used by this builder, if it is recorded.
*/
public SAXParser getParser ()
{ return parser; }
/**
* Returns the fruits of parsing, after a SAX parser has used this
* as a document handler during parsing.
*/
public XmlDocument getDocument () { return document; }
/**
* Returns the locale to be used for diagnostic messages by
* this builder, and by documents it produces. This uses
* the locale of any associated parser.
*/
/*public Locale getLocale ()
{
if (parser != null)
return parser.getLocale ();
else
return locale;
}*/
/**
* Assigns the locale to be used for diagnostic messages.
* Multi-language applications, such as web servers dealing with
* clients from different locales, need the ability to interact
* with clients in languages other than the server's default.
*
* <P>When an XmlDocument is created, its locale is the default
* locale for the virtual machine. If a parser was recorded,
* the locale will be associated with that parser.
*
* @see #chooseLocale
*/
public void setLocale (Locale locale)
throws SAXException
{
if (locale == null)
locale = Locale.getDefault ();
if (parser != null)
parser.setLocale (locale);
this.locale = locale;
}
/**
* Chooses a client locale to use for diagnostics, using the first
* language specified in the list that is supported by this builder.
* That locale is then automatically assigned using <a
* href="#setLocale(java.util.Locale)">setLocale()</a>. Such a list
* could be provided by a variety of user preference mechanisms,
* including the HTTP <em>Accept-Language</em> header field.
*
* @see org.apache.xerces.tree.MessageCatalog
*
* @param languages Array of language specifiers, ordered with the most
* preferable one at the front. For example, "en-ca" then "fr-ca",
* followed by "zh_CN". Both RFC 1766 and Java styles are supported.
* @return The chosen locale, or null.
*/
public Locale chooseLocale (String languages [])
throws SAXException
{
Locale l = XmlDocument.catalog.chooseLocale (languages);
if (l != null)
setLocale (l);
return l;
}
// Document operations ...
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports the locator object which will be used in reporting
* diagnostics and interpreting relative URIs in attributes and text.
*
* @param locator used to identify a location in an XML document
* being parsed.
*/
public void setDocumentLocator (Locator locator)
{
this.locator = locator;
}
/**
* Returns the document locator provided by the SAX parser. This
* is commonly used in diagnostics, and when interpreting relative
* URIs found in XML Processing Instructions or other parts of an
* XML document. This locator is only valid during document handler
* callbacks.
*/
public Locator getDocumentLocator ()
{
return locator;
}
/**
* This is a factory method, used to create an XmlDocument.
* Subclasses may override this method, for example to provide
* document classes with particular behaviors, or provide
* particular factory behaviours (such as returning elements
* that support the HTML DOM methods, if they have the right
* name and are in the right namespace).
*/
public XmlDocument createDocument ()
{
XmlDocument retval = new XmlDocument ();
if (factory != null)
retval.setElementFactory (factory);
return retval;
}
/**
* Assigns the factory to be associated with documents produced
* by this builder.
*/
final public void setElementFactory (ElementFactory factory)
{ this.factory = factory; }
/**
* Returns the factory to be associated with documents produced
* by this builder.
*/
final public ElementFactory getElementFactory ()
{ return factory; }
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports that the parser is beginning to process a document.
*/
public void startDocument () throws SAXException
{
document = createDocument ();
if (locator != null)
document.setSystemId (locator.getSystemId ());
//
// XXX don't want fixed size limits! Fix someday. For
// now, wide trees predominate, not deep ones. This is
// allowing a _very_ deep tree ... we typically observe
// depths on the order of a dozen.
//
elementStack = new ParentNode [200];
topOfStack = 0;
elementStack [topOfStack] = document;
inDTD = false;
document.startParse (context);
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports that the document has been fully parsed.
*/
public void endDocument () throws SAXException
{
if (topOfStack != 0)
throw new IllegalStateException (getMessage ("XDB-000"));
document.doneParse (context);
document.trimToSize ();
}
private String getNamespaceURI (String prefix)
{
if ("xml".equals (prefix))
return xmlURI;
else if ("xmlns".equals (prefix))
return null;
else
return elementStack [topOfStack]
.getInheritedAttribute ("xmlns:" + prefix);
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports that the parser started to parse a new element,
* with the given tag and attributes, and call its <em>startParse</em>
* method.
*
* @exception SAXParseException if XML namespace support is enabled
* and the tag or any attribute name contain more than one colon.
* @exception SAXException as appropriate, such as if a faulty parser
* provides an element or attribute name which is illegal.
*/
public void startElement (String tag, AttributeList attributes)
throws SAXException
{
AttributeSet attrs = null;
ElementNode e = null;
int length;
//
// Convert set of attributes to DOM representation.
//
length = (attributes == null) ? 0 : attributes.getLength ();
if (length != 0) {
try {
if (!disableNamespaces) {
//
// ID, IDREF(S), ENTITY(IES), NOTATION must be free of
// colons in value ... only CDATA and NMTOKEN(S) excepted.
//
for (int i = 0; i < length; i++) {
String type = attributes.getType (i);
if ("CDATA".equals (type)
|| type.startsWith ("NMTOKEN"))
continue;
if (attributes.getValue (i).indexOf (':') != -1)
error (new SAXParseException ((getMessage
("XDB-001", new Object []
{ attributes.getName (i) })), locator));
}
}
attrs = new AttributeSet (attributes);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-002", new
Object[] { ex.getMessage () })), locator, ex));
}
}
//
// Then create the element, associate its attributes, and
// stack it for later addition.
//
try {
if (disableNamespaces)
e = (ElementNode) document.createElementEx (tag);
else {
int index = tag.indexOf (':');
String attribute = "xmlns";
String namespace = "";
String localPart = tag;
if (index != -1) {
attribute = "xmlns:" + tag.substring (0, index);
localPart = tag.substring (index + 1);
if (tag.lastIndexOf (':') != index)
error (new SAXParseException ((getMessage ("XDB-003",
new Object [] { tag })), locator));
}
// Note: empty namespace URIs are ignored; the
// namespace spec doesn't say what they should do.
if (attrs != null)
namespace = attrs.getValue (attribute);
if ("".equals (namespace))
namespace = elementStack [topOfStack]
.getInheritedAttribute (attribute);
e = (ElementNode) document.createElementEx (namespace,
localPart);
// remember whatever prefix it came with
if (localPart != tag)
e.setTag (tag);
}
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
if (attributes != null && attributes instanceof AttributeListEx)
e.setIdAttributeName (
((AttributeListEx)attributes).getIdAttributeName ());
if (length != 0)
e.setAttributes (attrs);
elementStack [topOfStack++].appendChild (e);
elementStack [topOfStack] = e;
e.startParse (context);
//
// Division of responsibility for namespace processing is (being
// revised so) that the DOM builder reports errors when namespace
// constraints are violated, and the parser is ignorant of them.
//
if (!disableNamespaces) {
int index;
String prefix;
// Element prefix must be declared
index = tag.indexOf (':');
if (index > 0) {
prefix = tag.substring (0, index);
if (getNamespaceURI (prefix) == null)
error (new SAXParseException ((getMessage ("XDB-005",
new Object [] { prefix })), locator));
}
// Attribute prefixes must be declared, and only one instance
// of a given attribute (scope + local part) may appear
if (length != 0) {
// invariant: attrTmp empty except in this block
for (int i = 0; i < length; i++) {
String name = attrs.item (i).getNodeName ();
index = name.indexOf (':');
if (index > 0) {
String uri;
prefix = name.substring (0, index);
// "xmlns" is like a keyword
if ("xmlns".equals (prefix))
continue;
uri = getNamespaceURI (prefix);
if (uri == null) {
error (new SAXParseException ((getMessage
("XDB-006", new Object [] { prefix })),
locator));
continue;
}
if (name.lastIndexOf (':') != index)
error (new SAXParseException ((getMessage
("XDB-007", new Object [] { name })), locator));
// Unicode ffff -- illegal in URIs and XML names;
// the value is otherwise irrelevant
name = name.substring (index + 1);
name = uri + '\uffff' + name;
if (attrTmp.contains (name))
// duplicating attributes is a well-formedness
// error, but we don't interpret violations of
// namespace conformance as fatal errors if
// we have a chance.
error (new SAXParseException ((getMessage
("XDB-008", new Object [] { attrs.item
(i).getNodeName () })), locator));
else
attrTmp.addElement (name);
}
}
attrTmp.setSize (0);
}
}
}
public void startElement(String namespaceURI, String localName,
String rawName, Attributes attributes)
throws SAXException
{
//
// Convert set of attributes to DOM representation.
//
AttributeSet attSet = null;
int length = attributes.getLength();
if (length != 0) {
try {
attSet = new AttributeSet(attributes);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-002", new
Object[] { ex.getMessage () })), locator, ex));
}
}
//
// Then create the element, associate its attributes, and
// stack it for later addition.
//
ElementNode e = null;
try {
if (namespaceURI.equals("")) {
// Translate "" of SAX2 to null. See DOM2 spec under Node
// namespaceURI
namespaceURI = null;
}
e = (ElementNode)document.createElementNS(namespaceURI, rawName);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
if (attributes instanceof AttributeListEx) {
e.setIdAttributeName(
((AttributeListEx)attributes).getIdAttributeName());
}
if (length != 0) {
e.setAttributes(attSet);
}
elementStack[topOfStack++].appendChild(e);
elementStack[topOfStack] = e;
e.startParse(context);
//
// Division of responsibility for namespace processing is (being
// revised so) that the DOM builder reports errors when namespace
// constraints are violated, and the parser is ignorant of them.
//
if (!disableNamespaces) {
// XXX check duplicate attributes here ???
}
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports that the parser finished the current element.
* The element's <em>doneParse</em> method is then called.
*
* @exception SAXException as appropriate
*/
public void endElement (String tag)
throws SAXException
{
ElementNode e = (ElementNode) elementStack [topOfStack];
elementStack [topOfStack--] = null;
// Trusting that the SAX parser is correct, and hasn't
// mismatched start/end element callbacks.
// if (!tag.equals (e.getTagName ()))
// fatal (new SAXParseException ((getMessage ("XDB-009", new
// Object[] { tag, e.getTagName () })), locator));
try {
e.doneParse (context);
e.reduceWaste (); // use less space
elementStack [topOfStack].doneChild (e, context);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
public void endElement(String namespaceURI, String localName,
String rawName)
throws SAXException
{
ElementNode e = (ElementNode) elementStack[topOfStack];
elementStack[topOfStack--] = null;
// Trusting that the SAX parser is correct, and hasn't
// mismatched start/end element callbacks.
// if (!tag.equals (e.getTagName ()))
// fatal (new SAXParseException ((getMessage ("XDB-009", new
// Object[] { tag, e.getTagName () })), locator));
try {
e.doneParse(context);
e.reduceWaste(); // use less space
elementStack[topOfStack].doneChild(e, context);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
/**
* LexicalEventListener callback, not for general application
* use. Reports that CDATA section was begun.
*
* <P>If this builder is set to record lexical information (by default
* it ignores such information) then this callback arranges that
* character data (and ignorable whitespace) be recorded as part of
* a CDATA section, until the matching <em>endCDATA</em> method is
* called.
*/
public void startCDATA () throws SAXException
{
if (ignoringLexicalInfo)
return;
CDATASection text = document.createCDATASection ("");
ParentNode top = elementStack [topOfStack];
try {
inCDataSection = true;
top.appendChild (text);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
/**
* LexicalEventListener callback, not for general application
* use. Reports that CDATA section was completed.
* This terminates any CDATA section that is being constructed.
*/
public void endCDATA () throws SAXException
{
if (!inCDataSection)
return;
ParentNode top = elementStack [topOfStack];
try {
inCDataSection = false;
top.doneChild ((NodeEx) top.getLastChild (), context);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports text which is part of the document, and which will
* be provided stored as a Text node.
*
* <P> Some parsers report "ignorable" whitespace through this interface,
* which can cause portability problems. That's because there is no safe
* way to discard it from a parse tree without accessing DTD information,
* of a type which DOM doesn't expose and most applications won't want
* to deal with. Avoid using such parsers.
*
* @param buf holds text characters
* @param offset initial index of characters in <em>buf</em>
* @param len how many characters are being passed
* @exception SAXException as appropriate
*/
public void characters (char buf [], int offset, int len)
throws SAXException
{
ParentNode top = elementStack [topOfStack];
if (inCDataSection) {
String temp = new String (buf, offset, len);
CDATASection section;
section = (CDATASection) top.getLastChild ();
section.appendData (temp);
return;
}
try {
NodeBase lastChild = (NodeBase) top.getLastChild ();
if (lastChild instanceof TextNode) {
String tmp = new String (buf, offset, len);
((TextNode)lastChild).appendData (tmp);
} else {
TextNode text = document.newText (buf, offset, len);
top.appendChild (text);
top.doneChild (text, context);
}
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports ignorable whitespace; if lexical information is
* not ignored (by default, it is ignored) the whitespace reported
* here is recorded in a DOM text (or CDATA, as appropriate) node.
*
* @param buf holds text characters
* @param offset initial index of characters in <em>buf</em>
* @param len how many characters are being passed
* @exception SAXException as appropriate
*/
public void ignorableWhitespace (char buf [], int offset, int len)
throws SAXException
{
if (ignoringLexicalInfo)
return;
ParentNode top = elementStack [topOfStack];
if (inCDataSection) {
String temp = new String (buf, offset, len);
CDATASection section;
section = (CDATASection) top.getLastChild ();
section.appendData (temp);
return;
}
TextNode text = document.newText (buf, offset, len);
try {
top.appendChild (text);
top.doneChild (text, context);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
/**
* <b>SAX</b> DocumentHandler callback, not for general application
* use. Reports that a processing instruction was found.
*
* <P> Some applications may want to intercept processing instructions
* by overriding this method as one way to make such instructions
* take immediate effect during parsing, or to ensure that
* processing instructions in DTDs aren't ignored.
*
* @param name the processor to which the instruction is directed
* @param instruction the text of the instruction (no leading spaces)
* @exception SAXParseException if XML namespace support is enabled
* and the name contains a colon.
* @exception SAXException as appropriate
*/
public void processingInstruction (String name, String instruction)
throws SAXException
{
if (!disableNamespaces && name.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-010")), locator));
// Ignore PIs in DTD for DOM support
if (inDTD)
return;
ParentNode top = elementStack [topOfStack];
PINode pi;
try {
pi = (PINode) document.createProcessingInstruction (name,
instruction);
top.appendChild (pi);
top.doneChild (pi, context);
} catch (DOMException ex) {
fatal (new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
// mostly for namespace errors
private void error (SAXParseException err)
throws SAXException
{
if (parser != null)
parser.getErrorHandler ().error (err);
else
throw err;
}
private void fatal (SAXParseException err)
throws SAXException
{
if (parser != null)
parser.getErrorHandler ().fatalError (err);
throw err;
}
class ParseContextImpl implements ParseContext
{
public ErrorHandler getErrorHandler ()
{ return (parser != null) ? parser.getErrorHandler () : null; }
public Locale getLocale () {
//return XmlDocumentBuilder.this.getLocale ();
// XXX need to change SAXParser for this
return Locale.getDefault();
}
public Locator getLocator ()
{ return locator; }
}
//
// We really want to be able to use this ... not only does it
// build the DOM DocumentType object, but it also does many
// of the namespace conformance tests that SAX alone can't
// support.
//
class DtdListener implements DtdEventListener
{
private Doctype doctype;
private String publicId;
private String systemId;
private String internalSubset;
public void startDtd (String root)
{
doctype = document.createDoctype (root);
XmlDocumentBuilder.this.inDTD = true;
}
public void externalDtdDecl (String p, String s)
throws SAXException
{
publicId = p;
systemId = s;
}
public void internalDtdDecl (String s)
throws SAXException
{
internalSubset = s;
}
public void externalEntityDecl (String n, String p, String s)
throws SAXException
{
if (!disableNamespaces && n.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-012")),
locator));
doctype.addEntityNode (n, p, s, null);
}
public void internalEntityDecl (String n, String v)
throws SAXException
{
if (!disableNamespaces && n.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-012")),
locator));
doctype.addEntityNode (n, v);
}
public void notationDecl (String n, String p, String s)
throws SAXException
{
if (!disableNamespaces && n.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-013")),
locator));
doctype.addNotation (n, p, s);
}
public void unparsedEntityDecl (String n, String p, String s, String t)
throws SAXException
{
if (!disableNamespaces && n.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-012")),
locator));
doctype.addEntityNode (n, p, s, t);
}
public void elementDecl (String elementName, String contentModel)
throws SAXException
{
// ignored
}
public void attributeDecl (
String elementName,
String attributeName,
String attributeType,
String options [],
String defaultValue,
boolean isFixed,
boolean isRequired
) throws SAXException
{
// ignored
}
public void endDtd ()
{
doctype.setPrintInfo (publicId, systemId, internalSubset);
document.appendChild (doctype);
XmlDocumentBuilder.this.inDTD = false;
}
}
/*
* Gets the messages from the resource bundles for the given messageId.
*/
String getMessage (String messageId) {
return getMessage (messageId, null);
}
/*
* Gets the messages from the resource bundles for the given messageId
* after formatting it with the parameters passed to it.
*/
String getMessage (String messageId, Object[] parameters) {
/*if (locale == null) {
getLocale ();
}*/
return XmlDocument.catalog.getMessage (locale, messageId, parameters);
}
/*
* ContentHandler methods (some already declared above)
*/
public void skippedEntity(String name) throws SAXException {
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException
{
}
public void endPrefixMapping(String prefix) throws SAXException {
}
/*
* org.xml.sax.ext.LexicalHandler methods (some already declared above)
*/
public void startDTD(String name, String publicId, String systemId)
throws SAXException
{
doctype = document.createDoctype(name);
inDTD = true;
this.systemId = systemId;
this.publicId = publicId;
}
public void endDTD() throws SAXException {
doctype.setPrintInfo(publicId, systemId, internalSubset);
document.appendChild(doctype);
inDTD = false;
}
public void startEntity(String name) throws SAXException {
// Our parser doesn't report Paramater entities. Need to make
// changes for that.
// Ignore entity refs while parsing DTD
if (ignoringLexicalInfo || inDTD) {
return;
}
EntityReference e = document.createEntityReference(name);
elementStack[topOfStack++].appendChild(e);
elementStack[topOfStack] = (ParentNode)e;
}
public void endEntity(String name) throws SAXException {
// Ignore entity refs while parsing DTD
if (inDTD) {
return;
}
ParentNode entity = elementStack[topOfStack];
if (!(entity instanceof EntityReference))
return;
entity.setReadonly(true);
elementStack[topOfStack--] = null;
if (!name.equals(entity.getNodeName()))
fatal(new SAXParseException ((getMessage ("XDB-011", new
Object[] { name, entity.getNodeName () })), locator));
try {
elementStack[topOfStack].doneChild(entity, context);
} catch (DOMException ex) {
fatal(new SAXParseException ((getMessage ("XDB-004", new
Object [] { ex.getMessage () })), locator, ex));
}
}
// startCDATA() defined above
// endCDATA() defined above
public void comment(char[] ch, int start, int length) throws SAXException {
// Ignore comments if lexical info is to be ignored,
// or if parsing the DTD
if (ignoringLexicalInfo || inDTD) {
return;
}
String text = new String(ch, start, length);
Comment comment = document.createComment(text);
ParentNode top = elementStack[topOfStack];
try {
top.appendChild(comment);
top.doneChild((NodeEx) comment, context);
} catch (DOMException ex) {
fatal(new SAXParseException((getMessage("XDB-004", new
Object[] { ex.getMessage() })), locator, ex));
}
}
/*
* org.xml.sax.ext.DeclHandler methods
*/
public void elementDecl(String name, String model) throws SAXException {
// ignored
}
public void attributeDecl(String eName, String aName, String type,
String valueDefault, String value)
throws SAXException
{
// ignored
}
public void internalEntityDecl(String name, String value)
throws SAXException
{
if (!disableNamespaces && name.indexOf (':') != -1) {
error(new SAXParseException((getMessage("XDB-012")), locator));
}
doctype.addEntityNode(name, value);
}
public void externalEntityDecl(String name, String publicId,
String systemId)
throws SAXException
{
if (!disableNamespaces && name.indexOf (':') != -1) {
error(new SAXParseException((getMessage("XDB-012")), locator));
}
doctype.addEntityNode(name, publicId, systemId, null);
}
/*
* DTDHandler methods
*/
public void notationDecl (String n, String p, String s)
throws SAXException
{
if (!disableNamespaces && n.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-013")),
locator));
doctype.addNotation (n, p, s);
}
public void unparsedEntityDecl (String name, String publicId,
String systemId, String notation)
throws SAXException
{
if (!disableNamespaces && name.indexOf (':') != -1)
error (new SAXParseException ((getMessage ("XDB-012")),
locator));
doctype.addEntityNode (name, publicId, systemId, notation);
}
}