| 
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 }
 |