Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/jdom/Element.java


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