Package com.sun.xml.tree

Source Code of com.sun.xml.tree.XmlDocument$DocFragNode

/*
* $Id: XmlDocument.java,v 1.7 1999/05/20 21:58:29 mode Exp $
*
* Copyright (c) 1998-1999 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information").  You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*/

package com.sun.xml.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 com.sun.xml.parser.Parser;
import com.sun.xml.parser.Resolver;
import com.sun.xml.parser.ValidatingParser;

import com.sun.xml.util.MessageCatalog;
import com.sun.xml.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> 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>&lt;PurchaseOrder&gt;</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
* @version $Revision: 1.7 $
*/
public class XmlDocument extends ParentNode
    implements DocumentEx, DOMImplementation
{
    // 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 ()
    {
    }

    /**
     * Construct an XML document from the data at the specified URI,
     * optionally validating.  This uses Sun's validating parser if
     * validation is requested, otherwise uses Sun's 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
     */
    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 Sun's 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
     */
    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 Sun's validating parser
     * if validation is requested, otherwise uses Sun's 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
     */
    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 Sun's validating parser
     * if validation is requested, otherwise uses Sun's 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
     */
    public static XmlDocument createXmlDocument (
  InputSource in,
  boolean doValidate
    ) throws IOException, SAXException
    {
  Parser      parser;
  XmlDocumentBuilder  builder;

  try {
      if (doValidate)
    parser = new ValidatingParser (true);
      else
    parser = new Parser ();
      parser.setEntityResolver (new Resolver ());
      builder = new XmlDocumentBuilder ();
      builder.setDisableNamespaces (true);

  } catch (Exception e) {
      throw new SAXException (e);
  }

  builder.setParser (parser);
  parser.parse (in);
  return builder.getDocument ();
    }



    /*
     * Returns the top level document element.
     * This is a convenience function in the big picture;
     * use the DOM version instead, at least for now.
     */
    // package private
    ElementNode getDocument ()
    {
  // 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 ElementNode)
    return (ElementNode) n;
  }
    }

    /**
     * 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 com.sun.xml.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 && getDocument () != 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 &&
      getDocument () != 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;
  }
    }

    // package private!!
    Doctype createDoctype (String name)
    {
  Doctype  retval = new Doctype (name);
  retval.setOwnerDocument (this);
  return retval;
    }

    /**
     * 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 ()
  { return getDocument (); }

    /**
     * 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>.
     */
    final public void setElementFactory (ElementFactory factory)
    {
  this.factory = factory;
    }

    /**
     * Returns the element factory to be used by this document.
     */
    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>.
     */
    final public Element createElement (String tagName)
    throws DOMException
    {
  return createElementEx (tagName);
    }

    /**
     * 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>.
     */
    final public ElementEx createElementEx (String tagName)
    throws DOMException
    {
        ElementNode      retval;
 
  if (!XmlNames.isName (tagName))
      throw new DomEx (DomEx.INVALID_CHARACTER_ERR);

  if (factory != null)
      retval = (ElementNode) factory.createElementEx (tagName);
  else
      retval = new ElementNode ();
        retval.setTag (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>.
     */
    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)
      retval = (ElementNode) factory.createElementEx (uri, tagName);
  else
      retval = new ElementNode ();
        retval.setTag (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>]]&gt;</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>]]&gt;</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>?&gt;</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 (DomEx.INVALID_CHARACTER_ERR);

  AttributeNode retval = new AttributeNode (name, null, 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;
    }

    /**
     * DOM: Returns an object describing the features of the DOM implementation
     * used by this document:  it supports the XML 1.0 feature set.
     */
    public DOMImplementation getImplementation ()
  { return this; }

    /**
     * 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.
     *
     * @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;
      ElementNode    scope = attr.getNameScope ();

      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 ElementNode) {
    NamedNodeMap  list = n.getAttributes ();
    int    length = list.getLength ();
    for (int i = 0; i < length; i++)
        changeNodeOwner (list.item (i));
      }
  }
    }

    /**
     * DOM:  Reports that this document supports
     * XML version 1.0 (only).
     *
     * @param feature identifies a feature of this DOM implementation;
     *  case is ignored
     * @param version optionally identifies the version of the feature
     */
    public boolean hasFeature (String feature, String version)
    {
  if (!"XML".equalsIgnoreCase (feature))
      return false;
  if (version != null || !"1.0".equals (version))
      return false;
  return true;
    }


    /**
     * 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.
     */
    // 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;
    }


    //
    // 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) {
// XXX
    throw new RuntimeException (getMessage ("XD-001"));
      }
      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) {
// 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); }
    }
}
TOP

Related Classes of com.sun.xml.tree.XmlDocument$DocFragNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.