Package org.apache.crimson.tree

Source Code of org.apache.crimson.tree.ElementNode2

/*
* $Id: ElementNode2.java,v 1.11 2001/04/11 02:52:37 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.CharArrayWriter;
import java.io.IOException;
import java.io.Writer;

import java.util.Enumeration;

import org.apache.crimson.util.XmlNames;

import org.w3c.dom.*;


/**
* Modified version of ElementNode to support DOM Level 2 methods.  This
* class is named ElementNode2 for backward compatibility since old DOM
* Level 1 apps may have subclassed ElementNode.
*
* This class represents XML elements in a parse tree, and is often
* subclassed to add custom behaviors.  When an XML Document object
* is built using an <em>XmlDocumentBuilder</em> instance, simple
* declarative configuration information may be used to control whether
* this class, or some specialized subclass (e.g. supporting HTML DOM
* methods) is used for elements in the resulting tree.
*
* <P> As well as defining new methods to provide behaviors which are
* specific to application frameworks, such as Servlets or Swing, such
* subclasses may also override methods such as <em>doneParse</em>
* and <em>appendChild</em> to perform some kinds of processing during
* tree construction.  Such processing can include transforming tree
* structure to better suit the needs of a given application.  When
* such transformation is done, the <em>XmlWritable</em> methods
* may need to be overridden to make elements transform themselves back
* to XML without losing information.  (One common transformation is
* eliminating redundant representations of data; attributes of an XML
* element may correspond to defaultable object properties, and so on.)
*
* <P> Element nodes also support a single <em>userObject</em> property,
* which may be used to bind objects to elements where subclassing is
* either not possible or is inappropriate.  For example, user interface
* objects often derive from <code>java.awt.Component</code>, so that
* they can't extend a different class (<em>ElementNode</em>).
*
* @see XmlDocumentBuilder
*
* @author David Brownell
* @author Edwin Goei
*/
public class ElementNode2 extends NamespacedNode implements ElementEx
{
    protected AttributeSet  attributes;
    private String    idAttributeName;
    private Object    userObject;

    private static final char  tagStart [] = { '<', '/' };
    private static final char  tagEnd [] = { ' ', '/', '>' };
   
    public ElementNode2(String namespaceURI, String qName)
        throws DomEx
    {
        super(namespaceURI, qName);
    }

    /**
     * Make a clone of this node and return it.  Used for cloneNode().
     */
    ElementNode2 makeClone() {
        ElementNode2 retval = new ElementNode2(namespaceURI, qName);
        if (attributes != null) {
            retval.attributes = new AttributeSet(attributes, true);
            retval.attributes.setOwnerElement(retval);
        }
        retval.idAttributeName = idAttributeName;
        retval.userObject = userObject;
        retval.ownerDocument = ownerDocument;
        return retval;
    }

    /**
     * @return New ElementNode2 which is a copy of "this" but without
     * attributes that are defaulted in the original document.
     *
     * Used to implement Document.importNode().
     */
    ElementNode2 createCopyForImportNode(boolean deep) {
        ElementNode2 retval = new ElementNode2(namespaceURI, qName);
        if (attributes != null) {
            // Copy only "specified" Attr-s
            retval.attributes = new AttributeSet(attributes);
            retval.attributes.setOwnerElement(retval);
        }
        retval.userObject = userObject;

        if (deep) {
            // Copy ownerDocument to prevent appendChild() from throwing
            // WRONG_DOCUMENT_ERR for deep copies.  This gets changed to
            // the correct ownerDocument later in Document.importNode().
            retval.ownerDocument = ownerDocument;

            for (int i = 0; true; i++) {
                Node node = item(i);
                if (node == null) {
                    break;
                }
                if (node instanceof ElementNode2) {
                    retval.appendChild(
                        ((ElementNode2) node).createCopyForImportNode(true));
                } else {
                    retval.appendChild(node.cloneNode(true));
                }
            }
        }
        return retval;
    }

