001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.xml;
030:
031: import com.caucho.util.CharBuffer;
032:
033: import org.w3c.dom.*;
034:
035: import java.io.IOException;
036: import java.util.HashMap;
037:
038: /**
039: * Resin's implementation of the DOM element.
040: */
041: public class QElement extends QAttributedNode implements CauchoElement {
042: private QName _name;
043:
044: /**
045: * Create a new element.
046: */
047: public QElement() {
048: }
049:
050: /**
051: * Create a new named element.
052: *
053: * @param name the element's name.
054: */
055: public QElement(String name) {
056: _name = new QName(name);
057: }
058:
059: /**
060: * Create a new named element.
061: *
062: * @param name the element's name.
063: */
064: public QElement(String name, String namespace) {
065: _name = new QName(name, namespace);
066: }
067:
068: /**
069: * Create a new named element.
070: *
071: * @param name the element's name.
072: */
073: public QElement(QName name) {
074: _name = name;
075: }
076:
077: protected QElement(QDocument owner, QName name) {
078: _owner = owner;
079: _name = name;
080: }
081:
082: /**
083: * Create a new named element with initial parameters.
084: *
085: * @param name the element's name.
086: * @param attributes the element's attributes.
087: */
088: QElement(QName name, HashMap attributes) {
089: _name = name;
090: }
091:
092: /**
093: * Assign a name to the element. Not normally called by external
094: * API.
095: *
096: * @param name the element's name.
097: */
098: public void setName(QName name) {
099: _name = name;
100: }
101:
102: /**
103: * Returns the qname
104: */
105: public QName getQName() {
106: return _name;
107: }
108:
109: /**
110: * Returns the element's qualified-name as the node name.
111: */
112: public String getNodeName() {
113: return _name.getName();
114: }
115:
116: /**
117: * Returns the element's qualified-name as the node name.
118: */
119: public String getTagName() {
120: return _name.getName();
121: }
122:
123: /**
124: * Returns the local part of the element's name.
125: */
126: public String getLocalName() {
127: return _name.getLocalName();
128: }
129:
130: /**
131: * Returns the namespace prefix for the element.
132: */
133: public String getPrefix() {
134: return _name.getPrefix();
135: }
136:
137: /**
138: * Returns the canonical name of the element.
139: */
140: public String getCanonicalName() {
141: return _name.getCanonicalName();
142: }
143:
144: /**
145: * Returns the namespace of the element.
146: */
147: public String getNamespaceURI() {
148: return _name.getNamespace();
149: }
150:
151: /**
152: * Given a prefix, returns the namespace in effect at this element.
153: *
154: * @param prefix the prefix to test.
155: * @return the namespace URL matching the prefix or null.
156: */
157: public String getNamespace(String prefix) {
158: if (prefix == null)
159: return getNamespace("", "xmlns");
160: else
161: return getNamespace(prefix, "xmlns:" + prefix);
162: }
163:
164: private String getNamespace(String prefix, String xmlns) {
165: Attr namespace = getAttributeNode(xmlns);
166:
167: if (namespace != null)
168: return namespace.getNodeValue();
169:
170: if (_parent instanceof QElement)
171: return ((QElement) _parent).getNamespace(prefix, xmlns);
172:
173: return _owner.getNamespace(prefix);
174: }
175:
176: /**
177: * Returns the DOM NodeType, ELEMENT_NODE.
178: */
179: public short getNodeType() {
180: return ELEMENT_NODE;
181: }
182:
183: /**
184: * Returns the schema type.
185: */
186: public TypeInfo getSchemaTypeInfo() {
187: return null;
188: }
189:
190: /**
191: * Returns a list of elements, given a tag name.
192: */
193: public NodeList getElementsByTagName(String tagName) {
194: QAbstractNode child = (QAbstractNode) getFirstChild();
195:
196: if (child != null)
197: return new QDeepNodeList(this , child, new TagPredicate(
198: tagName));
199: else
200: return new QDeepNodeList(this , null, new TagPredicate(
201: tagName));
202: }
203:
204: /**
205: * Returns a list of elements, given a namespace and a local name.
206: */
207: public NodeList getElementsByTagNameNS(String uri, String name) {
208: QAbstractNode child = (QAbstractNode) getFirstChild();
209:
210: if (child != null)
211: return new QDeepNodeList(this , child, new NSTagPredicate(
212: uri, name));
213: else
214: return new QDeepNodeList(this , null, new NSTagPredicate(
215: uri, name));
216: }
217:
218: /**
219: * Appends a new node as the last child of the element.
220: *
221: * @param child the new child.
222: * @return the child.
223: */
224: public Node appendChild(Node child) throws DOMException {
225: Node result = super .appendChild(child);
226:
227: if (child instanceof QElement) {
228: QElement elt = (QElement) child;
229: QName name = elt._name;
230:
231: if (name.getNamespace() != "") {
232: addNamespace(name);
233: }
234:
235: for (QAttr attr = (QAttr) elt.getFirstAttribute(); attr != null; attr = (QAttr) attr
236: .getNextSibling()) {
237: name = attr._name;
238:
239: if (name.getNamespace() != "") {
240: addNamespace(name);
241: }
242: }
243: }
244:
245: return result;
246: }
247:
248: /**
249: * Adds the name to the global namespace, if possible.
250: */
251: void addNamespace(QName name) {
252: _owner.addNamespace(name.getPrefix(), name.getNamespace());
253: }
254:
255: /**
256: * Normalize the element, i.e. smash all neighboring text nodes together.
257: */
258: public void normalize() {
259: Node node = _firstChild;
260:
261: while (node != null) {
262: if (node.getNodeType() == TEXT_NODE
263: && node.getNextSibling() != null
264: && node.getNextSibling().getNodeType() == TEXT_NODE) {
265: Text text = (Text) node;
266: Text next = (Text) node.getNextSibling();
267: text.appendData(next.getData());
268: removeChild(next);
269: } else if (node.getNodeType() == ELEMENT_NODE) {
270: Element elt = (Element) node;
271: elt.normalize();
272: node = node.getNextSibling();
273: } else
274: node = node.getNextSibling();
275: }
276: }
277:
278: public boolean hasContent() {
279: return true;
280: }
281:
282: public boolean equals(Object arg) {
283: return this == arg;
284: }
285:
286: public boolean equals(Node arg, boolean deep) {
287: return this == arg;
288: }
289:
290: /**
291: * Returns the text value of the element. For an element, the text
292: * value is the smashing together of all the child text nodes.
293: */
294: public String getTextValue() {
295: CharBuffer cb = CharBuffer.allocate();
296:
297: for (QAbstractNode node = _firstChild; node != null; node = node._next) {
298: cb.append(node.getTextValue());
299: }
300:
301: return cb.close();
302: }
303:
304: void print(XmlPrinter out) throws IOException {
305: out.startElement(getNamespaceURI(), getLocalName(),
306: getNodeName());
307: for (QAbstractNode node = (QAbstractNode) getFirstAttribute(); node != null; node = (QAbstractNode) node
308: .getNextSibling()) {
309: out.attribute(node.getNamespaceURI(), node.getLocalName(),
310: node.getNodeName(), node.getNodeValue());
311: }
312: for (Node node = getFirstChild(); node != null; node = node
313: .getNextSibling()) {
314: ((QAbstractNode) node).print(out);
315: }
316: out
317: .endElement(getNamespaceURI(), getLocalName(),
318: getNodeName());
319: }
320:
321: public String toString() {
322: CharBuffer cb = CharBuffer.allocate();
323:
324: cb.append("Element[" + _name);
325:
326: for (QAttr attr = (QAttr) getFirstAttribute(); attr != null; attr = (QAttr) attr
327: .getNextSibling())
328: cb.append(" " + attr);
329: cb.append("]");
330:
331: return cb.close();
332: }
333:
334: private Object writeReplace() {
335: return new SerializedXml(this );
336: }
337:
338: static class TagPredicate implements QNodePredicate {
339: String _name;
340:
341: TagPredicate(String name) {
342: if (name == null)
343: name = "*";
344:
345: _name = name;
346: }
347:
348: public boolean isMatch(QAbstractNode node) {
349: return (node.getNodeName().equals(_name) || _name
350: .equals("*")
351: && node instanceof Element);
352: }
353: }
354:
355: static class NSTagPredicate implements QNodePredicate {
356: String _uri;
357: String _local;
358:
359: NSTagPredicate(String uri, String local) {
360: _uri = uri;
361: _local = local;
362: }
363:
364: public boolean isMatch(QAbstractNode node) {
365: return (_local.equals(node.getLocalName()) && ("*"
366: .equals(_uri) || _uri
367: .equals(node.getNamespaceURI())));
368: }
369: }
370: }
|