attrimpl.java

来自「JAVA 所有包」· Java 代码 · 共 1,236 行 · 第 1/3 页

JAVA
1,236
字号
/* * Copyright 1999-2004 The Apache Software Foundation. *  * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *  *      http://www.apache.org/licenses/LICENSE-2.0 *  * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.sun.org.apache.xerces.internal.dom;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import org.w3c.dom.TypeInfo;import org.w3c.dom.Attr;import org.w3c.dom.DOMException;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.Text;/** * Attribute represents an XML-style attribute of an * Element. Typically, the allowable values are controlled by its * declaration in the Document Type Definition (DTD) governing this * kind of document. * <P> * If the attribute has not been explicitly assigned a value, but has * been declared in the DTD, it will exist and have that default. Only * if neither the document nor the DTD specifies a value will the * Attribute really be considered absent and have no value; in that * case, querying the attribute will return null. * <P> * Attributes may have multiple children that contain their data. (XML * allows attributes to contain entity references, and tokenized * attribute types such as NMTOKENS may have a child for each token.) * For convenience, the Attribute object's getValue() method returns * the string version of the attribute's value. * <P> * Attributes are not children of the Elements they belong to, in the * usual sense, and have no valid Parent reference. However, the spec * says they _do_ belong to a specific Element, and an INUSE exception * is to be thrown if the user attempts to explicitly share them * between elements. * <P> * Note that Elements do not permit attributes to appear to be shared * (see the INUSE exception), so this object's mutability is * officially not an issue. * <p> * Note: The ownerNode attribute is used to store the Element the Attr * node is associated with. Attr nodes do not have parent nodes. * Besides, the getOwnerElement() method can be used to get the element node * this attribute is associated with. * <P> * AttrImpl does not support Namespaces. AttrNSImpl, which inherits from * it, does. * * <p>AttrImpl used to inherit from ParentNode. It now directly inherits from * NodeImpl and provide its own implementation of the ParentNode's behavior. * The reason is that we now try and avoid to always create a Text node to * hold the value of an attribute. The DOM spec requires it, so we still have * to do it in case getFirstChild() is called for instance. The reason * attribute values are stored as a list of nodes is so that they can carry * more than a simple string. They can also contain EntityReference nodes. * However, most of the times people only have a single string that they only * set and get through Element.set/getAttribute or Attr.set/getValue. In this * new version, the Attr node has a value pointer which can either be the * String directly or a pointer to the first ChildNode. A flag tells which one * it currently is. Note that while we try to stick with the direct String as * much as possible once we've switched to a node there is no going back. This * is because we have no way to know whether the application keeps referring to * the node we once returned. * <p> The gain in memory varies on the density of attributes in the document. * But in the tests I've run I've seen up to 12% of memory gain. And the good * thing is that it also leads to a slight gain in speed because we allocate * fewer objects! I mean, that's until we have to actually create the node... * <p> * To avoid too much duplicated code, I got rid of ParentNode and renamed * ChildAndParentNode, which I never really liked, to ParentNode for * simplicity, this doesn't make much of a difference in memory usage because * there are only very few objects that are only a Parent. This is only true * now because AttrImpl now inherits directly from NodeImpl and has its own * implementation of the ParentNode's node behavior. So there is still some * duplicated code there. * <p> * This class doesn't directly support mutation events, however, it notifies * the document when mutations are performed so that the document class do so. * * <p><b>WARNING</b>: Some of the code here is partially duplicated in * ParentNode, be careful to keep these two classes in sync! * * @xerces.internal * * @see AttrNSImpl  * * @author Arnaud  Le Hors, IBM * @author Joe Kesselman, IBM * @author Andy Clark, IBM  * @version $Id: AttrImpl.java,v 1.2.6.1 2005/08/30 11:26:26 sunithareddy Exp $ * @since PR-DOM-Level-1-19980818. * */public class AttrImpl    extends NodeImpl    implements Attr, TypeInfo{    //    // Constants    //    /** Serialization version. */    static final long serialVersionUID = 7277707688218972102L;        /** DTD namespace. **/    static final String DTD_URI = "http://www.w3.org/TR/REC-xml";    //    // Data    //    /** This can either be a String or the first child node. */    protected Object value = null;    /** Attribute name. */    protected String name;        /** Type information */    // REVISIT: we are losing the type information in DOM during serialization    transient Object type;    protected static TextImpl textNode = null;    //    // Constructors    //    /**     * Attribute has no public constructor. Please use the factory     * method in the Document class.     */    protected AttrImpl(CoreDocumentImpl ownerDocument, String name) {    	super(ownerDocument);        this.name = name;        /** False for default attributes. */        isSpecified(true);        hasStringValue(true);    }    // for AttrNSImpl    protected AttrImpl() {}    // Support for DOM Level 3 renameNode method.    // Note: This only deals with part of the pb. It is expected to be    // called after the Attr has been detached for one thing.    // CoreDocumentImpl does all the work.    void rename(String name) {        if (needsSyncData()) {            synchronizeData();        }        this.name = name;    }    // create a real text node as child if we don't have one yet    protected void makeChildNode() {        if (hasStringValue()) {            if (value != null) {                TextImpl text =                    (TextImpl) ownerDocument().createTextNode((String) value);                value = text;                text.isFirstChild(true);                text.previousSibling = text;                text.ownerNode = this;                text.isOwned(true);            }            hasStringValue(false);        }    }    /**     * NON-DOM     * set the ownerDocument of this node and its children     */    void setOwnerDocument(CoreDocumentImpl doc) {        if (needsSyncChildren()) {            synchronizeChildren();        }        super.setOwnerDocument(doc);        if (!hasStringValue()) {            for (ChildNode child = (ChildNode) value;                 child != null; child = child.nextSibling) {                child.setOwnerDocument(doc);            }        }    }    /**     * NON-DOM: set the type of this attribute to be ID type.     *      * @param id     */    public void setIdAttribute(boolean id){        if (needsSyncData()) {            synchronizeData();        }        isIdAttribute(id);    }    /** DOM Level 3: isId*/    public boolean isId(){        // REVISIT: should an attribute that is not in the tree return        // isID true?        return isIdAttribute();    }    //    // Node methods    //        public Node cloneNode(boolean deep) {        if (needsSyncChildren()) {            synchronizeChildren();        }        AttrImpl clone = (AttrImpl) super.cloneNode(deep);        // take care of case where there are kids    	if (!clone.hasStringValue()) {            // Need to break the association w/ original kids            clone.value = null;            // Cloning an Attribute always clones its children,             // since they represent its value, no matter whether this             // is a deep clone or not            for (Node child = (Node) value; child != null;                 child = child.getNextSibling()) {                 clone.appendChild(child.cloneNode(true));            }        }        clone.isSpecified(true);        return clone;    }    /**     * A short integer indicating what type of node this is. The named     * constants for this value are defined in the org.w3c.dom.Node interface.     */    public short getNodeType() {        return Node.ATTRIBUTE_NODE;    }    /**     * Returns the attribute name     */    public String getNodeName() {        if (needsSyncData()) {            synchronizeData();        }        return name;    }    /**     * Implicit in the rerouting of getNodeValue to getValue is the     * need to redefine setNodeValue, for symmetry's sake.  Note that     * since we're explicitly providing a value, Specified should be set     * true.... even if that value equals the default.     */    public void setNodeValue(String value) throws DOMException {    	setValue(value);    }        /**     * @see org.w3c.dom.TypeInfo#getTypeName()     */    public String getTypeName() {        return (String)type;    }    /**     * @see org.w3c.dom.TypeInfo#getTypeNamespace()     */    public String getTypeNamespace() {        if (type != null) {            return DTD_URI;        }        return null;    }        /**     * Method getSchemaTypeInfo.     * @return TypeInfo     */    public TypeInfo getSchemaTypeInfo(){      return this;    }    /**     * In Attribute objects, NodeValue is considered a synonym for     * Value.     *     * @see #getValue()     */    public String getNodeValue() {    	return getValue();    }    //    // Attr methods    //    /**     * In Attributes, NodeName is considered a synonym for the     * attribute's Name     */    public String getName() {        if (needsSyncData()) {            synchronizeData();        }    	return name;    } // getName():String    /**     * The DOM doesn't clearly define what setValue(null) means. I've taken it     * as "remove all children", which from outside should appear     * similar to setting it to the empty string.     */    public void setValue(String newvalue) {        CoreDocumentImpl ownerDocument = ownerDocument();                if (ownerDocument.errorChecking && isReadOnly()) {            String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);            throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);        }                Element ownerElement = getOwnerElement();        String oldvalue = "";        if (needsSyncData()) {            synchronizeData();        }        if (needsSyncChildren()) {            synchronizeChildren();        }        if (value != null) {            if (ownerDocument.getMutationEvents()) {                // Can no longer just discard the kids; they may have                // event listeners waiting for them to disconnect.                if (hasStringValue()) {                    oldvalue = (String) value;                    // create an actual text node as our child so                    // that we can use it in the event                    if (textNode == null) {                        textNode = (TextImpl)                            ownerDocument.createTextNode((String) value);                    }                    else {                        textNode.data = (String) value;                    }                    value = textNode;                    textNode.isFirstChild(true);                    textNode.previousSibling = textNode;                    textNode.ownerNode = this;                    textNode.isOwned(true);                    hasStringValue(false);                    internalRemoveChild(textNode, true);                }                else {                    oldvalue = getValue();                    while (value != null) {                        internalRemoveChild((Node) value, true);                    }                }            }            else {                if (hasStringValue()) {                    oldvalue = (String) value;                }                else {                    // simply discard children if any                    oldvalue = getValue();                    // remove ref from first child to last child                    ChildNode firstChild = (ChildNode) value;                    firstChild.previousSibling = null;                    firstChild.isFirstChild(false);                    firstChild.ownerNode = ownerDocument;                }                // then remove ref to current value                value = null;                needsSyncChildren(false);            }            if (isIdAttribute() && ownerElement != null) {                ownerDocument.removeIdentifier(oldvalue);            }        }        // Create and add the new one, generating only non-aggregate events        // (There are no listeners on the new Text, but there may be        // capture/bubble listeners on the Attr.        // Note that aggregate events are NOT dispatched here,        // since we need to combine the remove and insert.    	isSpecified(true);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?