    static void checkArguments(String namespaceURI, String qualifiedName)
        throws DomEx
    {
        // [6] QName ::= (Prefix ':')? LocalPart
        // [7] Prefix ::= NCName
        // [8] LocalPart ::= NCName

  if (qualifiedName == null) {
            throw new DomEx(DomEx.NAMESPACE_ERR);
        }

  int first = qualifiedName.indexOf(':');

        if (first <= 0) {
            // no Prefix, only check LocalPart
            if (!XmlNames.isUnqualifiedName(qualifiedName)) {
                throw new DomEx(DomEx.INVALID_CHARACTER_ERR);
            }
            return;
        }

        // Prefix exists, check everything

  int last = qualifiedName.lastIndexOf(':');
  if (last != first) {
            throw new DomEx(DomEx.NAMESPACE_ERR);
        }
 
        String prefix = qualifiedName.substring(0, first);
        String localName = qualifiedName.substring(first + 1);
  if (!XmlNames.isUnqualifiedName(prefix)
                || !XmlNames.isUnqualifiedName(localName)) {
            throw new DomEx(DomEx.INVALID_CHARACTER_ERR);
        }

        // If we get here then we must have a valid prefix
        if (namespaceURI == null
            || (prefix.equals("xml") &&
                !XmlNames.SPEC_XML_URI.equals(namespaceURI))) {
            throw new DomEx(DomEx.NAMESPACE_ERR);
        }
    }

    public void trimToSize ()
    {
  super.trimToSize ();
  if (attributes != null)
      attributes.trimToSize ();
    }

    // Assigns the element's attributes.
    void setAttributes (AttributeSet a)
    {
  AttributeSet oldAtts = attributes;

  // Check if the current AttributeSet or any attribute is readonly
  // isReadonly checks if any of the attributes in the AttributeSet
  // is readonly..
  if (oldAtts != null && oldAtts.isReadonly()) {
      throw new DomEx(DomEx.NO_MODIFICATION_ALLOWED_ERR);
        }

  if (a != null) {
      a.setOwnerElement(this);
        }
  attributes = a;
  if (oldAtts != null) {
      oldAtts.setOwnerElement(null);
        }
    }

    // package private -- overrides base class method
    void checkChildType (int type)
    throws DOMException
    {
  switch (type) {
    case ELEMENT_NODE:
    case TEXT_NODE:
    case COMMENT_NODE:
    case PROCESSING_INSTRUCTION_NODE:
    case CDATA_SECTION_NODE:
    case ENTITY_REFERENCE_NODE:
      return;
    default:
      throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
  }
    }

    // package private -- overrides base class method
    public void setReadonly (boolean deep)
    {
  if (attributes != null)
      attributes.setReadonly ();
  super.setReadonly (deep);
    }

    /** <b>DOM:</b> Returns the attributes of this element. */
    public NamedNodeMap getAttributes ()
    {
  if (attributes == null)
      attributes = new AttributeSet (this);
        return attributes;
    }
       
    /**
     * Returns whether this node (if it is an element) has any attributes.
     * @since DOM Level 2
     */
    public boolean hasAttributes() {
        return attributes != null;
    }

    /**
     * Returns the element and its content as a string, which includes
     * all the markup embedded in this element.  If the element is not
     * fully constructed, the content will not be an XML tag.
     */
    public String toString ()
    {
  try {
      CharArrayWriter  out = new CharArrayWriter ();
      XmlWriteContext  x = new XmlWriteContext (out);
      writeXml (x);
      return out.toString ();
  } catch (Exception e) {
      return super.toString ();
  }
    }
   
   
    /**
     * Writes this element and all of its children out, as well
     * formed XML.
     */
    public void writeXml (XmlWriteContext context) throws IOException
    {
  Writer  out = context.getWriter ();

  if (qName == null)
     throw new IllegalStateException ( getMessage ("EN-002"));
    
  out.write (tagStart, 0, 1)// "<"
  out.write (qName);
 
        if (attributes != null)
      attributes.writeXml (context);

  //
  // Write empty nodes as "<EMPTY />" to make sure version 3
  // and 4 web browsers can read empty tag output as HTML.
  // XML allows "<EMPTY/>" too, of course.
  //
  if (!hasChildNodes ())
      out.write (tagEnd, 0, 3)// " />"
  else  {
      out.write (tagEnd, 2, 1)// ">"
      writeChildrenXml (context);
      out.write (tagStart, 0, 2)// "</"
      out.write (qName);
      out.write (tagEnd, 2, 1)// ">"
  }
    }

