- /*
- * $Id: XmlDocument.java,v 1.10 2001/11/09 08:44:06 edwingo Exp $
- *
- * 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.crimson.tree;
-
-
- import java.io.InputStream;
- import java.io.OutputStreamWriter;
- import java.io.OutputStream;
- import java.io.Writer;
- import java.io.IOException;
-
- import java.util.Dictionary;
- import java.util.Enumeration;
- import java.util.Hashtable;
- import java.util.Locale;
-
- import org.w3c.dom.*;
-
- import org.xml.sax.InputSource;
- import org.xml.sax.SAXException;
- import org.xml.sax.SAXParseException;
- import org.xml.sax.helpers.DefaultHandler;
- import org.xml.sax.helpers.XMLReaderFactory;
- import org.xml.sax.XMLReader;
-
- import org.apache.crimson.parser.Parser2;
- import org.apache.crimson.parser.Resolver;
- import org.apache.crimson.parser.ValidatingParser;
-
- import org.apache.crimson.util.MessageCatalog;
- import org.apache.crimson.util.XmlNames;
-
-
- /**
- * This class implements the DOM <em>Document</em> interface, and also
- * provides static factory methods to create document instances. Instances
- * represent the top level of an XML 1.0 document, typically consisting
- * of processing instructions followed by one tree of XML data. These
- * documents may be written out for transfer or storage using a variety
- * of text encodings.
- *
- * <P> The static factory methods do not offer any customization options.
- * in particular, they do not enforce XML Namespaces when parsing, do not
- * offer customizable element factories, and discard certain information
- * which is not intended to be significant to applications. If your
- * application requires more sophisticated use of DOM, you may need
- * to use SAX directly with an <em>XmlDocumentBuilder</em>.
- *
- * <P> <b>Note: element factories are deprecated</b> because they are
- * non-standard. They are only provided in this version for backwards
- * compatibility. Instances are factories for their subsidiary nodes, but
- * applications may provide their own element factory to bind element tags
- * to particular DOM implementation classes (which must subclass
- * ElementNode). For example, a factory may use a set of classes which
- * support the HTML DOM methods, or which support methods associated with
- * XML vocabularies for specialized problem domains as found within
- * Internet Commerce systems. For example, an element tag
- * <code><PurchaseOrder></code> could be mapped to a
- * <code>com.startup.commerce.PurchaseOrder</code> class. The factory can
- * also use XML Namespace information, if desired.
- *
- * <P> Since DOM requires nodes to be owned exclusively by one document,
- * they can't be moved from one document to another using DOM APIs. This
- * class provides an <em>changeNodeOwner</em> functionality which may be
- * used to change the document associated with a node, and with any of its
- * children.
- *
- * <P> <em> Only the core DOM model is supported here, not the HTML support.
- * Such support basically adds a set of convenience element types, and so
- * can be implemented through element factories and document subclasses.</em>
- *
- * @see XmlDocumentBuilder
- *
- * @author David Brownell
- * @author Rajiv Mordani
- * @version $Revision: 1.10 $
- */
- public class XmlDocument extends ParentNode implements DocumentEx
- {
- // package private (with jdk 1.1 'javac' bug workaround)
- static /* final */ String eol;
-
- static {
- String temp;
- try { temp = System.getProperty ("line.separator", "\n"); }
- catch (SecurityException e) { temp = "\n"; }
- eol = temp;
- }
-
- static final MessageCatalog catalog = new Catalog ();
-
- private Locale locale = Locale.getDefault ();
-
- private String systemId;
- private ElementFactory factory;
-
- // package private
- int mutationCount;
- boolean replaceRootElement;
-
- /**
- * Constructs an empty document object.
- */
- public XmlDocument() {
- // No-op
- }
-
- /**
- * Construct an XML document from the data at the specified URI,
- * optionally validating. This uses validating parser if
- * validation is requested, otherwise uses non-validating
- * parser. XML Namespace conformance is not tested when parsing.
- *
- * @param documentURI The URI (normally URL) of the document
- * @param doValidate If true, validity errors are treated as fatal
- *
- * @exception IOException as appropriate
- * @exception SAXException as appropriate
- * @exception SAXParseException (with line number information)
- * for parsing errors
- * @exception IllegalStateException at least when the parser
- * is configured incorrectly
- * @deprecated Use JAXP javax.xml.parsers package instead
- */
- public static XmlDocument createXmlDocument (
- String documentURI,
- boolean doValidate
- ) throws IOException, SAXException
- {
- return createXmlDocument (new InputSource (documentURI), doValidate);
- }
-
-
- /**
- * Construct an XML document from the data at the specified URI,
- * using the nonvalidating parser. XML Namespace conformance
- * is not tested when parsing.
- *
- * @param documentURI The URI (normally URL) of the document
- *
- * @exception IOException as appropriate
- * @exception SAXException as appropriate
- * @exception SAXParseException (with line number information)
- * for parsing errors
- * @exception IllegalStateException at least when the parser
- * is configured incorrectly
- * @deprecated Use JAXP javax.xml.parsers package instead
- */
- public static XmlDocument createXmlDocument (String documentURI)
- throws IOException, SAXException
- {
- return createXmlDocument (new InputSource (documentURI), false);
- }
-
-
- /**
- * Construct an XML document from input stream, optionally validating.
- * This document must not require interpretation of relative URLs,
- * since the base URL is not known. This uses the validating parser
- * if validation is requested, otherwise uses the non-validating
- * parser. XML Namespace conformance is not tested when parsing.
- *
- * @param in Holds xml document
- * @param doValidate If true, validity errors are treated as fatal
- *
- * @exception IOException as appropriate
- * @exception SAXException as appropriate
- * @exception SAXParseException (with line number information)
- * for parsing errors
- * @exception IllegalStateException at least when the parser
- * is configured incorrectly
- * @deprecated Use JAXP javax.xml.parsers package instead
- */
- public static XmlDocument createXmlDocument (
- InputStream in,
- boolean doValidate
- ) throws IOException, SAXException
- {
- return createXmlDocument (new InputSource (in), doValidate);
- }
-
- /**
- * Construct an XML document from the data in the specified input
- * source, optionally validating. This uses the validating parser
- * if validation is requested, otherwise uses the non-validating
- * parser. XML Namespace conformance is not tested when parsing.
- *
- * @param in The input source of the document
- * @param doValidate If true, validity errors are treated as fatal
- *
- * @exception IOException as appropriate
- * @exception SAXException as appropriate
- * @exception SAXParseException (with line number information)
- * for parsing errors
- * @exception IllegalStateException at least when the parser
- * is configured incorrectly
- * @deprecated Use JAXP javax.xml.parsers package instead
- */
- public static XmlDocument createXmlDocument(InputSource in,
- boolean doValidate)
- throws IOException, SAXException
- {
- // Create XMLReader allowing user to override using system property
- // String defaultReader = "org.apache.xerces.parsers.SAXParser";
- String defaultReader = "org.apache.crimson.parser.XMLReaderImpl";
- String prop;
- try {
- prop = System.getProperty("org.xml.sax.driver", defaultReader);
- } catch (SecurityException se) {
- // This can happen if we are running as an applet
- prop = defaultReader;
- }
- XMLReader xmlReader = XMLReaderFactory.createXMLReader(prop);
-
- //
- // Namespace related features needed for XmlDocumentBuilder
- //
- String namespaces = "http://xml.org/sax/features/namespaces";
- xmlReader.setFeature(namespaces, true);
-
- String nsPrefixes = "http://xml.org/sax/features/namespace-prefixes";
- xmlReader.setFeature(nsPrefixes, true);
-
- // Create XmlDocumentBuilder instance
- XmlDocumentBuilder builder = new XmlDocumentBuilder();
-
- // Use as the ContentHandler
- xmlReader.setContentHandler(builder);
-
- // org.xml.sax.ext.LexicalHandler
- String lexHandler = "http://xml.org/sax/properties/lexical-handler";
- xmlReader.setProperty(lexHandler, builder);
-
- // org.xml.sax.ext.DeclHandler
- String declHandler
- = "http://xml.org/sax/properties/declaration-handler";
- xmlReader.setProperty(declHandler, builder);
-
- // DTDHandler
- xmlReader.setDTDHandler(builder);
-
- // Validation
- String validation = "http://xml.org/sax/features/validation";
- xmlReader.setFeature(validation, doValidate);
-
- // If validating, use an error handler that throws an exception for
- // validation errors.
- if (doValidate) {
- xmlReader.setErrorHandler(new DefaultHandler() {
- public void error(SAXParseException e) throws SAXException {
- throw e;
- }
- });
- }
-
- builder.setDisableNamespaces(true);
-
- // Parse the input
- xmlReader.parse(in);
- return builder.getDocument();
- }
-
- /**
- * Returns the locale to be used for diagnostic messages.
- */
- public Locale getLocale ()
- { 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.
- * When an XmlDocument is created, its locale is the default
- * locale for the virtual machine.
- *
- * @see #chooseLocale
- */
- public void setLocale (Locale locale)
- {
- if (locale == null)
- locale = Locale.getDefault ();
- this.locale = locale;
- }
-
- /**
- * Chooses a client locale to use for diagnostics, using the first
- * language specified in the list that is supported by this DOM
- * implementation. 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.crimson.util.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 [])
- {
- Locale l = catalog.chooseLocale (languages);
-
- if (l != null)
- setLocale (l);
- return l;
- }
-
-
- /**
- * Writes the document in UTF-8 character encoding, as a well formed
- * XML construct.
- *
- * @param out stream on which the document will be written
- */
- public void write (OutputStream out) throws IOException
- {
- Writer writer = new OutputStreamWriter (out, "UTF8");
- write (writer, "UTF-8");
- }
-
- /**
- * Writes the document as a well formed XML construct. If the
- * encoding can be determined from the writer, that is used in
- * the document's XML declaration. The encoding name may first
- * be transformed from a Java-internal form to a standard one;
- * for example, Java's "UTF8" is the standard "UTF-8".
- *
- * <P> <em>Use of UTF-8 (or UTF-16) OutputStreamWriters is strongly
- * encouraged. </em> All other encodings may lose critical data,
- * since the standard Java output writers substitute characters
- * such as the question mark for data which they can't encode in
- * the current output encoding. The IETF and other organizations
- * strongly encourage the use of UTF-8; also, all XML processors
- * are guaranteed to support it.
- *
- * @see #write(java.io.Writer,java.lang.String)
- *
- * @param out stream on which the document will be written
- */
- public void write (Writer out) throws IOException
- {
- String encoding = null;
-
- if (out instanceof OutputStreamWriter)
- encoding = java2std (((OutputStreamWriter)out).getEncoding ());
- write (out, encoding);
- }
-
-
- //
- // Try some of the common conversions from Java's internal names
- // (which must fit in class names) to standard ones understood by
- // most other code. We use the IETF's preferred names; case is
- // supposed to be ignored, note.
- //
- // package private
- static String java2std (String encodingName)
- {
- if (encodingName == null)
- return null;
-
- //
- // ISO-8859-N is a common family of 8 bit encodings;
- // N=1 is the eight bit subset of UNICODE, and there
- // seem to be at least drafts for some N >10.
- //
- if (encodingName.startsWith ("ISO8859_")) // JDK 1.2
- return "ISO-8859-" + encodingName.substring (8);
- if (encodingName.startsWith ("8859_")) // JDK 1.1
- return "ISO-8859-" + encodingName.substring (5);
-
- // XXX seven bit encodings ISO-2022-* ...
- // XXX EBCDIC encodings ...
-
- if ("ASCII7".equalsIgnoreCase (encodingName)
- || "ASCII".equalsIgnoreCase (encodingName))
- return "US-ASCII";
-
- //
- // All XML parsers _must_ support UTF-8 and UTF-16.
- // (UTF-16 ~= ISO-10646-UCS-2 plus surrogate pairs)
- //
- if ("UTF8".equalsIgnoreCase (encodingName))
- return "UTF-8";
- if (encodingName.startsWith ("Unicode"))
- return "UTF-16";
-
- //
- // Some common Japanese character sets.
- //
- if ("SJIS".equalsIgnoreCase (encodingName))
- return "Shift_JIS";
- if ("JIS".equalsIgnoreCase (encodingName))
- return "ISO-2022-JP";
- if ("EUCJIS".equalsIgnoreCase (encodingName))
- return "EUC-JP";
-
- // else we can't really do anything
- return encodingName;
- }
-
-
- /**
- * Writes the document in the specified encoding, and listing
- * that encoding in the XML declaration. The document will be
- * well formed XML; at this time, it will not additionally be
- * valid XML or standalone, since it includes no document type
- * declaration.
- *
- * <P> Note that the document will by default be "pretty printed".
- * Extra whitespace is added to indent children of elements according
- * to their level of nesting, unless those elements have (or inherit)
- * the <em>xml:space='preserve'</em> attribute value. This space
- * will be removed if, when the document is read back with DOM, a
- * call to <em>ElementNode.normalize</em> is made. To avoid this
- * pretty printing, use a write context configured to disable it,
- * or explicitly assign an <em>xml:space='preserve'</em> attribute to
- * the root node of your document.
- *
- * <P> Also, if a SAX parser was used to construct this tree, data
- * will have been discarded. Most of that will be insignificant in
- * terms of a "logical" view of document data: comments, whitespace
- * outside of the top level element, the exact content of the XML
- * directive, and entity references were expanded. However, <em>if a
- * DOCTYPE declaration was provided, it was also discarded</em>.
- * Such declarations will often be logically significant, due to the
- * attribute value defaulting and normalization they can provide.
- *
- * <P> In general, DOM does not support "round tripping" data from
- * XML to DOM and back without losing data about physical structures
- * and DTD information. "Logical structure" will be preserved.
- *
- * @see #setDoctype
- * @see #writeXml
- *
- * @param out the writer to use when writing the document
- * @param encoding the encoding name to use; this should be a
- * standard encoding name registered with the IANA (like "UTF-8")
- * not a Java-internal name (like "UTF8").
- */
- public void write (Writer out, String encoding)
- throws IOException
- {
- //
- // We put a pretty minimal declaration here, which is the
- // best we can do given SAX input and DOM. For the moment
- // this precludes our generating "standalone" annotations.
- //
- out.write ("<?xml version=\"1.0\"");
- if (encoding != null) {
- out.write (" encoding=\"");
- out.write (encoding);
- out.write ('\"');
- }
- out.write ("?>");
- out.write (eol);
- out.write (eol);
-
- writeChildrenXml (createWriteContext (out, 0));
- out.write (eol);
- out.flush ();
- }
-
- /**
- * Returns an XML write context set up not to pretty-print,
- * and which knows about the entities defined for this document.
- *
- * @param out stream on which the document will be written
- */
- public XmlWriteContext createWriteContext (Writer out)
- {
- return new ExtWriteContext (out);
- }
-
- /**
- * Returns an XML write context which pretty-prints output starting
- * at a specified indent level, and which knows about the entities
- * defined for this document.
- *
- * @param out stream on which the document will be written
- * @param level initial indent level for pretty-printing
- */
- public XmlWriteContext createWriteContext (Writer out, int level)
- {
- return new ExtWriteContext (out, level);
- }
-
- /**
- * Writes the document out using the specified context, using
- * an encoding name derived from the stream in the context where
- * that is possible.
- *
- * @see #createWriteContext(java.io.Writer)
- * @see #createWriteContext(java.io.Writer,int)
- *
- * @param context describes how to write the document
- */
- public void writeXml (XmlWriteContext context) throws IOException
- {
- Writer out = context.getWriter ();
- String encoding = null;
-
- //
- // XXX as above, it should be possible to be "told" this name
- // in order to use more standard names. We can pretty print,
- // or we can use the right encoding name; not both!!
- //
- if (out instanceof OutputStreamWriter)
- encoding = java2std (((OutputStreamWriter)out).getEncoding ());
-
- //
- // We put a pretty minimal declaration here, which is the
- // best we can do given SAX input and DOM. For the moment
- // this precludes our generating "standalone" annotations.
- //
- out.write ("<?xml version=\"1.0\"");
- if (encoding != null) {
- out.write (" encoding=\"");
- out.write (encoding);
- out.write ('\"');
- }
- out.write ("?>");
- out.write (eol);
- out.write (eol);
-
- writeChildrenXml (context);
- }
-
- /**
- * Writes all the child nodes of the document, following each one
- * with the end-of-line string in use in this environment.
- */
- public void writeChildrenXml (XmlWriteContext context) throws IOException
- {
- int length = getLength ();
- Writer out = context.getWriter ();
-
- if (length == 0)
- return;
- for (int i = 0; i < length; i++) {
- ((NodeBase)item (i)).writeXml (context);
- out.write (eol);
- }
- }
-
-
- // package private -- overrides base class method
- void checkChildType (int type)
- throws DOMException
- {
- switch (type) {
- case ELEMENT_NODE:
- case PROCESSING_INSTRUCTION_NODE:
- case COMMENT_NODE:
- case DOCUMENT_TYPE_NODE:
- return;
- default:
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- }
- }
-
- /**
- * Assigns the URI associated with the document, which is its
- * system ID.
- *
- * @param uri The document's system ID, as used when storing
- * the document.
- */
- final public void setSystemId (String uri)
- {
- systemId = uri;
- }
-
- /**
- * Returns system ID associated with the document, or null if
- * this is unknown.
- *
- * <P> This URI should not be used when interpreting relative URIs,
- * since the document may be partially stored in external parsed
- * entities with different base URIs. Instead, use methods in the
- * <em>XmlReadable</em> interface as the document is being parsed,
- * so that the correct base URI is available.
- */
- final public String getSystemId ()
- {
- return systemId;
- }
-
-
- // DOM support
-
-
- /**
- * DOM: Appends the specified child node to the document. Only one
- * element or document type node may be a child of a document.
- *
- * @param node the node to be appended.
- */
- public Node appendChild (Node n)
- throws DOMException
- {
- if (n instanceof Element && getDocumentElement () != null)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- if (n instanceof DocumentType && getDoctype () != null)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- return super.appendChild (n);
- }
-
- /**
- * DOM: Inserts the specified child node into the document. Only one
- * element or document type node may be a child of a document.
- *
- * @param n the node to be inserted.
- * @param refNode the node before which this is to be inserted
- */
- public Node insertBefore (Node n, Node refNode)
- throws DOMException
- {
- if (!replaceRootElement && n instanceof Element &&
- getDocumentElement () != null)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- if (!replaceRootElement && n instanceof DocumentType
- && getDoctype () != null)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- return super.insertBefore (n, refNode);
- }
-
- /**
- * <b>DOM:</b> Replaces the specified child with the new node,
- * returning the original child or throwing an exception.
- * The new child must belong to this particular document.
- *
- * @param newChild the new child to be inserted
- * @param refChild node which is to be replaced
- */
- public Node replaceChild (Node newChild, Node refChild)
- throws DOMException
- {
- if (newChild instanceof DocumentFragment ) {
- int elemCount = 0;
- int docCount = 0;
- replaceRootElement = false;
- ParentNode frag = (ParentNode) newChild;
- Node temp;
- int i = 0;
- while ((temp = frag.item (i)) != null) {
- if (temp instanceof Element)
- elemCount++;
-
- else if (temp instanceof DocumentType)
- docCount++;
- i++;
- }
- if (elemCount > 1 || docCount > 1)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- else
- replaceRootElement = true;
- }
- return super.replaceChild (newChild, refChild);
- }
-
-
- /** DOM: Returns the DOCUMENT_NODE node type constant. */
- final public short getNodeType () { return DOCUMENT_NODE; }
-
-
- /** DOM: returns the document type (DTD) */
- final public DocumentType getDoctype ()
- {
- // We ignore comments, PIs, whitespace, etc
- // and return the first (only!) doctype.
- for (int i = 0; true; i++) {
- Node n = item (i);
- if (n == null)
- return null;
- if (n instanceof DocumentType)
- return (DocumentType) n;
- }
- }
-
- /**
- * Establishes how the document prints its document type. If a system
- * ID (URI) is provided, that is used in a SYSTEM (or PUBLIC, if a public
- * ID is also provided) declaration. If an internal subset is provided,
- * that will be printed. The root element in the DTD will be what the
- * document itself provides.
- *
- * @param dtdPublicId Holds a "public identifier" used to identify the
- * last part of the external DTD subset that is read into the DTD.
- * This may be omitted, and in any case is ignored unless a system
- * ID is provided.
- * @param dtdSystemId Holds a "system identifier" (a URI) used to
- * identify the last part of the external DTD subset that is read
- * into the DTD. This may be omitted, in which case the document
- * type will contain at most an internal subset. This URI should
- * not be a relative URI unless the document will be accessed in a
- * context from which that relative URI makes sense.
- * @param internalSubset Optional; this holds XML text which will
- * be put into the internal subset. This must be legal syntax,
- * and it is not tested by this document.
- */
- public DocumentType setDoctype (
- String dtdPublicId,
- String dtdSystemId,
- String internalSubset
- ) {
- Doctype retval = (Doctype) getDoctype ();
-
- if (retval != null)
- retval.setPrintInfo (dtdPublicId, dtdSystemId,
- internalSubset);
- else {
- retval = new Doctype (dtdPublicId, dtdSystemId,
- internalSubset);
- retval.setOwnerDocument (this);
- insertBefore (retval, getFirstChild ());
- }
- return retval;
- }
-
-
- /**
- * DOM: Returns the content root element.
- */
- public Element getDocumentElement ()
- {
- // We ignore comments, PIs, whitespace, etc
- // and return the first (only!) element.
- for (int i = 0; true; i++) {
- Node n = item (i);
- if (n == null)
- return null;
- if (n instanceof Element) {
- return (Element)n;
- }
- }
- }
-
- /**
- * Assigns the element factory to be used by this document.
- *
- * @param factory the element factory to be used; if this is null,
- * all elements will be implemented by <em>ElementNode</em>.
- * @deprecated
- */
- final public void setElementFactory (ElementFactory factory)
- {
- this.factory = factory;
- }
-
- /**
- * Returns the element factory to be used by this document.
- * @deprecated
- */
- final public ElementFactory getElementFactory ()
- {
- return factory;
- }
-
-
- /**
- * DOM: Create a new element, associated with this document, with
- * no children, attributes, or parent, by calling createElementEx.
- *
- * @param tagName the tag of the element, used to determine what
- * type element to create as well as what tag to assign the new node.
- * @exception IllegalArgumentException if a mapping is defined,
- * but is invalid because the element can't be instantiated or
- * does not subclass <em>ElementNode</em>.
- */
- public Element createElement(String tagName)
- throws DOMException
- {
- return createElementEx (tagName);
- }
-
- /**
- * <b>DOM2:</b>
- * @since DOM Level 2
- * Warning: Does not work with the deprecated ElementFactory
- */
- public Element createElementNS(String namespaceURI, String qualifiedName)
- throws DOMException
- {
- // Check arguments and throw appropriate exceptions
- ElementNode2.checkArguments(namespaceURI, qualifiedName);
- ElementNode2 retval = new ElementNode2(namespaceURI, qualifiedName);
- retval.setOwnerDocument(this);
- return retval;
- }
-
- /**
- * Create a new element, associated with this document, with no
- * children, attributes, or parent. This uses the element factory,
- * or else directly constructs an ElementNode.
- *
- * @param tagName the tag of the element, used to determine what
- * type element to create as well as what tag to assign the new node.
- * @exception IllegalArgumentException if a mapping is defined,
- * but is invalid because the element can't be instantiated or
- * does not subclass <em>ElementNode</em>.
- * @deprecated Use the standard method createElement instead
- */
- final public ElementEx createElementEx(String tagName)
- throws DOMException
- {
- ElementNode retval;
-
- if (!XmlNames.isName (tagName)) {
- throw new DomEx (DomEx.INVALID_CHARACTER_ERR);
- }
-
- if (factory != null) {
- // Ask factory to create appropriate ElementNode subtype
- retval = (ElementNode) factory.createElementEx(tagName);
- // Set the name of the ElementNode
- retval.setTag(tagName);
- } else {
- retval = new ElementNode(tagName);
- }
- retval.setOwnerDocument(this);
- return retval;
- }
-
- /**
- * Create a new element, associated with this document, with no
- * children, attributes, or parent. This uses the element factory,
- * or else directly constructs an ElementNode.
- *
- * @param uri The namespace used to determine what type of element to
- * create. This is not stored with the element; the element must be
- * inserted into a DOM tree in a location where namespace declarations
- * cause its tag to be interpreted correctly.
- * @param tagName The tag of the element, which should not contain
- * any namespace prefix.
- * @exception IllegalArgumentException When a mapping is defined,
- * but is invalid because the element can't be instantiated or
- * does not subclass <em>ElementNode</em>.
- * @deprecated Use the standard method createElementNS instead
- */
- final public ElementEx createElementEx(String uri, String tagName)
- throws DOMException
- {
- ElementNode retval;
-
- if (!XmlNames.isName(tagName)) {
- throw new DomEx (DomEx.INVALID_CHARACTER_ERR);
- }
-
- if (factory != null) {
- // Ask factory to create appropriate ElementNode subtype
- retval = (ElementNode) factory.createElementEx(uri, tagName);
- // Set the name of the ElementNode
- retval.setTag(tagName);
- } else {
- retval = new ElementNode(tagName);
- }
- retval.setOwnerDocument(this);
- return retval;
- }
-
- /**
- * DOM: returns a Text node initialized with the given text.
- *
- * @param text The contents of the text node being created, which
- * should never contain "<em>]]></em>".
- */
- public Text createTextNode (String text)
- {
- TextNode retval;
-
- retval = new TextNode ();
- retval.setOwnerDocument (this);
- if (text != null)
- retval.setText (text.toCharArray ());
- return retval;
- }
-
- /**
- * DOM: Returns a CDATA section initialized with the given text.
- *
- * @param text the text which the CDATA section will hold, which
- * should never contain "<em>]]></em>".
- */
- public CDATASection createCDATASection (String text)
- {
- CDataNode retval = new CDataNode ();
-
- if (text != null)
- retval.setText (text.toCharArray ());
- retval.setOwnerDocument (this);
- return retval;
- }
-
- // package private ... convenience rtn, reduced mallocation
- TextNode newText (char buf [], int offset, int len)
- throws SAXException
- {
- TextNode retval = (TextNode) createTextNode (null);
- char data [] = new char [len];
-
- System.arraycopy (buf, offset, data, 0, len);
- retval.setText (data);
- return retval;
- }
-
-
- /**
- * DOM: Returns a Processing Instruction node for the specified
- * processing target, with the given instructions.
- *
- * @param target the target of the processing instruction
- * @param instructions the processing instruction, which should
- * never contain "<em>?></em>".
- */
- public ProcessingInstruction createProcessingInstruction (
- String target,
- String instructions
- ) throws DOMException
- {
- if (!XmlNames.isName (target))
- throw new DomEx (DomEx.INVALID_CHARACTER_ERR);
-
- PINode retval = new PINode (target, instructions);
- retval.setOwnerDocument (this);
- return retval;
- }
-
-
- /**
- * DOM: Returns a valueless attribute node with no default value.
- *
- * @param name the name of the attribute.
- */
- public Attr createAttribute(String name) throws DOMException {
- if (!XmlNames.isName(name)) {
- throw new DomEx(DOMException.INVALID_CHARACTER_ERR);
- }
- AttributeNode1 retval = new AttributeNode1(name, "", true, null);
- retval.setOwnerDocument(this);
- return retval;
- }
-
- /**
- * <b>DOM2:</b>
- * @since DOM Level 2
- */
- public Attr createAttributeNS(String namespaceURI, String qualifiedName)
- throws DOMException
- {
- AttributeNode.checkArguments(namespaceURI, qualifiedName);
- AttributeNode retval = new AttributeNode(namespaceURI, qualifiedName,
- "", true, null);
- retval.setOwnerDocument(this);
- return retval;
- }
-
- /**
- * DOM: creates a comment node.
- *
- * @param data The characters which will be in the comment.
- * This should not include the "<em>--</em>" characters.
- */
- public Comment createComment (String data)
- {
- CommentNode retval = new CommentNode (data);
- retval.setOwnerDocument (this);
- return retval;
- }
-
-
- /** DOM: returns null. */
- public Document getOwnerDoc ()
- {
- return null;
- }
-
- /**
- * The <code>DOMImplementation</code> object that handles this document.
- */
- public DOMImplementation getImplementation() {
- return DOMImplementationImpl.getDOMImplementation();
- }
-
- /**
- * DOM: Creates a new document fragment.
- */
- public DocumentFragment createDocumentFragment ()
- {
- DocFragNode retval = new DocFragNode ();
- retval.setOwnerDocument (this);
- return retval;
- }
-
-
- /**
- * DOM: Creates an entity reference to the named entity.
- * Note that the entity must already be defined in the document
- * type, and that the name must be a legal entity name.
- *
- * @param name the name of the the parsed entity
- */
- public EntityReference createEntityReference (String name)
- throws DOMException
- {
- if (!XmlNames.isName (name))
- throw new DomEx (DomEx.INVALID_CHARACTER_ERR);
-
- EntityRefNode retval = new EntityRefNode (name);
- retval.setOwnerDocument (this);
- return retval;
- }
-
-
- /** DOM: Returns the string "#document". */
- final public String getNodeName () { return "#document"; }
-
-
- /**
- * DOM: Returns a copy of this document.
- *
- * <P> <em>Note:</em> At this time, any element factory or document
- * type associated with this document will not be cloned.
- *
- * @param deep if true, child nodes are also cloned.
- */
- public Node cloneNode (boolean deep)
- {
- XmlDocument retval = new XmlDocument ();
-
- retval.systemId = systemId;
- // XXX clone the element factory ...
-
- if (deep) {
- Node node;
-
- for (int i = 0; (node = item (i)) != null; i++) {
- if (node instanceof DocumentType) {
- // XXX recreate
- continue;
- }
- node = node.cloneNode (true);
- retval.changeNodeOwner (node);
- retval.appendChild (node);
- }
- }
-
- return retval;
- }
-
-
- /**
- * Changes the "owner document" of the given node, and all child
- * and associated attribute nodes, to be this document. If the
- * node has a parent, it is first removed from that parent.
- * <b>Obsolete</b> Use importNode method instead. Still useful for
- * internal implementation.
- *
- * @param node
- * @exception DOMException WRONG_DOCUMENT_ERROR when attempting
- * to change the owner for some other DOM implementation<P>
- * HIERARCHY_REQUEST_ERROR when the node is a document, document
- * type, entity, or notation; or when it is an attribute associated
- * with an element whose owner is not being (recursively) changed.
- */
- final public void changeNodeOwner (Node node)
- throws DOMException
- {
- TreeWalker walker;
- NodeBase n;
-
- if (node.getOwnerDocument () == this)
- return;
- if (!(node instanceof NodeBase))
- throw new DomEx (DomEx.WRONG_DOCUMENT_ERR);
-
- switch (node.getNodeType ()) {
- // Documents _are_ owners; can't switch identities
- case Node.DOCUMENT_NODE:
-
- // Entities, Notations only live in doctypes ... we
- // don't support changing their ownership at this time
- case Node.ENTITY_NODE:
- case Node.NOTATION_NODE:
- case Node.DOCUMENT_TYPE_NODE:
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- }
-
- //
- // If node is an attribute, its "scoped" by one element...
- // and if that scope hasn't been changed (i.e. if this isn't
- // a recursive call) we can't really fix anything!
- //
- if (node instanceof AttributeNode) {
- AttributeNode attr = (AttributeNode) node;
- Element scope = attr.getOwnerElement();
-
- if (scope != null && scope.getOwnerDocument () != this)
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- }
-
- // unparent node if needed
- n = (NodeBase) node.getParentNode ();
- if (n != null)
- n.removeChild (node);
-
- // change any children (including self)
- for (walker = new TreeWalker (node),
- n = (NodeBase) walker.getCurrent ();
- n != null;
- n = (NodeBase) walker.getNext ()) {
- n.setOwnerDocument (this);
-
- // Elements have associated attributes, which must
- // also have owners changed.
- if (n instanceof Element) {
- NamedNodeMap list = n.getAttributes ();
- int length = list.getLength ();
- for (int i = 0; i < length; i++)
- changeNodeOwner (list.item (i));
- }
- }
- }
-
- /**
- * Returns the <code>Element</code> whose <code>ID</code> is given by
- * <code>elementId</code>.
- *
- * @since DOM Level 2
- */
- public Element getElementById(String elementId) {
- return getElementExById(elementId);
- }
-
- /**
- * Returns the element whose ID is given by the parameter; or null
- * if no such element exists. This relies on elements to know the
- * name of their ID attribute, as will be currently be true only if
- * the document has been parsed from XML text with a DTD using the
- * <em>XmlDocumentBuilder</em> class, or if it has been constructed
- * using specialized DOM implementation classes which know the name
- * of their ID attribute. (XML allows only one ID attribute per
- * element, and different elements may use different names for their
- * ID attributes.)
- *
- * <P> This may be used to implement internal IDREF linkage, as well
- * as some kinds of <em>XPointer</em> linkage as used in current
- * drafts of <em>XLink</em>.
- *
- * @param id The value of the ID attribute which will be matched
- * by any element which is returned.
- * @deprecated As of DOM level 2, replaced by the method
- * Document.getElementById
- */
- // Note: HTML DOM has getElementById() with "Element" return type
- public ElementEx getElementExById (String id)
- {
- if (id == null)
- throw new IllegalArgumentException (getMessage ("XD-000"));
-
- TreeWalker w = new TreeWalker (this);
- ElementEx element;
-
- while ((element = (ElementEx) w.getNextElement (null)) != null) {
- String idAttr = element.getIdAttributeName ();
- String value;
-
- if (idAttr == null)
- continue;
- value = element.getAttribute (idAttr);
- if (value.equals (id))
- return element;
- }
- return null;
- }
-
- /**
- * @since DOM Level 2
- */
- public Node importNode(Node importedNode, boolean deep)
- throws DOMException
- {
- // First make a copy of the subtree, then change the ownerDocument
- // of the subtree.
-
- Node node = null;
-
- switch (importedNode.getNodeType()) {
- case ATTRIBUTE_NODE:
- node = importedNode.cloneNode(true);
- break;
- case DOCUMENT_FRAGMENT_NODE:
- if (deep) {
- node = importedNode.cloneNode(true);
- } else {
- node = new DocFragNode();
- }
- break;
- case DOCUMENT_NODE:
- case DOCUMENT_TYPE_NODE:
- throw new DomEx(DomEx.NOT_SUPPORTED_ERR);
- case ELEMENT_NODE:
- node = ((ElementNode2) importedNode).createCopyForImportNode(deep);
- break;
- case ENTITY_NODE:
- node = importedNode.cloneNode(deep);
- break;
- case ENTITY_REFERENCE_NODE:
- node = importedNode.cloneNode(false);
- break;
- case NOTATION_NODE:
- case PROCESSING_INSTRUCTION_NODE:
- case TEXT_NODE:
- case CDATA_SECTION_NODE:
- case COMMENT_NODE:
- default:
- node = importedNode.cloneNode(false);
- break;
- }
-
- // Change the ownerDocument of subtree root and any children
- TreeWalker walker;
- NodeBase n;
- for (walker = new TreeWalker (node),
- n = (NodeBase) walker.getCurrent ();
- n != null;
- n = (NodeBase) walker.getNext ()) {
- n.setOwnerDocument (this);
-
- // Elements have associated attributes, which must
- // also have owners changed.
- if (n instanceof Element) {
- NamedNodeMap list = n.getAttributes ();
- int length = list.getLength ();
- for (int i = 0; i < length; i++)
- changeNodeOwner (list.item (i));
- }
- }
-
- return node;
- }
-
-
- //
- // Represent document fragments other than the document itself.
- // (This class is primarily motivated for use with editors.)
- //
- static final class DocFragNode extends ParentNode
- implements DocumentFragment
- {
- // package private -- overrides base class method
- void checkChildType (int type)
- throws DOMException
- {
- switch (type) {
- case ELEMENT_NODE:
- case PROCESSING_INSTRUCTION_NODE:
- case COMMENT_NODE:
- case TEXT_NODE:
- case CDATA_SECTION_NODE:
- case ENTITY_REFERENCE_NODE:
- return;
- default:
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- }
- }
-
- public void writeXml (XmlWriteContext context) throws IOException
- {
- this.writeChildrenXml (context);
- }
-
- public Node getParentNode ()
- { return null; }
-
- public void setParentNode (Node p)
- { if (p != null) throw new IllegalArgumentException (); }
-
- public short getNodeType ()
- { return DOCUMENT_FRAGMENT_NODE; }
-
- public String getNodeName () {
- return ("#document-fragment");
- }
-
- public Node cloneNode (boolean deep)
- {
- DocFragNode retval = new DocFragNode ();
- ((NodeBase)retval).setOwnerDocument
- ((XmlDocument)this.getOwnerDocument ());
-
- if (deep) {
- Node node;
-
- for (int i = 0; (node = item (i)) != null; i++) {
- node = node.cloneNode (true);
- retval.appendChild (node);
- }
- }
- return retval;
- }
- }
-
-
- //
- // Represent entity references.
- //
- final static class EntityRefNode extends ParentNode
- implements EntityReference
- {
- private String entity;
-
- EntityRefNode (String name)
- {
- if (name == null)
- throw new IllegalArgumentException (getMessage ("XD-002"));
- entity = name;
- }
-
- // package private -- overrides base class method
- void checkChildType (int type)
- throws DOMException
- {
- switch (type) {
- case ELEMENT_NODE:
- case PROCESSING_INSTRUCTION_NODE:
- case COMMENT_NODE:
- case TEXT_NODE:
- case CDATA_SECTION_NODE:
- case ENTITY_REFERENCE_NODE:
- return;
- default:
- throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
- }
- }
- public void writeXml (XmlWriteContext context)
- throws IOException
- {
- if (!context.isEntityDeclared (entity))
- throw new IOException (getMessage ("XD-003", new Object[]
- { entity }));
-
- Writer out = context.getWriter ();
-
- out.write ('&');
- out.write (entity);
- out.write (';');
- }
-
- public short getNodeType ()
- { return ENTITY_REFERENCE_NODE; }
-
- public String getNodeName ()
- { return entity; }
-
- public Node cloneNode (boolean deep) {
- EntityRefNode retval = new EntityRefNode (entity);
- ((NodeBase)retval).setOwnerDocument((
- XmlDocument)this.getOwnerDocument ());
- if (deep) {
- Node node;
-
- for (int i = 0; (node = item (i)) != null; i++) {
- node = node.cloneNode (true);
- retval.appendChild (node);
- }
- // XXX
- //throw new RuntimeException (getMessage ("XD-001"));
- }
- return retval;
- }
- }
-
- class ExtWriteContext extends XmlWriteContext
- {
- ExtWriteContext (Writer out) { super (out); }
- ExtWriteContext (Writer out, int level) { super (out, level); }
-
- public boolean isEntityDeclared (String name)
- {
- if (super.isEntityDeclared (name))
- return true;
-
- DocumentType doctype = getDoctype ();
-
- if (doctype == null)
- return false;
- else
- return doctype.getEntities ().getNamedItem (name) != null;
- }
- }
-
- static class Catalog extends MessageCatalog
- {
- Catalog () { super (Catalog.class); }
- }
- }