Frames | No Frames |
1: /* DomAttr.java -- 2: Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package gnu.xml.dom; 39: 40: import org.w3c.dom.Attr; 41: import org.w3c.dom.DOMException; 42: import org.w3c.dom.Element; 43: import org.w3c.dom.Node; 44: import org.w3c.dom.TypeInfo; 45: import org.w3c.dom.events.MutationEvent; 46: 47: 48: /** 49: * <p> "Attr" implementation. In DOM, attributes cost quite a lot of 50: * memory because their values are complex structures rather than just 51: * simple strings. To reduce your costs, avoid having more than one 52: * child of an attribute; stick to a single Text node child, and ignore 53: * even that by using the attribute's "nodeValue" property.</p> 54: * 55: * <p> As a bit of general advice, only look at attribute modification 56: * events through the DOMAttrModified event (sent to the associated 57: * element). Implementations are not guaranteed to report other events 58: * in the same order, so you're very likely to write nonportable code if 59: * you monitor events at the "children of Attr" level.</p> 60: * 61: * <p> At this writing, not all attribute modifications will cause the 62: * DOMAttrModified event to be triggered ... only the ones using the string 63: * methods (setNodeValue, setValue, and Element.setAttribute) to modify 64: * those values. That is, if you manipulate those children directly, 65: * elements won't get notified that attribute values have changed. 66: * The natural fix for that will report other modifications, but won't 67: * be able to expose "previous" attribute value; it'll need to be cached 68: * or something (at which point why bother using child nodes). </p> 69: * 70: * <p><em>You are strongly advised not to use "children" of any attribute 71: * nodes you work with.</em> </p> 72: * 73: * @author David Brownell 74: * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 75: */ 76: public class DomAttr 77: extends DomNsNode 78: implements Attr 79: { 80: 81: private boolean specified; 82: private String value; // string value cache 83: 84: /** 85: * Constructs an Attr node associated with the specified document. 86: * The "specified" flag is initialized to true, since this DOM has 87: * no current "back door" mechanisms to manage default values so 88: * that every value must effectively be "specified". 89: * 90: * <p>This constructor should only be invoked by a Document as part of 91: * its createAttribute functionality, or through a subclass which is 92: * similarly used in a "Sub-DOM" style layer. 93: * 94: * @param owner The document with which this node is associated 95: * @param namespaceURI Combined with the local part of the name, 96: * this is used to uniquely identify a type of attribute 97: * @param name Name of this attribute, which may include a prefix 98: */ 99: protected DomAttr(DomDocument owner, String namespaceURI, String name) 100: { 101: super(ATTRIBUTE_NODE, owner, namespaceURI, name); 102: specified = true; 103: length = 1; 104: 105: // XXX register self to get insertion/removal events 106: // and character data change events and when they happen, 107: // report self-mutation 108: } 109: 110: /** 111: * <b>DOM L1</b> 112: * Returns the attribute name (same as getNodeName) 113: */ 114: public final String getName() 115: { 116: return getNodeName(); 117: } 118: 119: /** 120: * <b>DOM L1</b> 121: * Returns true if a parser reported this was in the source text. 122: */ 123: public final boolean getSpecified() 124: { 125: return specified; 126: } 127: 128: /** 129: * Records whether this attribute was in the source text. 130: */ 131: public final void setSpecified(boolean value) 132: { 133: specified = value; 134: } 135: 136: /** 137: * <b>DOM L1</b> 138: * Returns the attribute value, with character and entity 139: * references substituted. 140: * <em>NOTE: entity refs as children aren't currently handled.</em> 141: */ 142: public String getNodeValue() 143: { 144: // If we have a simple node-value, use that 145: if (first == null) 146: { 147: return (value == null) ? "" : value; 148: } 149: // Otherwise collect child node-values 150: StringBuffer buf = new StringBuffer(); 151: for (DomNode ctx = first; ctx != null; ctx = ctx.next) 152: { 153: switch (ctx.nodeType) 154: { 155: case Node.TEXT_NODE: 156: buf.append(ctx.getNodeValue()); 157: break; 158: case Node.ENTITY_REFERENCE_NODE: 159: // TODO 160: break; 161: } 162: } 163: return buf.toString(); 164: } 165: 166: /** 167: * <b>DOM L1</b> 168: * Assigns the value of the attribute; it will have one child, 169: * which is a text node with the specified value (same as 170: * setNodeValue). 171: */ 172: public final void setValue(String value) 173: { 174: setNodeValue(value); 175: } 176: 177: /** 178: * <b>DOM L1</b> 179: * Returns the value of the attribute as a non-null string; same 180: * as getNodeValue. 181: * <em>NOTE: entity refs as children aren't currently handled.</em> 182: */ 183: public final String getValue() 184: { 185: return getNodeValue(); 186: } 187: 188: /** 189: * <b>DOM L1</b> 190: * Assigns the attribute value; using this API, no entity or 191: * character references will exist. 192: * Causes a DOMAttrModified mutation event to be sent. 193: */ 194: public void setNodeValue(String value) 195: { 196: if (readonly) 197: { 198: throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); 199: } 200: if (value == null) 201: { 202: value = ""; 203: } 204: String oldValue = getNodeValue(); 205: while (last != null) 206: { 207: removeChild(last); 208: } 209: // don't create a new node just for this... 210: /* 211: Node text = owner.createTextNode(value); 212: appendChild(text); 213: */ 214: this.value = value; 215: length = 1; 216: specified = true; 217: 218: mutating(oldValue, value, MutationEvent.MODIFICATION); 219: } 220: 221: public final Node getFirstChild() 222: { 223: // Create a child text node if necessary 224: if (first == null) 225: { 226: length = 0; 227: Node text = owner.createTextNode((value == null) ? "" : value); 228: appendChild(text); 229: } 230: return first; 231: } 232: 233: public final Node getLastChild() 234: { 235: // Create a child text node if necessary 236: if (last == null) 237: { 238: length = 0; 239: Node text = owner.createTextNode((value == null) ? "" : value); 240: appendChild(text); 241: } 242: return last; 243: } 244: 245: public Node item(int index) 246: { 247: // Create a child text node if necessary 248: if (first == null) 249: { 250: length = 0; 251: Node text = owner.createTextNode((value == null) ? "" : value); 252: appendChild(text); 253: } 254: return super.item(index); 255: } 256: 257: /** 258: * <b>DOM L2</b> 259: * Returns the element with which this attribute is associated. 260: */ 261: public final Element getOwnerElement() 262: { 263: return (Element) parent; 264: } 265: 266: public final Node getNextSibling() 267: { 268: return null; 269: } 270: 271: public final Node getPreviousSibling() 272: { 273: return null; 274: } 275: 276: public Node getParentNode() 277: { 278: return null; 279: } 280: 281: /** 282: * Records the element with which this attribute is associated. 283: */ 284: public final void setOwnerElement(Element e) 285: { 286: if (parent != null) 287: { 288: throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); 289: } 290: if (!(e instanceof DomElement)) 291: { 292: throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); 293: } 294: parent = (DomElement) e; 295: depth = parent.depth + 1; 296: } 297: 298: /** 299: * The base URI of an Attr is always <code>null</code>. 300: */ 301: public final String getBaseURI() 302: { 303: return null; 304: } 305: 306: /** 307: * Shallow clone of the attribute, breaking all ties with any 308: * elements. 309: */ 310: public Object clone() 311: { 312: DomAttr retval = (DomAttr) super.clone(); 313: retval.specified = true; 314: return retval; 315: } 316: 317: private void mutating(String oldValue, String newValue, short why) 318: { 319: if (!reportMutations || parent == null) 320: { 321: return; 322: } 323: 324: // EVENT: DOMAttrModified, target = parent, 325: // prev/new values provided, also attr name 326: MutationEvent event; 327: 328: event = (MutationEvent) createEvent ("MutationEvents"); 329: event.initMutationEvent ("DOMAttrModified", 330: true /* bubbles */, false /* nocancel */, 331: null, oldValue, newValue, getNodeName (), why); 332: parent.dispatchEvent (event); 333: } 334: 335: // DOM Level 3 methods 336: 337: public TypeInfo getSchemaTypeInfo() 338: { 339: if (parent != null) 340: { 341: // DTD implementation 342: DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); 343: if (doctype != null) 344: { 345: return doctype.getAttributeTypeInfo(parent.getNodeName(), 346: getNodeName()); 347: } 348: // TODO XML Schema implementation 349: } 350: return null; 351: } 352: 353: public boolean isId() 354: { 355: if (parent != null) 356: { 357: DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); 358: if (doctype != null) 359: { 360: DTDAttributeTypeInfo info = 361: doctype.getAttributeTypeInfo(parent.getNodeName(), 362: getNodeName()); 363: if (info != null && "ID".equals(info.type)) 364: { 365: return true; 366: } 367: } 368: DomElement element = (DomElement) parent; 369: if (element.userIdAttrs != null && 370: element.userIdAttrs.contains(this)) 371: { 372: return true; 373: } 374: // TODO XML Schema implementation 375: } 376: return false; 377: } 378: 379: }