    /**
     * Assigns the name of the element's ID attribute; only one attribute
     * may have the ID type.  XML supports a kind of validatable internal
     * linking using ID attributes, with IDREF attributes identifying
     * specific nodes (and IDREFS attributes identifying sets of them).
     */
    public void setIdAttributeName (String attName)
    {
  if (readonly)
      throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
  idAttributeName = attName;
    }

    /**
     * Returns the name of the element's ID attribute, if one is known.
     */
    public String getIdAttributeName ()
  { return idAttributeName; }

   
    public void setUserObject (Object userObject)
  { this.userObject = userObject; }

    public Object getUserObject ()
  { return userObject; }

    // DOM support

    /** <b>DOM:</b> Returns the ELEMENT_NODE node type. */
    public short getNodeType ()  { return ELEMENT_NODE; }

    /** <b>DOM:</b> Returns the name of the XML tag for this element. */
    public String getTagName () { return qName; }
   
    /**
     * Returns <code>true</code> when an attribute with a given name is
     * specified on this element or has a default value, <code>false</code>
     * otherwise.
     * @since DOM Level 2
     */
    public boolean hasAttribute(String name) {
        return getAttributeNode(name) != null;
    }

    /**
     * Returns <code>true</code> when an attribute with a given local name
     * and namespace URI is specified on this element or has a default
     * value, <code>false</code> otherwise.
     * @since DOM Level 2
     */
    public boolean hasAttributeNS(String namespaceURI, String localName) {
        return getAttributeNodeNS(namespaceURI, localName) != null;
    }

    /** <b>DOM:</b> Returns the value of the named attribute, or an empty
     * string
     */
    public String getAttribute (String name)
    {
  return (attributes == null)
      ? ""
      : attributes.getValue (name);
    }

    /**
     * Retrieves an attribute value by local name and namespace URI.
     * @since DOM Level 2
     */
    public String getAttributeNS(String namespaceURI, String localName) {
  if (attributes == null) {
      return "";
        }
  Attr attr = getAttributeNodeNS(namespaceURI, localName);
  if (attr == null) {
      return "";
        }
  return attr.getValue();
    }

    /**
     * Retrieves an <code>Attr</code> node by local name and namespace URI.
     * @since DOM Level 2
     */
    public Attr getAttributeNodeNS(String namespaceURI, String localName) {
  if (localName == null) {
      return null;
        }
  if (attributes == null) {
            return null;
        }
        for (int i = 0; ; i++) {
            AttributeNode attr = (AttributeNode) attributes.item(i);
            if (attr == null) {
                return null;
            }
            if (localName.equals(attr.getLocalName())
                && (attr.getNamespaceURI() == namespaceURI
                    || attr.getNamespaceURI().equals(namespaceURI))) {
                return attr;
            }
        }
    }
   
    /**
     * <b>DOM:</b> Assigns or modifies the value of the specified attribute.
     */
    public void setAttribute (String name, String value)
    throws DOMException
    {
  NodeBase att;                   // Common superclass of all Attr nodes

  if (readonly)
      throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
        if (!XmlNames.isName(name)) {
            throw new DomEx(DOMException.INVALID_CHARACTER_ERR);
        }
  if (attributes == null)
      attributes = new AttributeSet (this);
  if ((att = (NodeBase) attributes.getNamedItem (name)) != null)
      att.setNodeValue (value);
  else {
      att = new AttributeNode1(name, value, true, null);
      att.setOwnerDocument ((XmlDocument) getOwnerDocument ());
            /* "ownerElement" should be null before calling "setNamedItem" */
      attributes.setNamedItem (att);
  }
    }
   
    /**
     * <b>DOM2:</b>
     * @since DOM Level 2
     */
    public void setAttributeNS(String namespaceURI, String qualifiedName,
                               String value)
        throws DOMException
    {
        AttributeNode.checkArguments(namespaceURI, qualifiedName);

        Attr attr = getAttributeNodeNS(namespaceURI,
                XmlNames.getLocalPart(qualifiedName));
        if (attr == null) {
            AttributeNode newAttr = new AttributeNode(namespaceURI,
                                                      qualifiedName, value,
                                                      true, null);
      newAttr.setOwnerDocument((XmlDocument)getOwnerDocument());
            setAttributeNodeNS(newAttr);
        } else {
            attr.setValue(value);
            attr.setPrefix(XmlNames.getPrefix(qualifiedName));
        }
    }

