1. /*
  2. * $Id: AttributeNode.java,v 1.11 2001/04/11 02:27:56 edwingo Exp $
  3. *
  4. * The Apache Software License, Version 1.1
  5. *
  6. *
  7. * Copyright (c) 2000 The Apache Software Foundation. All rights
  8. * reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The end-user documentation included with the redistribution,
  23. * if any, must include the following acknowledgment:
  24. * "This product includes software developed by the
  25. * Apache Software Foundation (http://www.apache.org/)."
  26. * Alternately, this acknowledgment may appear in the software itself,
  27. * if and wherever such third-party acknowledgments normally appear.
  28. *
  29. * 4. The names "Crimson" and "Apache Software Foundation" must
  30. * not be used to endorse or promote products derived from this
  31. * software without prior written permission. For written
  32. * permission, please contact apache@apache.org.
  33. *
  34. * 5. Products derived from this software may not be called "Apache",
  35. * nor may "Apache" appear in their name, without prior written
  36. * permission of the Apache Software Foundation.
  37. *
  38. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  39. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  40. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  41. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  42. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  43. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  44. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  45. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  46. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  47. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  48. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  49. * SUCH DAMAGE.
  50. * ====================================================================
  51. *
  52. * This software consists of voluntary contributions made by many
  53. * individuals on behalf of the Apache Software Foundation and was
  54. * originally based on software copyright (c) 1999, Sun Microsystems, Inc.,
  55. * http://www.sun.com. For more information on the Apache Software
  56. * Foundation, please see <http://www.apache.org/>.
  57. */
  58. package org.apache.crimson.tree;
  59. import java.io.Writer;
  60. import java.io.IOException;
  61. import org.w3c.dom.*;
  62. import org.apache.crimson.util.XmlNames;
  63. /**
  64. * Node representing an XML attribute. Many views of attributes can be
  65. * useful, but only the first of these is explicitly supported: <DL>
  66. *
  67. * <DT> <em>Logical View</em> </DT><DD> Attributes always hold a
  68. * string created by expanding character and entity references from
  69. * source text conforming to the XML specification. If this
  70. * attribute was declared in a DTD, normalization will often be
  71. * done to eliminate insignificant whitespace.</DD>
  72. *
  73. * <DT> <em>DTD Validated View</em> </DT><DD> If the attribute was
  74. * declared in a DTD, it will have minimal semantics provided by its
  75. * declaration, and checked by validating parsers. For example, the
  76. * logical view may name one (or many) unparsed entities or DOM nodes.
  77. * This view could provide direct access to them for any DTD, since
  78. * these attribute semantics are defined by XML itself.</DD>
  79. *
  80. * <DT> <em>Semantic View</em> </DT><DD> The person who wrote the
  81. * DTD (or other namespace) defined what each attribute's logical
  82. * view "means". For example, that it's a URL, or that the unparsed
  83. * entity referred to identifies a particular database to be used.
  84. * This view would provide direct access to such values, but would
  85. * need to have code specialized to that DTD or namespace.</DD>
  86. *
  87. * <DT> <em>Physical View</em> </DT><DD> Attributes may have children
  88. * to represent text and entity reference nodes found in unexpanded
  89. * and unnormalized XML source text. Such views are mostly of interest
  90. * when editing XML text that is not dynamically generated by programs.
  91. * This implementation does not currently support physical views of
  92. * attributes. </DD>
  93. *
  94. * </DL>
  95. *
  96. *
  97. * @author David Brownell
  98. * @author Rajiv Mordani
  99. * @version $Revision: 1.11 $
  100. */
  101. public class AttributeNode extends NamespacedNode implements Attr
  102. {
  103. private String value;
  104. private boolean specified;
  105. private String defaultValue;
  106. /** At construction time ownerElement is null, it gets set whenever an
  107. attribute is set on an Element */
  108. private Element ownerElement;
  109. /** Constructs an attribute node. Used for SAX2 and DOM2 */
  110. public AttributeNode(String namespaceURI, String qName,
  111. String value, boolean specified, String defaultValue)
  112. throws DOMException
  113. {
  114. super(namespaceURI, qName);
  115. this.value = value;
  116. this.specified = specified;
  117. this.defaultValue = defaultValue;
  118. }
  119. /**
  120. * Make a clone of this node and return it. Used for cloneNode().
  121. */
  122. AttributeNode makeClone() {
  123. AttributeNode retval = new AttributeNode(namespaceURI, qName, value,
  124. specified, defaultValue);
  125. retval.ownerDocument = ownerDocument;
  126. return retval;
  127. }
  128. /**
  129. * Package private method to check arguments for constructor
  130. */
  131. static void checkArguments(String namespaceURI, String qualifiedName)
  132. throws DomEx
  133. {
  134. // [6] QName ::= (Prefix ':')? LocalPart
  135. // [7] Prefix ::= NCName
  136. // [8] LocalPart ::= NCName
  137. if (qualifiedName == null) {
  138. throw new DomEx(DomEx.NAMESPACE_ERR);
  139. }
  140. int first = qualifiedName.indexOf(':');
  141. if (first <= 0) {
  142. // no Prefix, only check LocalPart
  143. if (!XmlNames.isUnqualifiedName(qualifiedName)) {
  144. throw new DomEx(DomEx.INVALID_CHARACTER_ERR);
  145. }
  146. if ("xmlns".equals(qualifiedName) &&
  147. !XmlNames.SPEC_XMLNS_URI.equals(namespaceURI)) {
  148. throw new DomEx(DomEx.NAMESPACE_ERR);
  149. }
  150. return;
  151. }
  152. // Prefix exists, check everything
  153. int last = qualifiedName.lastIndexOf(':');
  154. if (last != first) {
  155. throw new DomEx(DomEx.NAMESPACE_ERR);
  156. }
  157. String prefix = qualifiedName.substring(0, first);
  158. String localName = qualifiedName.substring(first + 1);
  159. if (!XmlNames.isUnqualifiedName(prefix)
  160. || !XmlNames.isUnqualifiedName(localName)) {
  161. throw new DomEx(DomEx.INVALID_CHARACTER_ERR);
  162. }
  163. // If we get here then we must have a valid prefix
  164. if (namespaceURI == null
  165. || ("xml".equals(prefix)
  166. && !XmlNames.SPEC_XML_URI.equals(namespaceURI))) {
  167. throw new DomEx(DomEx.NAMESPACE_ERR);
  168. }
  169. }
  170. // package private
  171. String getDefaultValue ()
  172. {
  173. return defaultValue;
  174. }
  175. /**
  176. * <b>DOM2:</b>
  177. */
  178. public Element getOwnerElement() {
  179. return ownerElement;
  180. }
  181. // package private
  182. void setOwnerElement(Element element) {
  183. if (element != null && ownerElement != null) {
  184. throw new IllegalStateException(getMessage("A-000",
  185. new Object[] { element.getTagName() }));
  186. }
  187. ownerElement = element;
  188. }
  189. /** DOM: Returns the ATTRIBUTE_NODE node type constant. */
  190. public short getNodeType () { return ATTRIBUTE_NODE; }
  191. /** DOM: Returns the attribute name */
  192. public String getName () { return qName; }
  193. /** DOM: Returns the attribute value. */
  194. public String getValue () { return value; }
  195. /** DOM: Assigns the value of this attribute. */
  196. public void setValue (String value) { setNodeValue (value); }
  197. /** DOM: Returns the attribute value. */
  198. public String getNodeValue () { return value; }
  199. /** DOM: Returns true if the source text specified the attribute. */
  200. public boolean getSpecified () { return specified; }
  201. /** DOM: Assigns the value of this attribute. */
  202. public void setNodeValue (String value)
  203. {
  204. if (isReadonly ())
  205. throw new DomEx (DomEx.NO_MODIFICATION_ALLOWED_ERR);
  206. this.value = value;
  207. specified = true;
  208. }
  209. /** Flags whether the source text specified the attribute. */
  210. // pubic
  211. void setSpecified (boolean specified) { this.specified = specified; }
  212. /** DOM: Returns null */
  213. public Node getParentNode () { return null; }
  214. /** DOM: Returns null */
  215. public Node getNextSibling () { return null; }
  216. /** DOM: Returns null */
  217. public Node getPreviousSibling () { return null; }
  218. /**
  219. * Writes the attribute out, as if it were assigned within an
  220. * element's starting tag (<em>name="value"</em>).
  221. */
  222. public void writeXml (XmlWriteContext context) throws IOException
  223. {
  224. Writer out = context.getWriter ();
  225. out.write (qName);
  226. out.write ("=\"");
  227. writeChildrenXml (context);
  228. out.write ('"');
  229. }
  230. /**
  231. * Writes the attribute's value.
  232. */
  233. public void writeChildrenXml (XmlWriteContext context) throws IOException
  234. {
  235. Writer out = context.getWriter ();
  236. for (int i = 0; i < value.length (); i++) {
  237. int c = value.charAt (i);
  238. switch (c) {
  239. // XXX only a few of these are necessary; we
  240. // do what "Canonical XML" expects
  241. case '<': out.write ("<"); continue;
  242. case '>': out.write (">"); continue;
  243. case '&': out.write ("&"); continue;
  244. case '\'': out.write ("'"); continue;
  245. case '"': out.write ("""); continue;
  246. default: out.write (c); continue;
  247. }
  248. }
  249. }
  250. /**
  251. * DOM: returns a copy of this node which is not owned by an Element
  252. */
  253. public Node cloneNode(boolean deep) {
  254. AttributeNode attr = cloneAttributeNode(deep);
  255. // DOM says specified should be true
  256. attr.specified = true;
  257. return attr;
  258. }
  259. /**
  260. * Clone this AttributeNode and possibly its children (which cannot be
  261. * AttributeNodes themselves). "ownerElement" will remain null.
  262. */
  263. AttributeNode cloneAttributeNode(boolean deep) {
  264. try {
  265. AttributeNode attr = makeClone();
  266. if (deep) {
  267. Node node;
  268. for (int i = 0; (node = item (i)) != null; i++) {
  269. node = node.cloneNode (true);
  270. attr.appendChild (node);
  271. }
  272. }
  273. return attr;
  274. } catch (DOMException e) {
  275. throw new RuntimeException (getMessage ("A-002"));
  276. }
  277. }
  278. void checkChildType(int type) throws DOMException {
  279. switch(type) {
  280. case TEXT_NODE:
  281. case ENTITY_REFERENCE_NODE:
  282. return;
  283. default:
  284. throw new DomEx (DomEx.HIERARCHY_REQUEST_ERR);
  285. }
  286. }
  287. }