0001: /*--
0002:
0003: $Id: Element.java,v 1.2 2005/05/03 07:02:04 wittek Exp $
0004:
0005: Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
0006: All rights reserved.
0007:
0008: Redistribution and use in source and binary forms, with or without
0009: modification, are permitted provided that the following conditions
0010: are met:
0011:
0012: 1. Redistributions of source code must retain the above copyright
0013: notice, this list of conditions, and the following disclaimer.
0014:
0015: 2. Redistributions in binary form must reproduce the above copyright
0016: notice, this list of conditions, and the disclaimer that follows
0017: these conditions in the documentation and/or other materials
0018: provided with the distribution.
0019:
0020: 3. The name "JDOM" must not be used to endorse or promote products
0021: derived from this software without prior written permission. For
0022: written permission, please contact <request_AT_jdom_DOT_org>.
0023:
0024: 4. Products derived from this software may not be called "JDOM", nor
0025: may "JDOM" appear in their name, without prior written permission
0026: from the JDOM Project Management <request_AT_jdom_DOT_org>.
0027:
0028: In addition, we request (but do not require) that you include in the
0029: end-user documentation provided with the redistribution and/or in the
0030: software itself an acknowledgement equivalent to the following:
0031: "This product includes software developed by the
0032: JDOM Project (http://www.jdom.org/)."
0033: Alternatively, the acknowledgment may be graphical using the logos
0034: available at http://www.jdom.org/images/logos.
0035:
0036: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0037: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0038: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0039: DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
0040: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0041: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0042: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0043: USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0044: ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0045: OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0046: OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0047: SUCH DAMAGE.
0048:
0049: This software consists of voluntary contributions made by many
0050: individuals on behalf of the JDOM Project and was originally
0051: created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
0052: Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
0053: on the JDOM Project, please see <http://www.jdom.org/>.
0054:
0055: */
0056:
0057: package org.jdom;
0058:
0059: import java.io.*;
0060: import java.util.*;
0061:
0062: import org.jdom.filter.*;
0063:
0064: /**
0065: * An XML element. Methods allow the user to get and manipulate its child
0066: * elements and content, directly access the element's textual content,
0067: * manipulate its attributes, and manage namespaces.
0068: *
0069: * @version $Revision: 1.2 $, $Date: 2005/05/03 07:02:04 $
0070: * @author Brett McLaughlin
0071: * @author Jason Hunter
0072: * @author Lucas Gonze
0073: * @author Kevin Regan
0074: * @author Dan Schaffer
0075: * @author Yusuf Goolamabbas
0076: * @author Kent C. Johnson
0077: * @author Jools Enticknap
0078: * @author Alex Rosen
0079: * @author Bradley S. Huffman
0080: */
0081: public class Element extends Content implements Parent {
0082:
0083: private static final String CVS_ID = "@(#) $RCSfile: Element.java,v $ $Revision: 1.2 $ $Date: 2005/05/03 07:02:04 $ $Name: $";
0084:
0085: private static final int INITIAL_ARRAY_SIZE = 5;
0086:
0087: /** The local name of the element */
0088: protected String name;
0089:
0090: /** The namespace of the element */
0091: protected transient Namespace namespace;
0092:
0093: /** Additional namespace declarations to store on this element; useful
0094: * during output */
0095: protected transient List additionalNamespaces;
0096:
0097: // See http://lists.denveronline.net/lists/jdom-interest/2000-September/003030.html
0098: // for a possible memory optimization here (using a RootElement subclass)
0099:
0100: /**
0101: * The attributes of the element. Subclassers have to
0102: * track attributes using their own mechanism.
0103: */
0104: AttributeList attributes = new AttributeList(this );
0105:
0106: /**
0107: * The content of the element. Subclassers have to
0108: * track content using their own mechanism.
0109: */
0110: ContentList content = new ContentList(this );
0111:
0112: /**
0113: * This protected constructor is provided in order to support an Element
0114: * subclass that wants full control over variable initialization. It
0115: * intentionally leaves all instance variables null, allowing a lightweight
0116: * subclass implementation. The subclass is responsible for ensuring all the
0117: * get and set methods on Element behave as documented.
0118: * <p>
0119: * When implementing an Element subclass which doesn't require full control
0120: * over variable initialization, be aware that simply calling super() (or
0121: * letting the compiler add the implicit super() call) will not initialize
0122: * the instance variables which will cause many of the methods to throw a
0123: * NullPointerException. Therefore, the constructor for these subclasses
0124: * should call one of the public constructors so variable initialization is
0125: * handled automatically.
0126: */
0127: protected Element() {
0128: }
0129:
0130: /**
0131: * Creates a new element with the supplied (local) name and namespace. If
0132: * the provided namespace is null, the element will have no namespace.
0133: *
0134: * @param name local name of the element
0135: * @param namespace namespace for the element
0136: * @throws IllegalNameException if the given name is illegal as an element
0137: * name
0138: */
0139: public Element(String name, Namespace namespace) {
0140: setName(name);
0141: setNamespace(namespace);
0142: }
0143:
0144: /**
0145: * Create a new element with the supplied (local) name and no namespace.
0146: *
0147: * @param name local name of the element
0148: * @throws IllegalNameException if the given name is illegal as an element
0149: * name.
0150: */
0151: public Element(String name) {
0152: this (name, (Namespace) null);
0153: }
0154:
0155: /**
0156: * Creates a new element with the supplied (local) name and a namespace
0157: * given by a URI. The element will be put into the unprefixed (default)
0158: * namespace.
0159: *
0160: * @param name name of the element
0161: * @param uri namespace URI for the element
0162: * @throws IllegalNameException if the given name is illegal as an element
0163: * name or the given URI is illegal as a
0164: * namespace URI
0165: */
0166: public Element(String name, String uri) {
0167: this (name, Namespace.getNamespace("", uri));
0168: }
0169:
0170: /**
0171: * Creates a new element with the supplied (local) name and a namespace
0172: * given by the supplied prefix and URI combination.
0173: *
0174: * @param name local name of the element
0175: * @param prefix namespace prefix
0176: * @param uri namespace URI for the element
0177: * @throws IllegalNameException if the given name is illegal as an element
0178: * name, the given prefix is illegal as a
0179: * namespace prefix, or the given URI is
0180: * illegal as a namespace URI
0181: */
0182: public Element(String name, String prefix, String uri) {
0183: this (name, Namespace.getNamespace(prefix, uri));
0184: }
0185:
0186: /**
0187: * Returns the (local) name of the element (without any namespace prefix).
0188: *
0189: * @return local element name
0190: */
0191: public String getName() {
0192: return name;
0193: }
0194:
0195: /**
0196: * Sets the (local) name of the element.
0197: *
0198: * @param name the new (local) name of the element
0199: * @return the target element
0200: * @throws IllegalNameException if the given name is illegal as an Element
0201: * name
0202: */
0203: public Element setName(String name) {
0204: String reason = Verifier.checkElementName(name);
0205: if (reason != null) {
0206: throw new IllegalNameException(name, "element", reason);
0207: }
0208: this .name = name;
0209: return this ;
0210: }
0211:
0212: /**
0213: * Returns the element's {@link Namespace}.
0214: *
0215: * @return the element's namespace
0216: */
0217: public Namespace getNamespace() {
0218: return namespace;
0219: }
0220:
0221: /**
0222: * Sets the element's {@link Namespace}. If the provided namespace is null,
0223: * the element will have no namespace.
0224: *
0225: * @param namespace the new namespace
0226: * @return the target element
0227: */
0228: public Element setNamespace(Namespace namespace) {
0229: if (namespace == null) {
0230: namespace = Namespace.NO_NAMESPACE;
0231: }
0232:
0233: this .namespace = namespace;
0234: return this ;
0235: }
0236:
0237: /**
0238: * Returns the namespace prefix of the element or an empty string if none
0239: * exists.
0240: *
0241: * @return the namespace prefix
0242: */
0243: public String getNamespacePrefix() {
0244: return namespace.getPrefix();
0245: }
0246:
0247: /**
0248: * Returns the namespace URI mapped to this element's prefix (or the
0249: * in-scope default namespace URI if no prefix). If no mapping is found, an
0250: * empty string is returned.
0251: *
0252: * @return the namespace URI for this element
0253: */
0254: public String getNamespaceURI() {
0255: return namespace.getURI();
0256: }
0257:
0258: /**
0259: * Returns the {@link Namespace} corresponding to the given prefix in scope
0260: * for this element. This involves searching up the tree, so the results
0261: * depend on the current location of the element. Returns null if there is
0262: * no namespace in scope with the given prefix at this point in the
0263: * document.
0264: *
0265: * @param prefix namespace prefix to look up
0266: * @return the Namespace for this prefix at this
0267: * location, or null if none
0268: */
0269: public Namespace getNamespace(String prefix) {
0270: if (prefix == null) {
0271: return null;
0272: }
0273:
0274: if (prefix.equals("xml")) {
0275: // Namespace "xml" is always bound.
0276: return Namespace.XML_NAMESPACE;
0277: }
0278:
0279: // Check if the prefix is the prefix for this element
0280: if (prefix.equals(getNamespacePrefix())) {
0281: return getNamespace();
0282: }
0283:
0284: // Scan the additional namespaces
0285: if (additionalNamespaces != null) {
0286: for (int i = 0; i < additionalNamespaces.size(); i++) {
0287: Namespace ns = (Namespace) additionalNamespaces.get(i);
0288: if (prefix.equals(ns.getPrefix())) {
0289: return ns;
0290: }
0291: }
0292: }
0293:
0294: // If we still don't have a match, ask the parent
0295: if (parent instanceof Element) {
0296: return ((Element) parent).getNamespace(prefix);
0297: }
0298:
0299: return null;
0300: }
0301:
0302: /**
0303: * Returns the full name of the element, in the form
0304: * [namespacePrefix]:[localName]. If the element does not have a namespace
0305: * prefix, then the local name is returned.
0306: *
0307: * @return qualified name of the element (including
0308: * namespace prefix)
0309: */
0310: public String getQualifiedName() {
0311: // Note: Any changes here should be reflected in
0312: // XMLOutputter.printQualifiedName()
0313: if (namespace.getPrefix().equals("")) {
0314: return getName();
0315: }
0316:
0317: return new StringBuffer(namespace.getPrefix()).append(':')
0318: .append(name).toString();
0319: }
0320:
0321: /**
0322: * Adds a namespace declarations to this element. This should <i>not</i> be
0323: * used to add the declaration for this element itself; that should be
0324: * assigned in the construction of the element. Instead, this is for adding
0325: * namespace declarations on the element not relating directly to itself.
0326: * It's used during output to for stylistic reasons move namespace
0327: * declarations higher in the tree than they would have to be.
0328: *
0329: * @param additional namespace to add
0330: * @throws IllegalAddException if the namespace prefix collides with another
0331: * namespace prefix on the element
0332: */
0333: public void addNamespaceDeclaration(Namespace additional) {
0334:
0335: // Verify the new namespace prefix doesn't collide with another
0336: // declared namespace, an attribute prefix, or this element's prefix
0337: String reason = Verifier.checkNamespaceCollision(additional,
0338: this );
0339: if (reason != null) {
0340: throw new IllegalAddException(this , additional, reason);
0341: }
0342:
0343: if (additionalNamespaces == null) {
0344: additionalNamespaces = new ArrayList(INITIAL_ARRAY_SIZE);
0345: }
0346:
0347: additionalNamespaces.add(additional);
0348: }
0349:
0350: /**
0351: * Removes an additional namespace declarations from this element. This
0352: * should <i>not</i> be used to remove the declaration for this element
0353: * itself; that should be handled in the construction of the element.
0354: * Instead, this is for removing namespace declarations on the element not
0355: * relating directly to itself. If the declaration is not present, this
0356: * method does nothing.
0357: *
0358: * @param additionalNamespace namespace to remove
0359: */
0360: public void removeNamespaceDeclaration(Namespace additionalNamespace) {
0361: if (additionalNamespaces == null) {
0362: return;
0363: }
0364: additionalNamespaces.remove(additionalNamespace);
0365: }
0366:
0367: /**
0368: * Returns a list of the additional namespace declarations on this element.
0369: * This includes only additional namespace, not the namespace of the element
0370: * itself, which can be obtained through {@link #getNamespace()}. If there
0371: * are no additional declarations, this returns an empty list. Note, the
0372: * returned list is unmodifiable.
0373: *
0374: * @return a List of the additional namespace
0375: * declarations
0376: */
0377: public List getAdditionalNamespaces() {
0378: // NotElement having the returned list be live allows us to avoid creating a
0379: // new list object when XMLOutputter calls this method on an element
0380: // with an empty list.
0381: if (additionalNamespaces == null) {
0382: return Collections.EMPTY_LIST;
0383: }
0384: return Collections.unmodifiableList(additionalNamespaces);
0385: }
0386:
0387: /**
0388: * Returns the XPath 1.0 string value of this element, which is the
0389: * complete, ordered content of all text node descendants of this element
0390: * (i.e. the text that's left after all references are resolved
0391: * and all other markup is stripped out.)
0392: *
0393: * @return a concatentation of all text node descendants
0394: */
0395: public String getValue() {
0396: StringBuffer buffer = new StringBuffer();
0397:
0398: Iterator itr = getContent().iterator();
0399: while (itr.hasNext()) {
0400: Content child = (Content) itr.next();
0401: if (child instanceof Element || child instanceof Text) {
0402: buffer.append(child.getValue());
0403: }
0404: }
0405: return buffer.toString();
0406: }
0407:
0408: /**
0409: * Returns whether this element is a root element. This can be used in
0410: * tandem with {@link #getParent} to determine if an element has any
0411: * "attachments" to a parent element or document.
0412: *
0413: * @return whether this is a root element
0414: */
0415: public boolean isRootElement() {
0416: return parent instanceof Document;
0417: }
0418:
0419: public int getContentSize() {
0420: return content.size();
0421: }
0422:
0423: public int indexOf(Content child) {
0424: return content.indexOf(child);
0425: }
0426:
0427: // private int indexOf(int start, Filter filter) {
0428: // int size = getContentSize();
0429: // for (int i = start; i < size; i++) {
0430: // if (filter.matches(getContent(i))) {
0431: // return i;
0432: // }
0433: // }
0434: // return -1;
0435: // }
0436:
0437: /**
0438: * Returns the textual content directly held under this element as a string.
0439: * This includes all text within this single element, including whitespace
0440: * and CDATA sections if they exist. It's essentially the concatenation of
0441: * all {@link Text} and {@link CDATA} nodes returned by {@link #getContent}.
0442: * The call does not recurse into child elements. If no textual value exists
0443: * for the element, an empty string is returned.
0444: *
0445: * @return text content for this element, or empty
0446: * string if none
0447: */
0448: public String getText() {
0449: if (content.size() == 0) {
0450: return "";
0451: }
0452:
0453: // If we hold only a Text or CDATA, return it directly
0454: if (content.size() == 1) {
0455: Object obj = content.get(0);
0456: if (obj instanceof Text) {
0457: return ((Text) obj).getText();
0458: } else {
0459: return "";
0460: }
0461: }
0462:
0463: // Else build String up
0464: StringBuffer textContent = new StringBuffer();
0465: boolean hasText = false;
0466:
0467: for (int i = 0; i < content.size(); i++) {
0468: Object obj = content.get(i);
0469: if (obj instanceof Text) {
0470: textContent.append(((Text) obj).getText());
0471: hasText = true;
0472: }
0473: }
0474:
0475: if (!hasText) {
0476: return "";
0477: } else {
0478: return textContent.toString();
0479: }
0480: }
0481:
0482: /**
0483: * Returns the textual content of this element with all surrounding
0484: * whitespace removed. If no textual value exists for the element, or if
0485: * only whitespace exists, the empty string is returned.
0486: *
0487: * @return trimmed text content for this element, or
0488: * empty string if none
0489: */
0490: public String getTextTrim() {
0491: return getText().trim();
0492: }
0493:
0494: /**
0495: * Returns the textual content of this element with all surrounding
0496: * whitespace removed and internal whitespace normalized to a single space.
0497: * If no textual value exists for the element, or if only whitespace exists,
0498: * the empty string is returned.
0499: *
0500: * @return normalized text content for this element, or
0501: * empty string if none
0502: */
0503: public String getTextNormalize() {
0504: return Text.normalizeString(getText());
0505: }
0506:
0507: /**
0508: * Returns the textual content of the named child element, or null if
0509: * there's no such child. This method is a convenience because calling
0510: * <code>getChild().getText()</code> can throw a NullPointerException.
0511: *
0512: * @param name the name of the child
0513: * @return text content for the named child, or null if
0514: * no such child
0515: */
0516: public String getChildText(String name) {
0517: Element child = getChild(name);
0518: if (child == null) {
0519: return null;
0520: }
0521: return child.getText();
0522: }
0523:
0524: /**
0525: * Returns the trimmed textual content of the named child element, or null
0526: * if there's no such child. See <code>{@link #getTextTrim()}</code> for
0527: * details of text trimming.
0528: *
0529: * @param name the name of the child
0530: * @return trimmed text content for the named child, or
0531: * null if no such child
0532: */
0533: public String getChildTextTrim(String name) {
0534: Element child = getChild(name);
0535: if (child == null) {
0536: return null;
0537: }
0538: return child.getTextTrim();
0539: }
0540:
0541: /**
0542: * Returns the normalized textual content of the named child element, or
0543: * null if there's no such child. See <code>{@link
0544: * #getTextNormalize()}</code> for details of text normalizing.
0545: *
0546: * @param name the name of the child
0547: * @return normalized text content for the named child,
0548: * or null if no such child
0549: */
0550: public String getChildTextNormalize(String name) {
0551: Element child = getChild(name);
0552: if (child == null) {
0553: return null;
0554: }
0555: return child.getTextNormalize();
0556: }
0557:
0558: /**
0559: * Returns the textual content of the named child element, or null if
0560: * there's no such child.
0561: *
0562: * @param name the name of the child
0563: * @param ns the namespace of the child
0564: * @return text content for the named child, or null if
0565: * no such child
0566: */
0567: public String getChildText(String name, Namespace ns) {
0568: Element child = getChild(name, ns);
0569: if (child == null) {
0570: return null;
0571: }
0572: return child.getText();
0573: }
0574:
0575: /**
0576: * Returns the trimmed textual content of the named child element, or null
0577: * if there's no such child.
0578: *
0579: * @param name the name of the child
0580: * @param ns the namespace of the child
0581: * @return trimmed text content for the named child, or
0582: * null if no such child
0583: */
0584: public String getChildTextTrim(String name, Namespace ns) {
0585: Element child = getChild(name, ns);
0586: if (child == null) {
0587: return null;
0588: }
0589: return child.getTextTrim();
0590: }
0591:
0592: /**
0593: * Returns the normalized textual content of the named child element, or
0594: * null if there's no such child.
0595: *
0596: * @param name the name of the child
0597: * @param ns the namespace of the child
0598: * @return normalized text content for the named child,
0599: * or null if no such child
0600: */
0601: public String getChildTextNormalize(String name, Namespace ns) {
0602: Element child = getChild(name, ns);
0603: if (child == null) {
0604: return null;
0605: }
0606: return child.getTextNormalize();
0607: }
0608:
0609: /**
0610: * Sets the content of the element to be the text given. All existing text
0611: * content and non-text context is removed. If this element should have both
0612: * textual content and nested elements, use <code>{@link #setContent}</code>
0613: * instead. Setting a null text value is equivalent to setting an empty
0614: * string value.
0615: *
0616: * @param text new text content for the element
0617: * @return the target element
0618: * @throws IllegalDataException if the assigned text contains an illegal
0619: * character such as a vertical tab (as
0620: * determined by {@link
0621: * org.jdom.Verifier#checkCharacterData})
0622: */
0623: public Element setText(String text) {
0624: content.clear();
0625:
0626: if (text != null) {
0627: addContent(new Text(text));
0628: }
0629:
0630: return this ;
0631: }
0632:
0633: /**
0634: * This returns the full content of the element as a List which
0635: * may contain objects of type <code>Text</code>, <code>Element</code>,
0636: * <code>Comment</code>, <code>ProcessingInstruction</code>,
0637: * <code>CDATA</code>, and <code>EntityRef</code>.
0638: * The List returned is "live" in document order and modifications
0639: * to it affect the element's actual contents. Whitespace content is
0640: * returned in its entirety.
0641: *
0642: * <p>
0643: * Sequential traversal through the List is best done with an Iterator
0644: * since the underlying implement of List.size() may require walking the
0645: * entire list.
0646: * </p>
0647: *
0648: * @return a <code>List</code> containing the mixed content of the
0649: * element: may contain <code>Text</code>,
0650: * <code>{@link Element}</code>, <code>{@link Comment}</code>,
0651: * <code>{@link ProcessingInstruction}</code>,
0652: * <code>{@link CDATA}</code>, and
0653: * <code>{@link EntityRef}</code> objects.
0654: */
0655: public List getContent() {
0656: return content;
0657: }
0658:
0659: /**
0660: * Return a filter view of this <code>Element</code>'s content.
0661: *
0662: * <p>
0663: * Sequential traversal through the List is best done with a Iterator
0664: * since the underlying implement of List.size() may require walking the
0665: * entire list.
0666: * </p>
0667: *
0668: * @param filter <code>Filter</code> to apply
0669: * @return <code>List</code> - filtered Element content
0670: */
0671: public List getContent(Filter filter) {
0672: return content.getView(filter);
0673: }
0674:
0675: /**
0676: * Removes all child content from this parent.
0677: *
0678: * @return list of the old children detached from this parent
0679: */
0680: public List removeContent() {
0681: List old = new ArrayList(content);
0682: content.clear();
0683: return old;
0684: }
0685:
0686: /**
0687: * Remove all child content from this parent matching the supplied filter.
0688: *
0689: * @param filter filter to select which content to remove
0690: * @return list of the old children detached from this parent
0691: */
0692: public List removeContent(Filter filter) {
0693: List old = new ArrayList();
0694: Iterator itr = content.getView(filter).iterator();
0695: while (itr.hasNext()) {
0696: Content child = (Content) itr.next();
0697: old.add(child);
0698: itr.remove();
0699: }
0700: return old;
0701: }
0702:
0703: /**
0704: * This sets the content of the element. The supplied List should
0705: * contain only objects of type <code>Element</code>, <code>Text</code>,
0706: * <code>CDATA</code>, <code>Comment</code>,
0707: * <code>ProcessingInstruction</code>, and <code>EntityRef</code>.
0708: *
0709: * <p>
0710: * When all objects in the supplied List are legal and before the new
0711: * content is added, all objects in the old content will have their
0712: * parentage set to null (no parent) and the old content list will be
0713: * cleared. This has the effect that any active list (previously obtained
0714: * with a call to {@link #getContent} or {@link #getChildren}) will also
0715: * change to reflect the new content. In addition, all objects in the
0716: * supplied List will have their parentage set to this element, but the
0717: * List itself will not be "live" and further removals and additions will
0718: * have no effect on this elements content. If the user wants to continue
0719: * working with a "live" list, then a call to setContent should be
0720: * followed by a call to {@link #getContent} or {@link #getChildren} to
0721: * obtain a "live" version of the content.
0722: * </p>
0723: *
0724: * <p>
0725: * Passing a null or empty List clears the existing content.
0726: * </p>
0727: *
0728: * <p>
0729: * In event of an exception the original content will be unchanged and
0730: * the objects in the supplied content will be unaltered.
0731: * </p>
0732: *
0733: * @param newContent <code>List</code> of content to set
0734: * @return this element modified
0735: * @throws IllegalAddException if the List contains objects of
0736: * illegal types or with existing parentage.
0737: */
0738: public Element setContent(Collection newContent) {
0739: content.clearAndSet(newContent);
0740: return this ;
0741: }
0742:
0743: /**
0744: * Replace the current child the given index with the supplied child.
0745: * <p>
0746: * In event of an exception the original content will be unchanged and
0747: * the supplied child will be unaltered.
0748: * </p>
0749: *
0750: * @param index - index of child to replace.
0751: * @param child - child to add.
0752: * @return element on which this method was invoked
0753: * @throws IllegalAddException if the supplied child is already attached
0754: * or not legal content for this parent.
0755: * @throws IndexOutOfBoundsException if index is negative or greater
0756: * than the current number of children.
0757: */
0758: public Element setContent(int index, Content child) {
0759: content.set(index, child);
0760: return this ;
0761: }
0762:
0763: /**
0764: * Replace the child at the given index whith the supplied
0765: * collection.
0766: * <p>
0767: * In event of an exception the original content will be unchanged and
0768: * the content in the supplied collection will be unaltered.
0769: * </p>
0770: *
0771: * @param index - index of child to replace.
0772: * @param collection - collection of content to add.
0773: * @return object on which this method was invoked
0774: * @throws IllegalAddException if the collection contains objects of
0775: * illegal types.
0776: * @throws IndexOutOfBoundsException if index is negative or greater
0777: * than the current number of children.
0778: */
0779: public Parent setContent(int index, Collection collection) {
0780: content.remove(index);
0781: content.addAll(index, collection);
0782: return this ;
0783: }
0784:
0785: /**
0786: * This adds text content to this element. It does not replace the
0787: * existing content as does <code>setText()</code>.
0788: *
0789: * @param str <code>String</code> to add
0790: * @return this element modified
0791: * @throws IllegalDataException if <code>str</code> contains an
0792: * illegal character such as a vertical tab (as determined
0793: * by {@link org.jdom.Verifier#checkCharacterData})
0794: */
0795: public Element addContent(String str) {
0796: return addContent(new Text(str));
0797: }
0798:
0799: /**
0800: * Appends the child to the end of the element's content list.
0801: *
0802: * @param child child to append to end of content list
0803: * @return the element on which the method was called
0804: * @throws IllegalAddException if the given child already has a parent. */
0805: public Element addContent(Content child) {
0806: content.add(child);
0807: return this ;
0808: }
0809:
0810: /**
0811: * Appends all children in the given collection to the end of
0812: * the content list. In event of an exception during add the
0813: * original content will be unchanged and the objects in the supplied
0814: * collection will be unaltered.
0815: *
0816: * @param collection collection to append
0817: * @return the element on which the method was called
0818: * @throws IllegalAddException if any item in the collection
0819: * already has a parent or is of an inappropriate type.
0820: */
0821: public Element addContent(Collection collection) {
0822: content.addAll(collection);
0823: return this ;
0824: }
0825:
0826: /**
0827: * Inserts the child into the content list at the given index.
0828: *
0829: * @param index location for adding the collection
0830: * @param child child to insert
0831: * @return the parent on which the method was called
0832: * @throws IndexOutOfBoundsException if index is negative or beyond
0833: * the current number of children
0834: * @throws IllegalAddException if the given child already has a parent.
0835: */
0836: public Element addContent(int index, Content child) {
0837: content.add(index, child);
0838: return this ;
0839: }
0840:
0841: /**
0842: * Inserts the content in a collection into the content list
0843: * at the given index. In event of an exception the original content
0844: * will be unchanged and the objects in the supplied collection will be
0845: * unaltered.
0846: *
0847: * @param index location for adding the collection
0848: * @param c collection to insert
0849: * @return the parent on which the method was called
0850: * @throws IndexOutOfBoundsException if index is negative or beyond
0851: * the current number of children
0852: * @throws IllegalAddException if any item in the collection
0853: * already has a parent or is of an inappropriate type.
0854: */
0855: public Element addContent(int index, Collection c) {
0856: content.addAll(index, c);
0857: return this ;
0858: }
0859:
0860: public List cloneContent() {
0861: int size = getContentSize();
0862: List list = new ArrayList(size);
0863: for (int i = 0; i < size; i++) {
0864: Content child = getContent(i);
0865: list.add(child.clone());
0866: }
0867: return list;
0868: }
0869:
0870: public Content getContent(int index) {
0871: return (Content) content.get(index);
0872: }
0873:
0874: // public Content getChild(Filter filter) {
0875: // int i = indexOf(0, filter);
0876: // return (i < 0) ? null : getContent(i);
0877: // }
0878:
0879: public boolean removeContent(Content child) {
0880: return content.remove(child);
0881: }
0882:
0883: public Content removeContent(int index) {
0884: return (Content) content.remove(index);
0885: }
0886:
0887: /**
0888: * Set this element's content to be the supplied child.
0889: * <p>
0890: * If the supplied child is legal content for this parent and before
0891: * it is added, all content in the current content list will
0892: * be cleared and all current children will have their parentage set to
0893: * null.
0894: * <p>
0895: * This has the effect that any active list (previously obtained with
0896: * a call to one of the {@link #getContent} methods will also change
0897: * to reflect the new content. In addition, all content in the supplied
0898: * collection will have their parentage set to this parent. If the user
0899: * wants to continue working with a <b>"live"</b> list of this parent's
0900: * child, then a call to setContent should be followed by a call to one
0901: * of the {@link #getContent} methods to obtain a <b>"live"</b>
0902: * version of the children.
0903: * <p>
0904: * Passing a null child clears the existing content.
0905: * <p>
0906: * In event of an exception the original content will be unchanged and
0907: * the supplied child will be unaltered.
0908: *
0909: * @param child new content to replace existing content
0910: * @return the parent on which the method was called
0911: * @throws IllegalAddException if the supplied child is already attached
0912: * or not legal content for an Element
0913: */
0914: public Element setContent(Content child) {
0915: content.clear();
0916: content.add(child);
0917: return this ;
0918: }
0919:
0920: /**
0921: * Determines if this element is the ancestor of another element.
0922: *
0923: * @param element <code>Element</code> to check against
0924: * @return <code>true</code> if this element is the ancestor of the
0925: * supplied element
0926: */
0927: public boolean isAncestor(Element element) {
0928: Object p = element.getParent();
0929: while (p instanceof Element) {
0930: if (p == this ) {
0931: return true;
0932: }
0933: p = ((Element) p).getParent();
0934: }
0935: return false;
0936: }
0937:
0938: /**
0939: * <p>
0940: * This returns the complete set of attributes for this element, as a
0941: * <code>List</code> of <code>Attribute</code> objects in no particular
0942: * order, or an empty list if there are none.
0943: * The returned list is "live" and changes to it affect the
0944: * element's actual attributes.
0945: * </p>
0946: *
0947: * @return attributes for the element
0948: */
0949: public List getAttributes() {
0950: return attributes;
0951: }
0952:
0953: /**
0954: * <p>
0955: * This returns the attribute for this element with the given name
0956: * and within no namespace, or null if no such attribute exists.
0957: * </p>
0958: *
0959: * @param name name of the attribute to return
0960: * @return attribute for the element
0961: */
0962: public Attribute getAttribute(String name) {
0963: return getAttribute(name, Namespace.NO_NAMESPACE);
0964: }
0965:
0966: /**
0967: * <p>
0968: * This returns the attribute for this element with the given name
0969: * and within the given Namespace, or null if no such attribute exists.
0970: * </p>
0971: *
0972: * @param name name of the attribute to return
0973: * @param ns <code>Namespace</code> to search within
0974: * @return attribute for the element
0975: */
0976: public Attribute getAttribute(String name, Namespace ns) {
0977: return (Attribute) attributes.get(name, ns);
0978: }
0979:
0980: /**
0981: * <p>
0982: * This returns the attribute value for the attribute with the given name
0983: * and within no namespace, null if there is no such attribute, and the
0984: * empty string if the attribute value is empty.
0985: * </p>
0986: *
0987: * @param name name of the attribute whose value to be returned
0988: * @return the named attribute's value, or null if no such attribute
0989: */
0990: public String getAttributeValue(String name) {
0991: return getAttributeValue(name, Namespace.NO_NAMESPACE);
0992: }
0993:
0994: /**
0995: * <p>
0996: * This returns the attribute value for the attribute with the given name
0997: * and within no namespace, or the passed-in default if there is no
0998: * such attribute.
0999: * </p>
1000: *
1001: * @param name name of the attribute whose value to be returned
1002: * @param def a default value to return if the attribute does not exist
1003: * @return the named attribute's value, or the default if no such attribute
1004: */
1005: public String getAttributeValue(String name, String def) {
1006: return getAttributeValue(name, Namespace.NO_NAMESPACE, def);
1007: }
1008:
1009: /**
1010: * <p>
1011: * This returns the attribute value for the attribute with the given name
1012: * and within the given Namespace, null if there is no such attribute, and
1013: * the empty string if the attribute value is empty.
1014: * </p>
1015: *
1016: * @param name name of the attribute whose valud is to be returned
1017: * @param ns <code>Namespace</code> to search within
1018: * @return the named attribute's value, or null if no such attribute
1019: */
1020: public String getAttributeValue(String name, Namespace ns) {
1021: return getAttributeValue(name, ns, null);
1022: }
1023:
1024: /**
1025: * <p>
1026: * This returns the attribute value for the attribute with the given name
1027: * and within the given Namespace, or the passed-in default if there is no
1028: * such attribute.
1029: * </p>
1030: *
1031: * @param name name of the attribute whose valud is to be returned
1032: * @param ns <code>Namespace</code> to search within
1033: * @param def a default value to return if the attribute does not exist
1034: * @return the named attribute's value, or the default if no such attribute
1035: */
1036: public String getAttributeValue(String name, Namespace ns,
1037: String def) {
1038: Attribute attribute = (Attribute) attributes.get(name, ns);
1039: return (attribute == null) ? def : attribute.getValue();
1040: }
1041:
1042: /**
1043: * <p>
1044: * This sets the attributes of the element. The supplied List should
1045: * contain only objects of type <code>Attribute</code>.
1046: * </p>
1047: *
1048: * <p>
1049: * When all objects in the supplied List are legal and before the new
1050: * attributes are added, all old attributes will have their
1051: * parentage set to null (no parent) and the old attribute list will be
1052: * cleared. This has the effect that any active attribute list (previously
1053: * obtained with a call to {@link #getAttributes}) will also change to
1054: * reflect the new attributes. In addition, all attributes in the supplied
1055: * List will have their parentage set to this element, but the List itself
1056: * will not be "live" and further removals and additions will have no
1057: * effect on this elements attributes. If the user wants to continue
1058: * working with a "live" attribute list, then a call to setAttributes
1059: * should be followed by a call to {@link #getAttributes} to obtain a
1060: * "live" version of the attributes.
1061: * </p>
1062: *
1063: * <p>
1064: * Passing a null or empty List clears the existing attributes.
1065: * </p>
1066: *
1067: * <p>
1068: * In cases where the List contains duplicate attributes, only the last
1069: * one will be retained. This has the same effect as calling
1070: * {@link #setAttribute(Attribute)} sequentially.
1071: * </p>
1072: *
1073: * <p>
1074: * In event of an exception the original attributes will be unchanged and
1075: * the attributes in the supplied attributes will be unaltered.
1076: * </p>
1077: *
1078: * @param newAttributes <code>List</code> of attributes to set
1079: * @return this element modified
1080: * @throws IllegalAddException if the List contains objects
1081: * that are not instances of <code>Attribute</code>,
1082: * or if any of the <code>Attribute</code> objects have
1083: * conflicting namespace prefixes.
1084: */
1085: public Element setAttributes(List newAttributes) {
1086: attributes.clearAndSet(newAttributes);
1087: return this ;
1088: }
1089:
1090: /**
1091: * <p>
1092: * This sets an attribute value for this element. Any existing attribute
1093: * with the same name and namespace URI is removed.
1094: * </p>
1095: *
1096: * @param name name of the attribute to set
1097: * @param value value of the attribute to set
1098: * @return this element modified
1099: * @throws IllegalNameException if the given name is illegal as an
1100: * attribute name.
1101: * @throws IllegalDataException if the given attribute value is
1102: * illegal character data (as determined by
1103: * {@link org.jdom.Verifier#checkCharacterData}).
1104: */
1105: public Element setAttribute(String name, String value) {
1106: return setAttribute(new Attribute(name, value));
1107: }
1108:
1109: /**
1110: * <p>
1111: * This sets an attribute value for this element. Any existing attribute
1112: * with the same name and namespace URI is removed.
1113: * </p>
1114: *
1115: * @param name name of the attribute to set
1116: * @param value value of the attribute to set
1117: * @param ns namespace of the attribute to set
1118: * @return this element modified
1119: * @throws IllegalNameException if the given name is illegal as an
1120: * attribute name, or if the namespace is an unprefixed default
1121: * namespace
1122: * @throws IllegalDataException if the given attribute value is
1123: * illegal character data (as determined by
1124: * {@link org.jdom.Verifier#checkCharacterData}).
1125: * @throws IllegalAddException if the attribute namespace prefix
1126: * collides with another namespace prefix on the element.
1127: */
1128: public Element setAttribute(String name, String value, Namespace ns) {
1129: return setAttribute(new Attribute(name, value, ns));
1130: }
1131:
1132: /**
1133: * <p>
1134: * This sets an attribute value for this element. Any existing attribute
1135: * with the same name and namespace URI is removed.
1136: * </p>
1137: *
1138: * @param attribute <code>Attribute</code> to set
1139: * @return this element modified
1140: * @throws IllegalAddException if the attribute being added already has a
1141: * parent or if the attribute namespace prefix collides with another
1142: * namespace prefix on the element.
1143: */
1144: public Element setAttribute(Attribute attribute) {
1145: attributes.add(attribute);
1146: return this ;
1147: }
1148:
1149: /**
1150: * <p>
1151: * This removes the attribute with the given name and within no
1152: * namespace. If no such attribute exists, this method does nothing.
1153: * </p>
1154: *
1155: * @param name name of attribute to remove
1156: * @return whether the attribute was removed
1157: */
1158: public boolean removeAttribute(String name) {
1159: return removeAttribute(name, Namespace.NO_NAMESPACE);
1160: }
1161:
1162: /**
1163: * <p>
1164: * This removes the attribute with the given name and within the
1165: * given Namespace. If no such attribute exists, this method does
1166: * nothing.
1167: * </p>
1168: *
1169: * @param name name of attribute to remove
1170: * @param ns namespace URI of attribute to remove
1171: * @return whether the attribute was removed
1172: */
1173: public boolean removeAttribute(String name, Namespace ns) {
1174: return attributes.remove(name, ns);
1175: }
1176:
1177: /**
1178: * <p>
1179: * This removes the supplied Attribute should it exist.
1180: * </p>
1181: *
1182: * @param attribute Reference to the attribute to be removed.
1183: * @return whether the attribute was removed
1184: */
1185: public boolean removeAttribute(Attribute attribute) {
1186: return attributes.remove(attribute);
1187: }
1188:
1189: /**
1190: * <p>
1191: * This returns a <code>String</code> representation of the
1192: * <code>Element</code>, suitable for debugging. If the XML
1193: * representation of the <code>Element</code> is desired,
1194: * {@link org.jdom.output.XMLOutputter#outputString(Element)}
1195: * should be used.
1196: * </p>
1197: *
1198: * @return <code>String</code> - information about the
1199: * <code>Element</code>
1200: */
1201: public String toString() {
1202: StringBuffer stringForm = new StringBuffer(64).append(
1203: "[Element: <").append(getQualifiedName());
1204:
1205: String nsuri = getNamespaceURI();
1206: if (!nsuri.equals("")) {
1207: stringForm.append(" [Namespace: ").append(nsuri)
1208: .append("]");
1209: }
1210: stringForm.append("/>]");
1211:
1212: return stringForm.toString();
1213: }
1214:
1215: /**
1216: * <p>
1217: * This returns a deep clone of this element.
1218: * The new element is detached from its parent, and getParent()
1219: * on the clone will return null.
1220: * </p>
1221: *
1222: * @return the clone of this element
1223: */
1224: public Object clone() {
1225:
1226: // Ken Rune Helland <kenh@csc.no> is our local clone() guru
1227:
1228: Element element = null;
1229:
1230: element = (Element) super .clone();
1231:
1232: // name and namespace are references to immutable objects
1233: // so super.clone() handles them ok
1234:
1235: // Reference to parent is copied by super.clone()
1236: // (Object.clone()) so we have to remove it
1237: // Actually, super is a Content, which has already detached in the clone().
1238: // element.parent = null;
1239:
1240: // Reference to content list and attribute lists are copyed by
1241: // super.clone() so we set it new lists if the original had lists
1242: element.content = new ContentList(element);
1243: element.attributes = new AttributeList(element);
1244:
1245: // Cloning attributes
1246: if (attributes != null) {
1247: for (int i = 0; i < attributes.size(); i++) {
1248: Object obj = attributes.get(i);
1249: Attribute attribute = (Attribute) ((Attribute) obj)
1250: .clone();
1251: element.attributes.add(attribute);
1252: }
1253: }
1254:
1255: // Cloning additional namespaces
1256: if (additionalNamespaces != null) {
1257: int additionalSize = additionalNamespaces.size();
1258: element.additionalNamespaces = new ArrayList(additionalSize);
1259: for (int i = 0; i < additionalSize; i++) {
1260: Object additional = additionalNamespaces.get(i);
1261: element.additionalNamespaces.add(additional);
1262: }
1263: }
1264:
1265: // Cloning content
1266: if (content != null) {
1267: for (int i = 0; i < content.size(); i++) {
1268: Object obj = content.get(i);
1269: if (obj instanceof Element) {
1270: Element elt = (Element) ((Element) obj).clone();
1271: element.content.add(elt);
1272: } else if (obj instanceof CDATA) {
1273: CDATA cdata = (CDATA) ((CDATA) obj).clone();
1274: element.content.add(cdata);
1275: } else if (obj instanceof Text) {
1276: Text text = (Text) ((Text) obj).clone();
1277: element.content.add(text);
1278: } else if (obj instanceof Comment) {
1279: Comment comment = (Comment) ((Comment) obj).clone();
1280: element.content.add(comment);
1281: } else if (obj instanceof ProcessingInstruction) {
1282: ProcessingInstruction pi = (ProcessingInstruction) ((ProcessingInstruction) obj)
1283: .clone();
1284: element.content.add(pi);
1285: } else if (obj instanceof EntityRef) {
1286: EntityRef entity = (EntityRef) ((EntityRef) obj)
1287: .clone();
1288: element.content.add(entity);
1289: }
1290: }
1291: }
1292:
1293: // Handle additional namespaces
1294: if (additionalNamespaces != null) {
1295: // Avoid additionalNamespaces.clone() because List isn't Cloneable
1296: element.additionalNamespaces = new ArrayList();
1297: element.additionalNamespaces.addAll(additionalNamespaces);
1298: }
1299:
1300: return element;
1301: }
1302:
1303: // Support a custom Namespace serialization so no two namespace
1304: // object instances may exist for the same prefix/uri pair
1305: private void writeObject(ObjectOutputStream out) throws IOException {
1306:
1307: out.defaultWriteObject();
1308:
1309: // We use writeObject() and not writeUTF() to minimize space
1310: // This allows for writing pointers to already written strings
1311: out.writeObject(namespace.getPrefix());
1312: out.writeObject(namespace.getURI());
1313:
1314: if (additionalNamespaces == null) {
1315: out.write(0);
1316: } else {
1317: int size = additionalNamespaces.size();
1318: out.write(size);
1319: for (int i = 0; i < size; i++) {
1320: Namespace additional = (Namespace) additionalNamespaces
1321: .get(i);
1322: out.writeObject(additional.getPrefix());
1323: out.writeObject(additional.getURI());
1324: }
1325: }
1326: }
1327:
1328: private void readObject(ObjectInputStream in) throws IOException,
1329: ClassNotFoundException {
1330:
1331: in.defaultReadObject();
1332:
1333: namespace = Namespace.getNamespace((String) in.readObject(),
1334: (String) in.readObject());
1335:
1336: int size = in.read();
1337:
1338: if (size != 0) {
1339: additionalNamespaces = new ArrayList(size);
1340: for (int i = 0; i < size; i++) {
1341: Namespace additional = Namespace.getNamespace(
1342: (String) in.readObject(), (String) in
1343: .readObject());
1344: additionalNamespaces.add(additional);
1345: }
1346: }
1347: }
1348:
1349: /**
1350: * Returns an iterator that walks over all descendants in document order.
1351: *
1352: * @return an iterator to walk descendants
1353: */
1354: public Iterator getDescendants() {
1355: return new DescendantIterator(this );
1356: }
1357:
1358: /**
1359: * Returns an iterator that walks over all descendants in document order
1360: * applying the Filter to return only elements that match the filter rule.
1361: * With filters you can match only Elements, only Comments, Elements or
1362: * Comments, only Elements with a given name and/or prefix, and so on.
1363: *
1364: * @param filter filter to select which descendants to see
1365: * @return an iterator to walk descendants within a filter
1366: */
1367: public Iterator getDescendants(Filter filter) {
1368: return new FilterIterator(new DescendantIterator(this ), filter);
1369: }
1370:
1371: /**
1372: * This returns a <code>List</code> of all the child elements
1373: * nested directly (one level deep) within this element, as
1374: * <code>Element</code> objects. If this target element has no nested
1375: * elements, an empty List is returned. The returned list is "live"
1376: * in document order and changes to it affect the element's actual
1377: * contents.
1378: *
1379: * <p>
1380: * Sequential traversal through the List is best done with a Iterator
1381: * since the underlying implement of List.size() may not be the most
1382: * efficient.
1383: * </p>
1384: *
1385: * <p>
1386: * No recursion is performed, so elements nested two levels deep
1387: * would have to be obtained with:
1388: * <pre>
1389: * <code>
1390: * Iterator itr = (currentElement.getChildren()).iterator();
1391: * while(itr.hasNext()) {
1392: * Element oneLevelDeep = (Element)itr.next();
1393: * List twoLevelsDeep = oneLevelDeep.getChildren();
1394: * // Do something with these children
1395: * }
1396: * </code>
1397: * </pre>
1398: * </p>
1399: *
1400: * @return list of child <code>Element</code> objects for this element
1401: */
1402: public List getChildren() {
1403: return content.getView(new ElementFilter());
1404: }
1405:
1406: /**
1407: * This returns a <code>List</code> of all the child elements
1408: * nested directly (one level deep) within this element with the given
1409: * local name and belonging to no namespace, returned as
1410: * <code>Element</code> objects. If this target element has no nested
1411: * elements with the given name outside a namespace, an empty List
1412: * is returned. The returned list is "live" in document order
1413: * and changes to it affect the element's actual contents.
1414: * <p>
1415: * Please see the notes for <code>{@link #getChildren}</code>
1416: * for a code example.
1417: * </p>
1418: *
1419: * @param name local name for the children to match
1420: * @return all matching child elements
1421: */
1422: public List getChildren(String name) {
1423: return getChildren(name, Namespace.NO_NAMESPACE);
1424: }
1425:
1426: /**
1427: * This returns a <code>List</code> of all the child elements
1428: * nested directly (one level deep) within this element with the given
1429: * local name and belonging to the given Namespace, returned as
1430: * <code>Element</code> objects. If this target element has no nested
1431: * elements with the given name in the given Namespace, an empty List
1432: * is returned. The returned list is "live" in document order
1433: * and changes to it affect the element's actual contents.
1434: * <p>
1435: * Please see the notes for <code>{@link #getChildren}</code>
1436: * for a code example.
1437: * </p>
1438: *
1439: * @param name local name for the children to match
1440: * @param ns <code>Namespace</code> to search within
1441: * @return all matching child elements
1442: */
1443: public List getChildren(String name, Namespace ns) {
1444: return content.getView(new ElementFilter(name, ns));
1445: }
1446:
1447: /**
1448: * This returns the first child element within this element with the
1449: * given local name and belonging to the given namespace.
1450: * If no elements exist for the specified name and namespace, null is
1451: * returned.
1452: *
1453: * @param name local name of child element to match
1454: * @param ns <code>Namespace</code> to search within
1455: * @return the first matching child element, or null if not found
1456: */
1457: public Element getChild(String name, Namespace ns) {
1458: List elements = content.getView(new ElementFilter(name, ns));
1459: Iterator i = elements.iterator();
1460: if (i.hasNext()) {
1461: return (Element) i.next();
1462: }
1463: return null;
1464: }
1465:
1466: /**
1467: * This returns the first child element within this element with the
1468: * given local name and belonging to no namespace.
1469: * If no elements exist for the specified name and namespace, null is
1470: * returned.
1471: *
1472: * @param name local name of child element to match
1473: * @return the first matching child element, or null if not found
1474: */
1475: public Element getChild(String name) {
1476: return getChild(name, Namespace.NO_NAMESPACE);
1477: }
1478:
1479: /**
1480: * <p>
1481: * This removes the first child element (one level deep) with the
1482: * given local name and belonging to no namespace.
1483: * Returns true if a child was removed.
1484: * </p>
1485: *
1486: * @param name the name of child elements to remove
1487: * @return whether deletion occurred
1488: */
1489: public boolean removeChild(String name) {
1490: return removeChild(name, Namespace.NO_NAMESPACE);
1491: }
1492:
1493: /**
1494: * <p>
1495: * This removes the first child element (one level deep) with the
1496: * given local name and belonging to the given namespace.
1497: * Returns true if a child was removed.
1498: * </p>
1499: *
1500: * @param name the name of child element to remove
1501: * @param ns <code>Namespace</code> to search within
1502: * @return whether deletion occurred
1503: */
1504: public boolean removeChild(String name, Namespace ns) {
1505: List old = content.getView(new ElementFilter(name, ns));
1506: Iterator i = old.iterator();
1507: if (i.hasNext()) {
1508: i.next();
1509: i.remove();
1510: return true;
1511: }
1512:
1513: return false;
1514: }
1515:
1516: /**
1517: * <p>
1518: * This removes all child elements (one level deep) with the
1519: * given local name and belonging to no namespace.
1520: * Returns true if any were removed.
1521: * </p>
1522: *
1523: * @param name the name of child elements to remove
1524: * @return whether deletion occurred
1525: */
1526: public boolean removeChildren(String name) {
1527: return removeChildren(name, Namespace.NO_NAMESPACE);
1528: }
1529:
1530: /**
1531: * <p>
1532: * This removes all child elements (one level deep) with the
1533: * given local name and belonging to the given namespace.
1534: * Returns true if any were removed.
1535: * </p>
1536: *
1537: * @param name the name of child elements to remove
1538: * @param ns <code>Namespace</code> to search within
1539: * @return whether deletion occurred
1540: */
1541: public boolean removeChildren(String name, Namespace ns) {
1542: boolean deletedSome = false;
1543:
1544: List old = content.getView(new ElementFilter(name, ns));
1545: Iterator i = old.iterator();
1546: while (i.hasNext()) {
1547: i.next();
1548: i.remove();
1549: deletedSome = true;
1550: }
1551:
1552: return deletedSome;
1553: }
1554:
1555: }
|