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 + -
显示快捷键?