0
|
1 /*--
|
|
2
|
|
3 $Id: Element.java,v 1.159 2007/11/14 05:02:08 jhunter Exp $
|
|
4
|
|
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
|
|
6 All rights reserved.
|
|
7
|
|
8 Redistribution and use in source and binary forms, with or without
|
|
9 modification, are permitted provided that the following conditions
|
|
10 are met:
|
|
11
|
|
12 1. Redistributions of source code must retain the above copyright
|
|
13 notice, this list of conditions, and the following disclaimer.
|
|
14
|
|
15 2. Redistributions in binary form must reproduce the above copyright
|
|
16 notice, this list of conditions, and the disclaimer that follows
|
|
17 these conditions in the documentation and/or other materials
|
|
18 provided with the distribution.
|
|
19
|
|
20 3. The name "JDOM" must not be used to endorse or promote products
|
|
21 derived from this software without prior written permission. For
|
|
22 written permission, please contact <request_AT_jdom_DOT_org>.
|
|
23
|
|
24 4. Products derived from this software may not be called "JDOM", nor
|
|
25 may "JDOM" appear in their name, without prior written permission
|
|
26 from the JDOM Project Management <request_AT_jdom_DOT_org>.
|
|
27
|
|
28 In addition, we request (but do not require) that you include in the
|
|
29 end-user documentation provided with the redistribution and/or in the
|
|
30 software itself an acknowledgement equivalent to the following:
|
|
31 "This product includes software developed by the
|
|
32 JDOM Project (http://www.jdom.org/)."
|
|
33 Alternatively, the acknowledgment may be graphical using the logos
|
|
34 available at http://www.jdom.org/images/logos.
|
|
35
|
|
36 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
37 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
38 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
39 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
|
|
40 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
43 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
44 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
45 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
46 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
47 SUCH DAMAGE.
|
|
48
|
|
49 This software consists of voluntary contributions made by many
|
|
50 individuals on behalf of the JDOM Project and was originally
|
|
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
|
|
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
|
|
53 on the JDOM Project, please see <http://www.jdom.org/>.
|
|
54
|
|
55 */
|
|
56
|
|
57 package org.jdom;
|
|
58
|
|
59 import java.io.*;
|
|
60 import java.util.*;
|
|
61
|
|
62 import org.jdom.filter.*;
|
|
63
|
|
64 /**
|
|
65 * An XML element. Methods allow the user to get and manipulate its child
|
|
66 * elements and content, directly access the element's textual content,
|
|
67 * manipulate its attributes, and manage namespaces.
|
|
68 *
|
|
69 * @version $Revision: 1.159 $, $Date: 2007/11/14 05:02:08 $
|
|
70 * @author Brett McLaughlin
|
|
71 * @author Jason Hunter
|
|
72 * @author Lucas Gonze
|
|
73 * @author Kevin Regan
|
|
74 * @author Dan Schaffer
|
|
75 * @author Yusuf Goolamabbas
|
|
76 * @author Kent C. Johnson
|
|
77 * @author Jools Enticknap
|
|
78 * @author Alex Rosen
|
|
79 * @author Bradley S. Huffman
|
|
80 * @author Victor Toni
|
|
81 */
|
|
82 public class Element extends Content implements Parent {
|
|
83
|
|
84 private static final String CVS_ID =
|
|
85 "@(#) $RCSfile: Element.java,v $ $Revision: 1.159 $ $Date: 2007/11/14 05:02:08 $ $Name: jdom_1_1_1 $";
|
|
86
|
|
87 private static final int INITIAL_ARRAY_SIZE = 5;
|
|
88
|
|
89 /** The local name of the element */
|
|
90 protected String name;
|
|
91
|
|
92 /** The namespace of the element */
|
|
93 protected transient Namespace namespace;
|
|
94
|
|
95 /** Additional namespace declarations to store on this element; useful
|
|
96 * during output */
|
|
97 protected transient List additionalNamespaces;
|
|
98
|
|
99 // See http://lists.denveronline.net/lists/jdom-interest/2000-September/003030.html
|
|
100 // for a possible memory optimization here (using a RootElement subclass)
|
|
101
|
|
102 /**
|
|
103 * The attributes of the element. Subclassers have to
|
|
104 * track attributes using their own mechanism.
|
|
105 */
|
|
106 AttributeList attributes = new AttributeList(this);
|
|
107
|
|
108 /**
|
|
109 * The content of the element. Subclassers have to
|
|
110 * track content using their own mechanism.
|
|
111 */
|
|
112 ContentList content = new ContentList(this);
|
|
113
|
|
114 /**
|
|
115 * This protected constructor is provided in order to support an Element
|
|
116 * subclass that wants full control over variable initialization. It
|
|
117 * intentionally leaves all instance variables null, allowing a lightweight
|
|
118 * subclass implementation. The subclass is responsible for ensuring all the
|
|
119 * get and set methods on Element behave as documented.
|
|
120 * <p>
|
|
121 * When implementing an Element subclass which doesn't require full control
|
|
122 * over variable initialization, be aware that simply calling super() (or
|
|
123 * letting the compiler add the implicit super() call) will not initialize
|
|
124 * the instance variables which will cause many of the methods to throw a
|
|
125 * NullPointerException. Therefore, the constructor for these subclasses
|
|
126 * should call one of the public constructors so variable initialization is
|
|
127 * handled automatically.
|
|
128 */
|
|
129 protected Element() { }
|
|
130
|
|
131 /**
|
|
132 * Creates a new element with the supplied (local) name and namespace. If
|
|
133 * the provided namespace is null, the element will have no namespace.
|
|
134 *
|
|
135 * @param name local name of the element
|
|
136 * @param namespace namespace for the element
|
|
137 * @throws IllegalNameException if the given name is illegal as an element
|
|
138 * name
|
|
139 */
|
|
140 public Element(final String name, final Namespace namespace) {
|
|
141 setName(name);
|
|
142 setNamespace(namespace);
|
|
143 }
|
|
144
|
|
145 /**
|
|
146 * Create a new element with the supplied (local) name and no namespace.
|
|
147 *
|
|
148 * @param name local name of the element
|
|
149 * @throws IllegalNameException if the given name is illegal as an element
|
|
150 * name.
|
|
151 */
|
|
152 public Element(final String name) {
|
|
153 this(name, (Namespace) null);
|
|
154 }
|
|
155
|
|
156 /**
|
|
157 * Creates a new element with the supplied (local) name and a namespace
|
|
158 * given by a URI. The element will be put into the unprefixed (default)
|
|
159 * namespace.
|
|
160 *
|
|
161 * @param name name of the element
|
|
162 * @param uri namespace URI for the element
|
|
163 * @throws IllegalNameException if the given name is illegal as an element
|
|
164 * name or the given URI is illegal as a
|
|
165 * namespace URI
|
|
166 */
|
|
167 public Element(final String name, final String uri) {
|
|
168 this(name, Namespace.getNamespace("", uri));
|
|
169 }
|
|
170
|
|
171 /**
|
|
172 * Creates a new element with the supplied (local) name and a namespace
|
|
173 * given by the supplied prefix and URI combination.
|
|
174 *
|
|
175 * @param name local name of the element
|
|
176 * @param prefix namespace prefix
|
|
177 * @param uri namespace URI for the element
|
|
178 * @throws IllegalNameException if the given name is illegal as an element
|
|
179 * name, the given prefix is illegal as a
|
|
180 * namespace prefix, or the given URI is
|
|
181 * illegal as a namespace URI
|
|
182 */
|
|
183 public Element(final String name, final String prefix, final String uri) {
|
|
184 this(name, Namespace.getNamespace(prefix, uri));
|
|
185 }
|
|
186
|
|
187 /**
|
|
188 * Returns the (local) name of the element (without any namespace prefix).
|
|
189 *
|
|
190 * @return local element name
|
|
191 */
|
|
192 public String getName() {
|
|
193 return name;
|
|
194 }
|
|
195
|
|
196 /**
|
|
197 * Sets the (local) name of the element.
|
|
198 *
|
|
199 * @param name the new (local) name of the element
|
|
200 * @return the target element
|
|
201 * @throws IllegalNameException if the given name is illegal as an Element
|
|
202 * name
|
|
203 */
|
|
204 public Element setName(final String name) {
|
|
205 final String reason = Verifier.checkElementName(name);
|
|
206 if (reason != null) {
|
|
207 throw new IllegalNameException(name, "element", reason);
|
|
208 }
|
|
209 this.name = name;
|
|
210 return this;
|
|
211 }
|
|
212
|
|
213 /**
|
|
214 * Returns the element's {@link Namespace}.
|
|
215 *
|
|
216 * @return the element's namespace
|
|
217 */
|
|
218 public Namespace getNamespace() {
|
|
219 return namespace;
|
|
220 }
|
|
221
|
|
222 /**
|
|
223 * Sets the element's {@link Namespace}. If the provided namespace is null,
|
|
224 * the element will have no namespace.
|
|
225 *
|
|
226 * @param namespace the new namespace
|
|
227 * @return the target element
|
|
228 */
|
|
229 public Element setNamespace(Namespace namespace) {
|
|
230 if (namespace == null) {
|
|
231 namespace = Namespace.NO_NAMESPACE;
|
|
232 }
|
|
233
|
|
234 this.namespace = namespace;
|
|
235 return this;
|
|
236 }
|
|
237
|
|
238 /**
|
|
239 * Returns the namespace prefix of the element or an empty string if none
|
|
240 * exists.
|
|
241 *
|
|
242 * @return the namespace prefix
|
|
243 */
|
|
244 public String getNamespacePrefix() {
|
|
245 return namespace.getPrefix();
|
|
246 }
|
|
247
|
|
248 /**
|
|
249 * Returns the namespace URI mapped to this element's prefix (or the
|
|
250 * in-scope default namespace URI if no prefix). If no mapping is found, an
|
|
251 * empty string is returned.
|
|
252 *
|
|
253 * @return the namespace URI for this element
|
|
254 */
|
|
255 public String getNamespaceURI() {
|
|
256 return namespace.getURI();
|
|
257 }
|
|
258
|
|
259 /**
|
|
260 * Returns the {@link Namespace} corresponding to the given prefix in scope
|
|
261 * for this element. This involves searching up the tree, so the results
|
|
262 * depend on the current location of the element. Returns null if there is
|
|
263 * no namespace in scope with the given prefix at this point in the
|
|
264 * document.
|
|
265 *
|
|
266 * @param prefix namespace prefix to look up
|
|
267 * @return the Namespace for this prefix at this
|
|
268 * location, or null if none
|
|
269 */
|
|
270 public Namespace getNamespace(final String prefix) {
|
|
271 if (prefix == null) {
|
|
272 return null;
|
|
273 }
|
|
274
|
|
275 if ("xml".equals(prefix)) {
|
|
276 // Namespace "xml" is always bound.
|
|
277 return Namespace.XML_NAMESPACE;
|
|
278 }
|
|
279
|
|
280 // Check if the prefix is the prefix for this element
|
|
281 if (prefix.equals(getNamespacePrefix())) {
|
|
282 return getNamespace();
|
|
283 }
|
|
284
|
|
285 // Scan the additional namespaces
|
|
286 if (additionalNamespaces != null) {
|
|
287 for (int i = 0; i < additionalNamespaces.size(); i++) {
|
|
288 final Namespace ns = (Namespace) additionalNamespaces.get(i);
|
|
289 if (prefix.equals(ns.getPrefix())) {
|
|
290 return ns;
|
|
291 }
|
|
292 }
|
|
293 }
|
|
294
|
|
295 // If we still don't have a match, ask the parent
|
|
296 if (parent instanceof Element) {
|
|
297 return ((Element)parent).getNamespace(prefix);
|
|
298 }
|
|
299
|
|
300 return null;
|
|
301 }
|
|
302
|
|
303 /**
|
|
304 * Returns the full name of the element, in the form
|
|
305 * [namespacePrefix]:[localName]. If the element does not have a namespace
|
|
306 * prefix, then the local name is returned.
|
|
307 *
|
|
308 * @return qualified name of the element (including
|
|
309 * namespace prefix)
|
|
310 */
|
|
311 public String getQualifiedName() {
|
|
312 // Note: Any changes here should be reflected in
|
|
313 // XMLOutputter.printQualifiedName()
|
|
314 if ("".equals(namespace.getPrefix())) {
|
|
315 return getName();
|
|
316 }
|
|
317
|
|
318 return new StringBuffer(namespace.getPrefix())
|
|
319 .append(':')
|
|
320 .append(name)
|
|
321 .toString();
|
|
322 }
|
|
323
|
|
324 /**
|
|
325 * Adds a namespace declarations to this element. This should <i>not</i> be
|
|
326 * used to add the declaration for this element itself; that should be
|
|
327 * assigned in the construction of the element. Instead, this is for adding
|
|
328 * namespace declarations on the element not relating directly to itself.
|
|
329 * It's used during output to for stylistic reasons move namespace
|
|
330 * declarations higher in the tree than they would have to be.
|
|
331 *
|
|
332 * @param additionalNamespace namespace to add
|
|
333 * @throws IllegalAddException if the namespace prefix collides with another
|
|
334 * namespace prefix on the element
|
|
335 */
|
|
336 public void addNamespaceDeclaration(final Namespace additionalNamespace) {
|
|
337
|
|
338 // Verify the new namespace prefix doesn't collide with another
|
|
339 // declared namespace, an attribute prefix, or this element's prefix
|
|
340 final String reason = Verifier.checkNamespaceCollision(additionalNamespace, this);
|
|
341 if (reason != null) {
|
|
342 throw new IllegalAddException(this, additionalNamespace, reason);
|
|
343 }
|
|
344
|
|
345 if (additionalNamespaces == null) {
|
|
346 additionalNamespaces = new ArrayList(INITIAL_ARRAY_SIZE);
|
|
347 }
|
|
348
|
|
349 additionalNamespaces.add(additionalNamespace);
|
|
350 }
|
|
351
|
|
352 /**
|
|
353 * Removes an additional namespace declarations from this element. This
|
|
354 * should <i>not</i> be used to remove the declaration for this element
|
|
355 * itself; that should be handled in the construction of the element.
|
|
356 * Instead, this is for removing namespace declarations on the element not
|
|
357 * relating directly to itself. If the declaration is not present, this
|
|
358 * method does nothing.
|
|
359 *
|
|
360 * @param additionalNamespace namespace to remove
|
|
361 */
|
|
362 public void removeNamespaceDeclaration(final Namespace additionalNamespace) {
|
|
363 if (additionalNamespaces == null) {
|
|
364 return;
|
|
365 }
|
|
366 additionalNamespaces.remove(additionalNamespace);
|
|
367 }
|
|
368
|
|
369 /**
|
|
370 * Returns a list of the additional namespace declarations on this element.
|
|
371 * This includes only additional namespace, not the namespace of the element
|
|
372 * itself, which can be obtained through {@link #getNamespace()}. If there
|
|
373 * are no additional declarations, this returns an empty list. Note, the
|
|
374 * returned list is unmodifiable.
|
|
375 *
|
|
376 * @return a List of the additional namespace
|
|
377 * declarations
|
|
378 */
|
|
379 public List getAdditionalNamespaces() {
|
|
380 // Not having the returned list be live allows us to avoid creating a
|
|
381 // new list object when XMLOutputter calls this method on an element
|
|
382 // with an empty list.
|
|
383 if (additionalNamespaces == null) {
|
|
384 return Collections.EMPTY_LIST;
|
|
385 }
|
|
386 return Collections.unmodifiableList(additionalNamespaces);
|
|
387 }
|
|
388
|
|
389 /**
|
|
390 * Returns the XPath 1.0 string value of this element, which is the
|
|
391 * complete, ordered content of all text node descendants of this element
|
|
392 * (i.e. the text that's left after all references are resolved
|
|
393 * and all other markup is stripped out.)
|
|
394 *
|
|
395 * @return a concatentation of all text node descendants
|
|
396 */
|
|
397 public String getValue() {
|
|
398 final StringBuffer buffer = new StringBuffer();
|
|
399
|
|
400 final Iterator iter = getContent().iterator();
|
|
401 while (iter.hasNext()) {
|
|
402 final Content child = (Content) iter.next();
|
|
403 if (child instanceof Element || child instanceof Text) {
|
|
404 buffer.append(child.getValue());
|
|
405 }
|
|
406 }
|
|
407 return buffer.toString();
|
|
408 }
|
|
409
|
|
410 /**
|
|
411 * Returns whether this element is a root element. This can be used in
|
|
412 * tandem with {@link #getParent} to determine if an element has any
|
|
413 * "attachments" to a parent element or document.
|
|
414 *
|
|
415 * @return whether this is a root element
|
|
416 */
|
|
417 public boolean isRootElement() {
|
|
418 return parent instanceof Document;
|
|
419 }
|
|
420
|
|
421 public int getContentSize() {
|
|
422 return content.size();
|
|
423 }
|
|
424
|
|
425 public int indexOf(final Content child) {
|
|
426 return content.indexOf(child);
|
|
427 }
|
|
428
|
|
429 // private int indexOf(int start, Filter filter) {
|
|
430 // int size = getContentSize();
|
|
431 // for (int i = start; i < size; i++) {
|
|
432 // if (filter.matches(getContent(i))) {
|
|
433 // return i;
|
|
434 // }
|
|
435 // }
|
|
436 // return -1;
|
|
437 // }
|
|
438
|
|
439
|
|
440 /**
|
|
441 * Returns the textual content directly held under this element as a string.
|
|
442 * This includes all text within this single element, including whitespace
|
|
443 * and CDATA sections if they exist. It's essentially the concatenation of
|
|
444 * all {@link Text} and {@link CDATA} nodes returned by {@link #getContent}.
|
|
445 * The call does not recurse into child elements. If no textual value exists
|
|
446 * for the element, an empty string is returned.
|
|
447 *
|
|
448 * @return text content for this element, or empty
|
|
449 * string if none
|
|
450 */
|
|
451 public String getText() {
|
|
452 if (content.size() == 0) {
|
|
453 return "";
|
|
454 }
|
|
455
|
|
456 // If we hold only a Text or CDATA, return it directly
|
|
457 if (content.size() == 1) {
|
|
458 final Object obj = content.get(0);
|
|
459 if (obj instanceof Text) {
|
|
460 return ((Text) obj).getText();
|
|
461 }
|
|
462 else {
|
|
463 return "";
|
|
464 }
|
|
465 }
|
|
466
|
|
467 // Else build String up
|
|
468 final StringBuffer textContent = new StringBuffer();
|
|
469 boolean hasText = false;
|
|
470
|
|
471 for (int i = 0; i < content.size(); i++) {
|
|
472 final Object obj = content.get(i);
|
|
473 if (obj instanceof Text) {
|
|
474 textContent.append(((Text) obj).getText());
|
|
475 hasText = true;
|
|
476 }
|
|
477 }
|
|
478
|
|
479 if (!hasText) {
|
|
480 return "";
|
|
481 }
|
|
482 else {
|
|
483 return textContent.toString();
|
|
484 }
|
|
485 }
|
|
486
|
|
487 /**
|
|
488 * Returns the textual content of this element with all surrounding
|
|
489 * whitespace removed. If no textual value exists for the element, or if
|
|
490 * only whitespace exists, the empty string is returned.
|
|
491 *
|
|
492 * @return trimmed text content for this element, or
|
|
493 * empty string if none
|
|
494 */
|
|
495 public String getTextTrim() {
|
|
496 return getText().trim();
|
|
497 }
|
|
498
|
|
499 /**
|
|
500 * Returns the textual content of this element with all surrounding
|
|
501 * whitespace removed and internal whitespace normalized to a single space.
|
|
502 * If no textual value exists for the element, or if only whitespace exists,
|
|
503 * the empty string is returned.
|
|
504 *
|
|
505 * @return normalized text content for this element, or
|
|
506 * empty string if none
|
|
507 */
|
|
508 public String getTextNormalize() {
|
|
509 return Text.normalizeString(getText());
|
|
510 }
|
|
511
|
|
512 /**
|
|
513 * Returns the textual content of the named child element, or null if
|
|
514 * there's no such child. This method is a convenience because calling
|
|
515 * <code>getChild().getText()</code> can throw a NullPointerException.
|
|
516 *
|
|
517 * @param name the name of the child
|
|
518 * @return text content for the named child, or null if
|
|
519 * no such child
|
|
520 */
|
|
521 public String getChildText(final String name) {
|
|
522 final Element child = getChild(name);
|
|
523 if (child == null) {
|
|
524 return null;
|
|
525 }
|
|
526 return child.getText();
|
|
527 }
|
|
528
|
|
529 /**
|
|
530 * Returns the trimmed textual content of the named child element, or null
|
|
531 * if there's no such child. See <code>{@link #getTextTrim()}</code> for
|
|
532 * details of text trimming.
|
|
533 *
|
|
534 * @param name the name of the child
|
|
535 * @return trimmed text content for the named child, or
|
|
536 * null if no such child
|
|
537 */
|
|
538 public String getChildTextTrim(final String name) {
|
|
539 final Element child = getChild(name);
|
|
540 if (child == null) {
|
|
541 return null;
|
|
542 }
|
|
543 return child.getTextTrim();
|
|
544 }
|
|
545
|
|
546 /**
|
|
547 * Returns the normalized textual content of the named child element, or
|
|
548 * null if there's no such child. See <code>{@link
|
|
549 * #getTextNormalize()}</code> for details of text normalizing.
|
|
550 *
|
|
551 * @param name the name of the child
|
|
552 * @return normalized text content for the named child,
|
|
553 * or null if no such child
|
|
554 */
|
|
555 public String getChildTextNormalize(final String name) {
|
|
556 final Element child = getChild(name);
|
|
557 if (child == null) {
|
|
558 return null;
|
|
559 }
|
|
560 return child.getTextNormalize();
|
|
561 }
|
|
562
|
|
563 /**
|
|
564 * Returns the textual content of the named child element, or null if
|
|
565 * there's no such child.
|
|
566 *
|
|
567 * @param name the name of the child
|
|
568 * @param ns the namespace of the child
|
|
569 * @return text content for the named child, or null if
|
|
570 * no such child
|
|
571 */
|
|
572 public String getChildText(final String name, final Namespace ns) {
|
|
573 final Element child = getChild(name, ns);
|
|
574 if (child == null) {
|
|
575 return null;
|
|
576 }
|
|
577 return child.getText();
|
|
578 }
|
|
579
|
|
580 /**
|
|
581 * Returns the trimmed textual content of the named child element, or null
|
|
582 * if there's no such child.
|
|
583 *
|
|
584 * @param name the name of the child
|
|
585 * @param ns the namespace of the child
|
|
586 * @return trimmed text content for the named child, or
|
|
587 * null if no such child
|
|
588 */
|
|
589 public String getChildTextTrim(final String name, final Namespace ns) {
|
|
590 final Element child = getChild(name, ns);
|
|
591 if (child == null) {
|
|
592 return null;
|
|
593 }
|
|
594 return child.getTextTrim();
|
|
595 }
|
|
596
|
|
597 /**
|
|
598 * Returns the normalized textual content of the named child element, or
|
|
599 * null if there's no such child.
|
|
600 *
|
|
601 * @param name the name of the child
|
|
602 * @param ns the namespace of the child
|
|
603 * @return normalized text content for the named child,
|
|
604 * or null if no such child
|
|
605 */
|
|
606 public String getChildTextNormalize(final String name, final Namespace ns) {
|
|
607 final Element child = getChild(name, ns);
|
|
608 if (child == null) {
|
|
609 return null;
|
|
610 }
|
|
611 return child.getTextNormalize();
|
|
612 }
|
|
613
|
|
614 /**
|
|
615 * Sets the content of the element to be the text given. All existing text
|
|
616 * content and non-text context is removed. If this element should have both
|
|
617 * textual content and nested elements, use <code>{@link #setContent}</code>
|
|
618 * instead. Setting a null text value is equivalent to setting an empty
|
|
619 * string value.
|
|
620 *
|
|
621 * @param text new text content for the element
|
|
622 * @return the target element
|
|
623 * @throws IllegalDataException if the assigned text contains an illegal
|
|
624 * character such as a vertical tab (as
|
|
625 * determined by {@link
|
|
626 * org.jdom.Verifier#checkCharacterData})
|
|
627 */
|
|
628 public Element setText(final String text) {
|
|
629 content.clear();
|
|
630
|
|
631 if (text != null) {
|
|
632 addContent(new Text(text));
|
|
633 }
|
|
634
|
|
635 return this;
|
|
636 }
|
|
637
|
|
638 /**
|
|
639 * This returns the full content of the element as a List which
|
|
640 * may contain objects of type <code>Text</code>, <code>Element</code>,
|
|
641 * <code>Comment</code>, <code>ProcessingInstruction</code>,
|
|
642 * <code>CDATA</code>, and <code>EntityRef</code>.
|
|
643 * The List returned is "live" in document order and modifications
|
|
644 * to it affect the element's actual contents. Whitespace content is
|
|
645 * returned in its entirety.
|
|
646 *
|
|
647 * <p>
|
|
648 * Sequential traversal through the List is best done with an Iterator
|
|
649 * since the underlying implement of List.size() may require walking the
|
|
650 * entire list.
|
|
651 * </p>
|
|
652 *
|
|
653 * @return a <code>List</code> containing the mixed content of the
|
|
654 * element: may contain <code>Text</code>,
|
|
655 * <code>{@link Element}</code>, <code>{@link Comment}</code>,
|
|
656 * <code>{@link ProcessingInstruction}</code>,
|
|
657 * <code>{@link CDATA}</code>, and
|
|
658 * <code>{@link EntityRef}</code> objects.
|
|
659 */
|
|
660 public List getContent() {
|
|
661 return content;
|
|
662 }
|
|
663
|
|
664 /**
|
|
665 * Return a filter view of this <code>Element</code>'s content.
|
|
666 *
|
|
667 * <p>
|
|
668 * Sequential traversal through the List is best done with a Iterator
|
|
669 * since the underlying implement of List.size() may require walking the
|
|
670 * entire list.
|
|
671 * </p>
|
|
672 *
|
|
673 * @param filter <code>Filter</code> to apply
|
|
674 * @return <code>List</code> - filtered Element content
|
|
675 */
|
|
676 public List getContent(final Filter filter) {
|
|
677 return content.getView(filter);
|
|
678 }
|
|
679
|
|
680 /**
|
|
681 * Removes all child content from this parent.
|
|
682 *
|
|
683 * @return list of the old children detached from this parent
|
|
684 */
|
|
685 public List removeContent() {
|
|
686 final List old = new ArrayList(content);
|
|
687 content.clear();
|
|
688 return old;
|
|
689 }
|
|
690
|
|
691 /**
|
|
692 * Remove all child content from this parent matching the supplied filter.
|
|
693 *
|
|
694 * @param filter filter to select which content to remove
|
|
695 * @return list of the old children detached from this parent
|
|
696 */
|
|
697 public List removeContent(final Filter filter) {
|
|
698 final List old = new ArrayList();
|
|
699 final Iterator iter = content.getView(filter).iterator();
|
|
700 while (iter.hasNext()) {
|
|
701 final Content child = (Content) iter.next();
|
|
702 old.add(child);
|
|
703 iter.remove();
|
|
704 }
|
|
705 return old;
|
|
706 }
|
|
707
|
|
708 /**
|
|
709 * This sets the content of the element. The supplied List should
|
|
710 * contain only objects of type <code>Element</code>, <code>Text</code>,
|
|
711 * <code>CDATA</code>, <code>Comment</code>,
|
|
712 * <code>ProcessingInstruction</code>, and <code>EntityRef</code>.
|
|
713 *
|
|
714 * <p>
|
|
715 * When all objects in the supplied List are legal and before the new
|
|
716 * content is added, all objects in the old content will have their
|
|
717 * parentage set to null (no parent) and the old content list will be
|
|
718 * cleared. This has the effect that any active list (previously obtained
|
|
719 * with a call to {@link #getContent} or {@link #getChildren}) will also
|
|
720 * change to reflect the new content. In addition, all objects in the
|
|
721 * supplied List will have their parentage set to this element, but the
|
|
722 * List itself will not be "live" and further removals and additions will
|
|
723 * have no effect on this elements content. If the user wants to continue
|
|
724 * working with a "live" list, then a call to setContent should be
|
|
725 * followed by a call to {@link #getContent} or {@link #getChildren} to
|
|
726 * obtain a "live" version of the content.
|
|
727 * </p>
|
|
728 *
|
|
729 * <p>
|
|
730 * Passing a null or empty List clears the existing content.
|
|
731 * </p>
|
|
732 *
|
|
733 * <p>
|
|
734 * In event of an exception the original content will be unchanged and
|
|
735 * the objects in the supplied content will be unaltered.
|
|
736 * </p>
|
|
737 *
|
|
738 * @param newContent <code>Collection</code> of content to set
|
|
739 * @return this element modified
|
|
740 * @throws IllegalAddException if the List contains objects of
|
|
741 * illegal types or with existing parentage.
|
|
742 */
|
|
743 public Element setContent(final Collection newContent) {
|
|
744 content.clearAndSet(newContent);
|
|
745 return this;
|
|
746 }
|
|
747
|
|
748 /**
|
|
749 * Replace the current child the given index with the supplied child.
|
|
750 * <p>
|
|
751 * In event of an exception the original content will be unchanged and
|
|
752 * the supplied child will be unaltered.
|
|
753 * </p>
|
|
754 *
|
|
755 * @param index - index of child to replace.
|
|
756 * @param child - child to add.
|
|
757 * @return element on which this method was invoked
|
|
758 * @throws IllegalAddException if the supplied child is already attached
|
|
759 * or not legal content for this parent.
|
|
760 * @throws IndexOutOfBoundsException if index is negative or greater
|
|
761 * than the current number of children.
|
|
762 */
|
|
763 public Element setContent(final int index, final Content child) {
|
|
764 content.set(index, child);
|
|
765 return this;
|
|
766 }
|
|
767
|
|
768 /**
|
|
769 * Replace the child at the given index whith the supplied
|
|
770 * collection.
|
|
771 * <p>
|
|
772 * In event of an exception the original content will be unchanged and
|
|
773 * the content in the supplied collection will be unaltered.
|
|
774 * </p>
|
|
775 *
|
|
776 * @param index - index of child to replace.
|
|
777 * @param newContent - <code>Collection</code> of content to replace child.
|
|
778 * @return object on which this method was invoked
|
|
779 * @throws IllegalAddException if the collection contains objects of
|
|
780 * illegal types.
|
|
781 * @throws IndexOutOfBoundsException if index is negative or greater
|
|
782 * than the current number of children.
|
|
783 */
|
|
784 public Parent setContent(final int index, final Collection newContent) {
|
|
785 content.remove(index);
|
|
786 content.addAll(index, newContent);
|
|
787 return this;
|
|
788 }
|
|
789
|
|
790 /**
|
|
791 * This adds text content to this element. It does not replace the
|
|
792 * existing content as does <code>setText()</code>.
|
|
793 *
|
|
794 * @param str <code>String</code> to add
|
|
795 * @return this element modified
|
|
796 * @throws IllegalDataException if <code>str</code> contains an
|
|
797 * illegal character such as a vertical tab (as determined
|
|
798 * by {@link org.jdom.Verifier#checkCharacterData})
|
|
799 */
|
|
800 public Element addContent(final String str) {
|
|
801 return addContent(new Text(str));
|
|
802 }
|
|
803
|
|
804 /**
|
|
805 * Appends the child to the end of the element's content list.
|
|
806 *
|
|
807 * @param child child to append to end of content list
|
|
808 * @return the element on which the method was called
|
|
809 * @throws IllegalAddException if the given child already has a parent. */
|
|
810 public Element addContent(final Content child) {
|
|
811 content.add(child);
|
|
812 return this;
|
|
813 }
|
|
814
|
|
815 /**
|
|
816 * Appends all children in the given collection to the end of
|
|
817 * the content list. In event of an exception during add the
|
|
818 * original content will be unchanged and the objects in the supplied
|
|
819 * collection will be unaltered.
|
|
820 *
|
|
821 * @param newContent <code>Collection</code> of content to append
|
|
822 * @return the element on which the method was called
|
|
823 * @throws IllegalAddException if any item in the collection
|
|
824 * already has a parent or is of an inappropriate type.
|
|
825 */
|
|
826 public Element addContent(final Collection newContent) {
|
|
827 content.addAll(newContent);
|
|
828 return this;
|
|
829 }
|
|
830
|
|
831 /**
|
|
832 * Inserts the child into the content list at the given index.
|
|
833 *
|
|
834 * @param index location for adding the collection
|
|
835 * @param child child to insert
|
|
836 * @return the parent on which the method was called
|
|
837 * @throws IndexOutOfBoundsException if index is negative or beyond
|
|
838 * the current number of children
|
|
839 * @throws IllegalAddException if the given child already has a parent.
|
|
840 */
|
|
841 public Element addContent(final int index, final Content child) {
|
|
842 content.add(index, child);
|
|
843 return this;
|
|
844 }
|
|
845
|
|
846 /**
|
|
847 * Inserts the content in a collection into the content list
|
|
848 * at the given index. In event of an exception the original content
|
|
849 * will be unchanged and the objects in the supplied collection will be
|
|
850 * unaltered.
|
|
851 *
|
|
852 * @param index location for adding the collection
|
|
853 * @param newContent <code>Collection</code> of content to insert
|
|
854 * @return the parent on which the method was called
|
|
855 * @throws IndexOutOfBoundsException if index is negative or beyond
|
|
856 * the current number of children
|
|
857 * @throws IllegalAddException if any item in the collection
|
|
858 * already has a parent or is of an inappropriate type.
|
|
859 */
|
|
860 public Element addContent(final int index, final Collection newContent) {
|
|
861 content.addAll(index, newContent);
|
|
862 return this;
|
|
863 }
|
|
864
|
|
865 public List cloneContent() {
|
|
866 final int size = getContentSize();
|
|
867 final List list = new ArrayList(size);
|
|
868 for (int i = 0; i < size; i++) {
|
|
869 final Content child = getContent(i);
|
|
870 list.add(child.clone());
|
|
871 }
|
|
872 return list;
|
|
873 }
|
|
874
|
|
875 public Content getContent(final int index) {
|
|
876 return (Content) content.get(index);
|
|
877 }
|
|
878
|
|
879 // public Content getChild(Filter filter) {
|
|
880 // int i = indexOf(0, filter);
|
|
881 // return (i < 0) ? null : getContent(i);
|
|
882 // }
|
|
883
|
|
884 public boolean removeContent(final Content child) {
|
|
885 return content.remove(child);
|
|
886 }
|
|
887
|
|
888 public Content removeContent(final int index) {
|
|
889 return (Content) content.remove(index);
|
|
890 }
|
|
891
|
|
892 /**
|
|
893 * Set this element's content to be the supplied child.
|
|
894 * <p>
|
|
895 * If the supplied child is legal content for this parent and before
|
|
896 * it is added, all content in the current content list will
|
|
897 * be cleared and all current children will have their parentage set to
|
|
898 * null.
|
|
899 * <p>
|
|
900 * This has the effect that any active list (previously obtained with
|
|
901 * a call to one of the {@link #getContent} methods will also change
|
|
902 * to reflect the new content. In addition, all content in the supplied
|
|
903 * collection will have their parentage set to this parent. If the user
|
|
904 * wants to continue working with a <b>"live"</b> list of this parent's
|
|
905 * child, then a call to setContent should be followed by a call to one
|
|
906 * of the {@link #getContent} methods to obtain a <b>"live"</b>
|
|
907 * version of the children.
|
|
908 * <p>
|
|
909 * Passing a null child clears the existing content.
|
|
910 * <p>
|
|
911 * In event of an exception the original content will be unchanged and
|
|
912 * the supplied child will be unaltered.
|
|
913 *
|
|
914 * @param child new content to replace existing content
|
|
915 * @return the parent on which the method was called
|
|
916 * @throws IllegalAddException if the supplied child is already attached
|
|
917 * or not legal content for an Element
|
|
918 */
|
|
919 public Element setContent(final Content child) {
|
|
920 content.clear();
|
|
921 content.add(child);
|
|
922 return this;
|
|
923 }
|
|
924
|
|
925
|
|
926 /**
|
|
927 * Determines if this element is the ancestor of another element.
|
|
928 *
|
|
929 * @param element <code>Element</code> to check against
|
|
930 * @return <code>true</code> if this element is the ancestor of the
|
|
931 * supplied element
|
|
932 */
|
|
933 public boolean isAncestor(final Element element) {
|
|
934 Parent p = element.getParent();
|
|
935 while (p instanceof Element) {
|
|
936 if (p == this) {
|
|
937 return true;
|
|
938 }
|
|
939 p = p.getParent();
|
|
940 }
|
|
941 return false;
|
|
942 }
|
|
943
|
|
944 /**
|
|
945 * <p>
|
|
946 * This returns the complete set of attributes for this element, as a
|
|
947 * <code>List</code> of <code>Attribute</code> objects in no particular
|
|
948 * order, or an empty list if there are none.
|
|
949 * The returned list is "live" and changes to it affect the
|
|
950 * element's actual attributes.
|
|
951 * </p>
|
|
952 *
|
|
953 * @return attributes for the element
|
|
954 */
|
|
955 public List getAttributes() {
|
|
956 return attributes;
|
|
957 }
|
|
958
|
|
959 /**
|
|
960 * <p>
|
|
961 * This returns the attribute for this element with the given name
|
|
962 * and within no namespace, or null if no such attribute exists.
|
|
963 * </p>
|
|
964 *
|
|
965 * @param name name of the attribute to return
|
|
966 * @return attribute for the element
|
|
967 */
|
|
968 public Attribute getAttribute(final String name) {
|
|
969 return getAttribute(name, Namespace.NO_NAMESPACE);
|
|
970 }
|
|
971
|
|
972 /**
|
|
973 * <p>
|
|
974 * This returns the attribute for this element with the given name
|
|
975 * and within the given Namespace, or null if no such attribute exists.
|
|
976 * </p>
|
|
977 *
|
|
978 * @param name name of the attribute to return
|
|
979 * @param ns <code>Namespace</code> to search within
|
|
980 * @return attribute for the element
|
|
981 */
|
|
982 public Attribute getAttribute(final String name, final Namespace ns) {
|
|
983 return (Attribute) attributes.get(name, ns);
|
|
984 }
|
|
985
|
|
986 /**
|
|
987 * <p>
|
|
988 * This returns the attribute value for the attribute with the given name
|
|
989 * and within no namespace, null if there is no such attribute, and the
|
|
990 * empty string if the attribute value is empty.
|
|
991 * </p>
|
|
992 *
|
|
993 * @param name name of the attribute whose value to be returned
|
|
994 * @return the named attribute's value, or null if no such attribute
|
|
995 */
|
|
996 public String getAttributeValue(final String name) {
|
|
997 return getAttributeValue(name, Namespace.NO_NAMESPACE);
|
|
998 }
|
|
999
|
|
1000 /**
|
|
1001 * <p>
|
|
1002 * This returns the attribute value for the attribute with the given name
|
|
1003 * and within no namespace, or the passed-in default if there is no
|
|
1004 * such attribute.
|
|
1005 * </p>
|
|
1006 *
|
|
1007 * @param name name of the attribute whose value to be returned
|
|
1008 * @param def a default value to return if the attribute does not exist
|
|
1009 * @return the named attribute's value, or the default if no such attribute
|
|
1010 */
|
|
1011 public String getAttributeValue(final String name, final String def) {
|
|
1012 return getAttributeValue(name, Namespace.NO_NAMESPACE, def);
|
|
1013 }
|
|
1014
|
|
1015 /**
|
|
1016 * <p>
|
|
1017 * This returns the attribute value for the attribute with the given name
|
|
1018 * and within the given Namespace, null if there is no such attribute, and
|
|
1019 * the empty string if the attribute value is empty.
|
|
1020 * </p>
|
|
1021 *
|
|
1022 * @param name name of the attribute whose valud is to be returned
|
|
1023 * @param ns <code>Namespace</code> to search within
|
|
1024 * @return the named attribute's value, or null if no such attribute
|
|
1025 */
|
|
1026 public String getAttributeValue(final String name, final Namespace ns) {
|
|
1027 return getAttributeValue(name, ns, null);
|
|
1028 }
|
|
1029
|
|
1030 /**
|
|
1031 * <p>
|
|
1032 * This returns the attribute value for the attribute with the given name
|
|
1033 * and within the given Namespace, or the passed-in default if there is no
|
|
1034 * such attribute.
|
|
1035 * </p>
|
|
1036 *
|
|
1037 * @param name name of the attribute whose valud is to be returned
|
|
1038 * @param ns <code>Namespace</code> to search within
|
|
1039 * @param def a default value to return if the attribute does not exist
|
|
1040 * @return the named attribute's value, or the default if no such attribute
|
|
1041 */
|
|
1042 public String getAttributeValue(final String name, final Namespace ns, final String def) {
|
|
1043 final Attribute attribute = (Attribute) attributes.get(name, ns);
|
|
1044 if (attribute == null) {
|
|
1045 return def;
|
|
1046 }
|
|
1047
|
|
1048 return attribute.getValue();
|
|
1049 }
|
|
1050
|
|
1051 /**
|
|
1052 * <p>
|
|
1053 * This sets the attributes of the element. The supplied Collection should
|
|
1054 * contain only objects of type <code>Attribute</code>.
|
|
1055 * </p>
|
|
1056 *
|
|
1057 * <p>
|
|
1058 * When all objects in the supplied List are legal and before the new
|
|
1059 * attributes are added, all old attributes will have their
|
|
1060 * parentage set to null (no parent) and the old attribute list will be
|
|
1061 * cleared. This has the effect that any active attribute list (previously
|
|
1062 * obtained with a call to {@link #getAttributes}) will also change to
|
|
1063 * reflect the new attributes. In addition, all attributes in the supplied
|
|
1064 * List will have their parentage set to this element, but the List itself
|
|
1065 * will not be "live" and further removals and additions will have no
|
|
1066 * effect on this elements attributes. If the user wants to continue
|
|
1067 * working with a "live" attribute list, then a call to setAttributes
|
|
1068 * should be followed by a call to {@link #getAttributes} to obtain a
|
|
1069 * "live" version of the attributes.
|
|
1070 * </p>
|
|
1071 *
|
|
1072 * <p>
|
|
1073 * Passing a null or empty List clears the existing attributes.
|
|
1074 * </p>
|
|
1075 *
|
|
1076 * <p>
|
|
1077 * In cases where the List contains duplicate attributes, only the last
|
|
1078 * one will be retained. This has the same effect as calling
|
|
1079 * {@link #setAttribute(Attribute)} sequentially.
|
|
1080 * </p>
|
|
1081 *
|
|
1082 * <p>
|
|
1083 * In event of an exception the original attributes will be unchanged and
|
|
1084 * the attributes in the supplied attributes will be unaltered.
|
|
1085 * </p>
|
|
1086 *
|
|
1087 * @param newAttributes <code>Collection</code> of attributes to set
|
|
1088 * @return this element modified
|
|
1089 * @throws IllegalAddException if the List contains objects
|
|
1090 * that are not instances of <code>Attribute</code>,
|
|
1091 * or if any of the <code>Attribute</code> objects have
|
|
1092 * conflicting namespace prefixes.
|
|
1093 */
|
|
1094 public Element setAttributes(final Collection newAttributes) {
|
|
1095 attributes.clearAndSet(newAttributes);
|
|
1096 return this;
|
|
1097 }
|
|
1098
|
|
1099 /**
|
|
1100 * <p>
|
|
1101 * This sets the attributes of the element. It's an alternate form of
|
|
1102 * the method, accepting a <code>List</code> instead of a
|
|
1103 * <code>Collection</code>, for backward compatibility.
|
|
1104 * </p>
|
|
1105 */
|
|
1106 public Element setAttributes(final List newAttributes) {
|
|
1107 return setAttributes((Collection)newAttributes);
|
|
1108 }
|
|
1109
|
|
1110 /**
|
|
1111 * <p>
|
|
1112 * This sets an attribute value for this element. Any existing attribute
|
|
1113 * with the same name and namespace URI is removed.
|
|
1114 * </p>
|
|
1115 *
|
|
1116 * @param name name of the attribute to set
|
|
1117 * @param value value of the attribute to set
|
|
1118 * @return this element modified
|
|
1119 * @throws IllegalNameException if the given name is illegal as an
|
|
1120 * attribute name.
|
|
1121 * @throws IllegalDataException if the given attribute value is
|
|
1122 * illegal character data (as determined by
|
|
1123 * {@link org.jdom.Verifier#checkCharacterData}).
|
|
1124 */
|
|
1125 public Element setAttribute(final String name, final String value) {
|
|
1126 final Attribute attribute = getAttribute(name);
|
|
1127 if (attribute == null) {
|
|
1128 final Attribute newAttribute = new Attribute(name, value);
|
|
1129 setAttribute(newAttribute);
|
|
1130 } else {
|
|
1131 attribute.setValue(value);
|
|
1132 }
|
|
1133
|
|
1134 return this;
|
|
1135 }
|
|
1136
|
|
1137 /**
|
|
1138 * <p>
|
|
1139 * This sets an attribute value for this element. Any existing attribute
|
|
1140 * with the same name and namespace URI is removed.
|
|
1141 * </p>
|
|
1142 *
|
|
1143 * @param name name of the attribute to set
|
|
1144 * @param value value of the attribute to set
|
|
1145 * @param ns namespace of the attribute to set
|
|
1146 * @return this element modified
|
|
1147 * @throws IllegalNameException if the given name is illegal as an
|
|
1148 * attribute name, or if the namespace is an unprefixed default
|
|
1149 * namespace
|
|
1150 * @throws IllegalDataException if the given attribute value is
|
|
1151 * illegal character data (as determined by
|
|
1152 * {@link org.jdom.Verifier#checkCharacterData}).
|
|
1153 * @throws IllegalAddException if the attribute namespace prefix
|
|
1154 * collides with another namespace prefix on the element.
|
|
1155 */
|
|
1156 public Element setAttribute(final String name, final String value, final Namespace ns) {
|
|
1157 final Attribute attribute = getAttribute(name, ns);
|
|
1158 if (attribute == null) {
|
|
1159 final Attribute newAttribute = new Attribute(name, value, ns);
|
|
1160 setAttribute(newAttribute);
|
|
1161 } else {
|
|
1162 attribute.setValue(value);
|
|
1163 }
|
|
1164
|
|
1165 return this;
|
|
1166 }
|
|
1167
|
|
1168 /**
|
|
1169 * <p>
|
|
1170 * This sets an attribute value for this element. Any existing attribute
|
|
1171 * with the same name and namespace URI is removed.
|
|
1172 * </p>
|
|
1173 *
|
|
1174 * @param attribute <code>Attribute</code> to set
|
|
1175 * @return this element modified
|
|
1176 * @throws IllegalAddException if the attribute being added already has a
|
|
1177 * parent or if the attribute namespace prefix collides with another
|
|
1178 * namespace prefix on the element.
|
|
1179 */
|
|
1180 public Element setAttribute(final Attribute attribute) {
|
|
1181 attributes.add(attribute);
|
|
1182 return this;
|
|
1183 }
|
|
1184
|
|
1185 /**
|
|
1186 * <p>
|
|
1187 * This removes the attribute with the given name and within no
|
|
1188 * namespace. If no such attribute exists, this method does nothing.
|
|
1189 * </p>
|
|
1190 *
|
|
1191 * @param name name of attribute to remove
|
|
1192 * @return whether the attribute was removed
|
|
1193 */
|
|
1194 public boolean removeAttribute(final String name) {
|
|
1195 return removeAttribute(name, Namespace.NO_NAMESPACE);
|
|
1196 }
|
|
1197
|
|
1198 /**
|
|
1199 * <p>
|
|
1200 * This removes the attribute with the given name and within the
|
|
1201 * given Namespace. If no such attribute exists, this method does
|
|
1202 * nothing.
|
|
1203 * </p>
|
|
1204 *
|
|
1205 * @param name name of attribute to remove
|
|
1206 * @param ns namespace URI of attribute to remove
|
|
1207 * @return whether the attribute was removed
|
|
1208 */
|
|
1209 public boolean removeAttribute(final String name, final Namespace ns) {
|
|
1210 return attributes.remove(name, ns);
|
|
1211 }
|
|
1212
|
|
1213 /**
|
|
1214 * <p>
|
|
1215 * This removes the supplied Attribute should it exist.
|
|
1216 * </p>
|
|
1217 *
|
|
1218 * @param attribute Reference to the attribute to be removed.
|
|
1219 * @return whether the attribute was removed
|
|
1220 */
|
|
1221 public boolean removeAttribute(final Attribute attribute) {
|
|
1222 return attributes.remove(attribute);
|
|
1223 }
|
|
1224
|
|
1225 /**
|
|
1226 * <p>
|
|
1227 * This returns a <code>String</code> representation of the
|
|
1228 * <code>Element</code>, suitable for debugging. If the XML
|
|
1229 * representation of the <code>Element</code> is desired,
|
|
1230 * {@link org.jdom.output.XMLOutputter#outputString(Element)}
|
|
1231 * should be used.
|
|
1232 * </p>
|
|
1233 *
|
|
1234 * @return <code>String</code> - information about the
|
|
1235 * <code>Element</code>
|
|
1236 */
|
|
1237 public String toString() {
|
|
1238 final StringBuffer stringForm = new StringBuffer(64)
|
|
1239 .append("[Element: <")
|
|
1240 .append(getQualifiedName());
|
|
1241
|
|
1242 final String nsuri = getNamespaceURI();
|
|
1243 if (!"".equals(nsuri)) {
|
|
1244 stringForm
|
|
1245 .append(" [Namespace: ")
|
|
1246 .append(nsuri)
|
|
1247 .append("]");
|
|
1248 }
|
|
1249 stringForm.append("/>]");
|
|
1250
|
|
1251 return stringForm.toString();
|
|
1252 }
|
|
1253
|
|
1254 /**
|
|
1255 * <p>
|
|
1256 * This returns a deep clone of this element.
|
|
1257 * The new element is detached from its parent, and getParent()
|
|
1258 * on the clone will return null.
|
|
1259 * </p>
|
|
1260 *
|
|
1261 * @return the clone of this element
|
|
1262 */
|
|
1263 public Object clone() {
|
|
1264
|
|
1265 // Ken Rune Helland <kenh@csc.no> is our local clone() guru
|
|
1266
|
|
1267 final Element element = (Element) super.clone();
|
|
1268
|
|
1269 // name and namespace are references to immutable objects
|
|
1270 // so super.clone() handles them ok
|
|
1271
|
|
1272 // Reference to parent is copied by super.clone()
|
|
1273 // (Object.clone()) so we have to remove it
|
|
1274 // Actually, super is a Content, which has already detached in the
|
|
1275 // clone().
|
|
1276 // element.parent = null;
|
|
1277
|
|
1278 // Reference to content list and attribute lists are copyed by
|
|
1279 // super.clone() so we set it new lists if the original had lists
|
|
1280 element.content = new ContentList(element);
|
|
1281 element.attributes = new AttributeList(element);
|
|
1282
|
|
1283 // Cloning attributes
|
|
1284 if (attributes != null) {
|
|
1285 for(int i = 0; i < attributes.size(); i++) {
|
|
1286 final Attribute attribute = (Attribute) attributes.get(i);
|
|
1287 element.attributes.add(attribute.clone());
|
|
1288 }
|
|
1289 }
|
|
1290
|
|
1291 // Cloning additional namespaces
|
|
1292 if (additionalNamespaces != null) {
|
|
1293 element.additionalNamespaces = new ArrayList(additionalNamespaces);
|
|
1294 }
|
|
1295
|
|
1296 // Cloning content
|
|
1297 if (content != null) {
|
|
1298 for(int i = 0; i < content.size(); i++) {
|
|
1299 final Content c = (Content) content.get(i);
|
|
1300 element.content.add(c.clone());
|
|
1301 }
|
|
1302 }
|
|
1303
|
|
1304 return element;
|
|
1305 }
|
|
1306
|
|
1307
|
|
1308 // Support a custom Namespace serialization so no two namespace
|
|
1309 // object instances may exist for the same prefix/uri pair
|
|
1310 private void writeObject(final ObjectOutputStream out) throws IOException {
|
|
1311
|
|
1312 out.defaultWriteObject();
|
|
1313
|
|
1314 // We use writeObject() and not writeUTF() to minimize space
|
|
1315 // This allows for writing pointers to already written strings
|
|
1316 out.writeObject(namespace.getPrefix());
|
|
1317 out.writeObject(namespace.getURI());
|
|
1318
|
|
1319 if (additionalNamespaces == null) {
|
|
1320 out.write(0);
|
|
1321 }
|
|
1322 else {
|
|
1323 final int size = additionalNamespaces.size();
|
|
1324 out.write(size);
|
|
1325 for (int i = 0; i < size; i++) {
|
|
1326 final Namespace additional = (Namespace) additionalNamespaces.get(i);
|
|
1327 out.writeObject(additional.getPrefix());
|
|
1328 out.writeObject(additional.getURI());
|
|
1329 }
|
|
1330 }
|
|
1331 }
|
|
1332
|
|
1333 private void readObject(final ObjectInputStream in)
|
|
1334 throws IOException, ClassNotFoundException {
|
|
1335
|
|
1336 in.defaultReadObject();
|
|
1337
|
|
1338 namespace = Namespace.getNamespace(
|
|
1339 (String)in.readObject(), (String)in.readObject());
|
|
1340
|
|
1341 final int size = in.read();
|
|
1342
|
|
1343 if (size != 0) {
|
|
1344 additionalNamespaces = new ArrayList(size);
|
|
1345 for (int i = 0; i < size; i++) {
|
|
1346 final Namespace additional = Namespace.getNamespace(
|
|
1347 (String)in.readObject(), (String)in.readObject());
|
|
1348 additionalNamespaces.add(additional);
|
|
1349 }
|
|
1350 }
|
|
1351 }
|
|
1352
|
|
1353 /**
|
|
1354 * Returns an iterator that walks over all descendants in document order.
|
|
1355 *
|
|
1356 * @return an iterator to walk descendants
|
|
1357 */
|
|
1358 public Iterator getDescendants() {
|
|
1359 return new DescendantIterator(this);
|
|
1360 }
|
|
1361
|
|
1362 /**
|
|
1363 * Returns an iterator that walks over all descendants in document order
|
|
1364 * applying the Filter to return only elements that match the filter rule.
|
|
1365 * With filters you can match only Elements, only Comments, Elements or
|
|
1366 * Comments, only Elements with a given name and/or prefix, and so on.
|
|
1367 *
|
|
1368 * @param filter filter to select which descendants to see
|
|
1369 * @return an iterator to walk descendants within a filter
|
|
1370 */
|
|
1371 public Iterator getDescendants(final Filter filter) {
|
|
1372 final Iterator iterator = new DescendantIterator(this);
|
|
1373 return new FilterIterator(iterator, filter);
|
|
1374 }
|
|
1375
|
|
1376
|
|
1377
|
|
1378 /**
|
|
1379 * This returns a <code>List</code> of all the child elements
|
|
1380 * nested directly (one level deep) within this element, as
|
|
1381 * <code>Element</code> objects. If this target element has no nested
|
|
1382 * elements, an empty List is returned. The returned list is "live"
|
|
1383 * in document order and changes to it affect the element's actual
|
|
1384 * contents.
|
|
1385 *
|
|
1386 * <p>
|
|
1387 * Sequential traversal through the List is best done with a Iterator
|
|
1388 * since the underlying implement of List.size() may not be the most
|
|
1389 * efficient.
|
|
1390 * </p>
|
|
1391 *
|
|
1392 * <p>
|
|
1393 * No recursion is performed, so elements nested two levels deep
|
|
1394 * would have to be obtained with:
|
|
1395 * <pre>
|
|
1396 * <code>
|
|
1397 * Iterator itr = (currentElement.getChildren()).iterator();
|
|
1398 * while(itr.hasNext()) {
|
|
1399 * Element oneLevelDeep = (Element)itr.next();
|
|
1400 * List twoLevelsDeep = oneLevelDeep.getChildren();
|
|
1401 * // Do something with these children
|
|
1402 * }
|
|
1403 * </code>
|
|
1404 * </pre>
|
|
1405 * </p>
|
|
1406 *
|
|
1407 * @return list of child <code>Element</code> objects for this element
|
|
1408 */
|
|
1409 public List getChildren() {
|
|
1410 return content.getView(new ElementFilter());
|
|
1411 }
|
|
1412
|
|
1413 /**
|
|
1414 * This returns a <code>List</code> of all the child elements
|
|
1415 * nested directly (one level deep) within this element with the given
|
|
1416 * local name and belonging to no namespace, returned as
|
|
1417 * <code>Element</code> objects. If this target element has no nested
|
|
1418 * elements with the given name outside a namespace, an empty List
|
|
1419 * is returned. The returned list is "live" in document order
|
|
1420 * and changes to it affect the element's actual contents.
|
|
1421 * <p>
|
|
1422 * Please see the notes for <code>{@link #getChildren}</code>
|
|
1423 * for a code example.
|
|
1424 * </p>
|
|
1425 *
|
|
1426 * @param name local name for the children to match
|
|
1427 * @return all matching child elements
|
|
1428 */
|
|
1429 public List getChildren(final String name) {
|
|
1430 return getChildren(name, Namespace.NO_NAMESPACE);
|
|
1431 }
|
|
1432
|
|
1433 /**
|
|
1434 * This returns a <code>List</code> of all the child elements
|
|
1435 * nested directly (one level deep) within this element with the given
|
|
1436 * local name and belonging to the given Namespace, returned as
|
|
1437 * <code>Element</code> objects. If this target element has no nested
|
|
1438 * elements with the given name in the given Namespace, an empty List
|
|
1439 * is returned. The returned list is "live" in document order
|
|
1440 * and changes to it affect the element's actual contents.
|
|
1441 * <p>
|
|
1442 * Please see the notes for <code>{@link #getChildren}</code>
|
|
1443 * for a code example.
|
|
1444 * </p>
|
|
1445 *
|
|
1446 * @param name local name for the children to match
|
|
1447 * @param ns <code>Namespace</code> to search within
|
|
1448 * @return all matching child elements
|
|
1449 */
|
|
1450 public List getChildren(final String name, final Namespace ns) {
|
|
1451 return content.getView(new ElementFilter(name, ns));
|
|
1452 }
|
|
1453
|
|
1454 /**
|
|
1455 * This returns the first child element within this element with the
|
|
1456 * given local name and belonging to the given namespace.
|
|
1457 * If no elements exist for the specified name and namespace, null is
|
|
1458 * returned.
|
|
1459 *
|
|
1460 * @param name local name of child element to match
|
|
1461 * @param ns <code>Namespace</code> to search within
|
|
1462 * @return the first matching child element, or null if not found
|
|
1463 */
|
|
1464 public Element getChild(final String name, final Namespace ns) {
|
|
1465 final List elements = content.getView(new ElementFilter(name, ns));
|
|
1466 final Iterator iter = elements.iterator();
|
|
1467 if (iter.hasNext()) {
|
|
1468 return (Element) iter.next();
|
|
1469 }
|
|
1470 return null;
|
|
1471 }
|
|
1472
|
|
1473 /**
|
|
1474 * This returns the first child element within this element with the
|
|
1475 * given local name and belonging to no namespace.
|
|
1476 * If no elements exist for the specified name and namespace, null is
|
|
1477 * returned.
|
|
1478 *
|
|
1479 * @param name local name of child element to match
|
|
1480 * @return the first matching child element, or null if not found
|
|
1481 */
|
|
1482 public Element getChild(final String name) {
|
|
1483 return getChild(name, Namespace.NO_NAMESPACE);
|
|
1484 }
|
|
1485
|
|
1486 /**
|
|
1487 * <p>
|
|
1488 * This removes the first child element (one level deep) with the
|
|
1489 * given local name and belonging to no namespace.
|
|
1490 * Returns true if a child was removed.
|
|
1491 * </p>
|
|
1492 *
|
|
1493 * @param name the name of child elements to remove
|
|
1494 * @return whether deletion occurred
|
|
1495 */
|
|
1496 public boolean removeChild(final String name) {
|
|
1497 return removeChild(name, Namespace.NO_NAMESPACE);
|
|
1498 }
|
|
1499
|
|
1500 /**
|
|
1501 * <p>
|
|
1502 * This removes the first child element (one level deep) with the
|
|
1503 * given local name and belonging to the given namespace.
|
|
1504 * Returns true if a child was removed.
|
|
1505 * </p>
|
|
1506 *
|
|
1507 * @param name the name of child element to remove
|
|
1508 * @param ns <code>Namespace</code> to search within
|
|
1509 * @return whether deletion occurred
|
|
1510 */
|
|
1511 public boolean removeChild(final String name, final Namespace ns) {
|
|
1512 final Filter filter = new ElementFilter(name, ns);
|
|
1513 final List old = content.getView(filter);
|
|
1514 final Iterator iter = old.iterator();
|
|
1515 if (iter.hasNext()) {
|
|
1516 iter.next();
|
|
1517 iter.remove();
|
|
1518 return true;
|
|
1519 }
|
|
1520
|
|
1521 return false;
|
|
1522 }
|
|
1523
|
|
1524 /**
|
|
1525 * <p>
|
|
1526 * This removes all child elements (one level deep) with the
|
|
1527 * given local name and belonging to no namespace.
|
|
1528 * Returns true if any were removed.
|
|
1529 * </p>
|
|
1530 *
|
|
1531 * @param name the name of child elements to remove
|
|
1532 * @return whether deletion occurred
|
|
1533 */
|
|
1534 public boolean removeChildren(final String name) {
|
|
1535 return removeChildren(name, Namespace.NO_NAMESPACE);
|
|
1536 }
|
|
1537
|
|
1538 /**
|
|
1539 * <p>
|
|
1540 * This removes all child elements (one level deep) with the
|
|
1541 * given local name and belonging to the given namespace.
|
|
1542 * Returns true if any were removed.
|
|
1543 * </p>
|
|
1544 *
|
|
1545 * @param name the name of child elements to remove
|
|
1546 * @param ns <code>Namespace</code> to search within
|
|
1547 * @return whether deletion occurred
|
|
1548 */
|
|
1549 public boolean removeChildren(final String name, final Namespace ns) {
|
|
1550 boolean deletedSome = false;
|
|
1551
|
|
1552 final Filter filter = new ElementFilter(name, ns);
|
|
1553 final List old = content.getView(filter);
|
|
1554 final Iterator iter = old.iterator();
|
|
1555 while (iter.hasNext()) {
|
|
1556 iter.next();
|
|
1557 iter.remove();
|
|
1558 deletedSome = true;
|
|
1559 }
|
|
1560
|
|
1561 return deletedSome;
|
|
1562 }
|
|
1563
|
|
1564 }
|