    /**
     * <b>DOM2:</b>
     * @since DOM Level 2
     */
    public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
  if (readonly) {
      throw new DomEx(DomEx.NO_MODIFICATION_ALLOWED_ERR);
        }
        if (newAttr.getOwnerDocument() != getOwnerDocument()) {
      throw new DomEx(DomEx.WRONG_DOCUMENT_ERR);
        }

  if (attributes == null) {
      attributes = new AttributeSet(this);
        }

        // Note: ownerElement of newAttr is both checked and set in the
        // following call to AttributeSet.setNamedItemNS(Node)
  return (Attr)attributes.setNamedItemNS(newAttr);
    }

    /** <b>DOM:</b> Remove the named attribute. */
    public void removeAttribute (String name)
    throws DOMException
    {
  if (readonly)
      throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
  if (attributes == null) {
            return;
        }
        try {
            attributes.removeNamedItem (name);
        } catch (DOMException x) {
            // DOM2 does not allow a NOT_FOUND_ERR exception to be thrown
            if (x.code != DOMException.NOT_FOUND_ERR) {
                throw x;
            }
        }
    }

    /**
     * <b>DOM2:</b>
     * @since DOM Level 2
     */
    public void removeAttributeNS(String namespaceURI, String localName)
        throws DOMException
    {
  if (readonly) {
      throw new DomEx(DomEx.NO_MODIFICATION_ALLOWED_ERR);
        }
        try {
            attributes.removeNamedItemNS(namespaceURI, localName);
        } catch (DOMException x) {
            // DOM2 does not allow a NOT_FOUND_ERR exception to be thrown
            if (x.code != DOMException.NOT_FOUND_ERR) {
                throw x;
            }
        }
    }

    /** <b>DOM:</b>  returns the attribute */
    public Attr getAttributeNode (String name)
    {
  if (attributes != null)
      return (Attr) attributes.getNamedItem (name);
  else
      return null;
    }
   
    /** <b>DOM:</b> assigns the attribute */
    public Attr setAttributeNode (Attr newAttr)
    throws DOMException
    {
  if (readonly)
      throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
  if (!(newAttr instanceof AttributeNode))
      throw new DomEx (DomEx.WRONG_DOCUMENT_ERR);

  if (attributes == null)
      attributes = new AttributeSet (this);

        // Note: ownerElement of newAttr is both checked and set in the
        // following call to AttributeSet.setNamedItem(Node)
  return (Attr) attributes.setNamedItem(newAttr);
    }
   
    /** <b>DOM:</b> removes the attribute with the same name as this one */
    public Attr removeAttributeNode (Attr oldAttr)
    throws DOMException
    {
  if (isReadonly ())
      throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);

  Attr  attr = getAttributeNode (oldAttr.getNodeName ());
  if (attr == null)
      throw new DomEx (DomEx.NOT_FOUND_ERR);
  removeAttribute (attr.getNodeName ());
  return attr;
    }

    /**
     * Creates a new unparented node whose attributes are the same as
     * this node's attributes; if <em>deep</em> is true, the children
     * of this node are cloned as children of the new node.
     */
    public Node cloneNode (boolean deep)
    {
  try {
      ElementNode2 retval = makeClone();
      if (deep) {
    for (int i = 0; true; i++) {
        Node  node = item (i);
        if (node == null)
      break;
        retval.appendChild (node.cloneNode (true));
    }
      }
      return retval;
  } catch (DOMException e) {
      throw new RuntimeException (getMessage ("EN-001"));
  }
    }

    /**
     * Convenience method to construct a non-prettyprinting XML write
     * context and call writeXml with it.  Subclasses may choose to
     * to override this method to generate non-XML text,
     *
     * @param out where to emit the XML content of this node
     */
    public void write (Writer out) throws IOException
    {
  writeXml (new XmlWriteContext (out));
    }
}
TOP

Related Classes of org.apache.crimson.tree.ElementNode2

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.