All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlpull.infoset.impl.XmlElementImpl Maven / Gradle / Ivy

Go to download

XML Pull parser library developed by Extreme Computing Lab, Indian University

There is a newer version: 1.2.8
Show newest version
/* -*-             c-basic-offset: 4; indent-tabs-mode: nil; -*-  //------100-columns-wide------>|*/
// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)

package org.xmlpull.infoset.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.xmlpull.infoset.XmlAttribute;
import org.xmlpull.infoset.XmlBuilderException;
import org.xmlpull.infoset.XmlCharacters;
import org.xmlpull.infoset.XmlComment;
import org.xmlpull.infoset.XmlContained;
import org.xmlpull.infoset.XmlContainer;
import org.xmlpull.infoset.XmlDocument;
import org.xmlpull.infoset.XmlElement;
import org.xmlpull.infoset.XmlElementView;
import org.xmlpull.infoset.XmlNamespace;

/**
 * This is implementation of XML Infoset Element Information Item.
 *
 * @version $Revision: 1.11 $
 * @author Aleksander Slominski
 */
public class XmlElementImpl implements XmlElement {
    
    
    private XmlContainer parent;
    private XmlNamespace namespace;
    //private String prefix;
    private String name;
    private List attrs = null;
    private List nsList = null;
    //NOTE: optimize for one child: Object oneChild; or create ElementWithChild????
    private List children = null;
    
    public XmlElementImpl(XmlNamespace namespace, String name) {
        this.namespace = namespace;
        this.name = name;
    }
    
    public XmlElementImpl(String namespaceName, String name) {
        if (namespaceName != null) {
            this.namespace = new XmlNamespaceImpl(null, namespaceName);
        }
        this.name = name;
    }
    
    //JDK15 covariant public XmlElement clone() throws CloneNotSupportedException
    public XmlElement clone() throws CloneNotSupportedException {
        XmlElementImpl cloned = (XmlElementImpl) super.clone();
        cloned.parent = null;
        // now do deep clone
        cloned.attrs = cloneList(cloned, attrs);
        cloned.nsList = cloneList(cloned, nsList); ///TODO should duplicate ALL in-scope namespaces?
        cloned.children = cloneList(cloned, children);
        
        //fix parent -- if needs fixing ...
        if (cloned.children != null) {
            for (int i = 0; i < cloned.children.size(); i++) {
                Object member = cloned.children.get(i);
                //                if(member instanceof XmlElement) {
                //                    XmlElement el = (XmlElement) member;
                //                    if(el.getParent() == this) {
                //                        el.setParent(null);
                //                        el.setParent(cloned);
                //                    }
                //                }
                if (member instanceof XmlContained) {
                    XmlContained contained = (XmlContained) member;
                    // we need to access uncloned as its children parent were nto touched (cloned are set to null)
                    XmlContained notClonedContained = (XmlContained) children.get(i);
                    if (notClonedContained.getParent() == this) {
                        contained.setParent(null);
                        contained.setParent(cloned);
                    }
                }
                
            }
        }
        
        return cloned;
    }
    
    private List cloneList(XmlElementImpl cloned, List list) throws CloneNotSupportedException {
        if (list == null) {
            return null;
        }
        List newList = new ArrayList(list.size());
        //JDK15 for(Object member: list) {
        for (int i = 0; i < list.size(); i++) {
            Object member = list.get(i);
            Object newMember; // = null;
            if ((member instanceof XmlNamespace) || (member instanceof String)) {
                // immutable and has no owner - no need to clone
                newMember = member;
            } else if (member instanceof XmlElement) {
                //                XmlElement el = (XmlElement) member;
                //                newMember = el.clone();
                XmlElement el = (XmlElement) member;
                newMember = el.clone();
            } else if (member instanceof XmlAttribute) {
                XmlAttribute attr = (XmlAttribute) member;
                newMember = new XmlAttributeImpl(cloned,
                                                 attr.getType(),
                                                 attr.getNamespace(),
                                                 attr.getName(),
                                                 attr.getValue(),
                                                 attr.isSpecified());
//            } else if (member instanceof XmlComment) {
//                XmlComment comment = (XmlComment) member;
//                newMember = new XmlCommentImpl(cloned, comment.getContent());
            } else if (member instanceof java.lang.Cloneable) {
                //use reflection to call clone() -- this is getting ugly!!!!
                // more background on this in http://www.artima.com/intv/issues3.html "The clone Dilemma"
                try {
                    newMember  = member.getClass().getMethod("clone", null).invoke(member, null);
                } catch (Exception e) {
                    throw new CloneNotSupportedException("failed to call clone() on  " + member + e);
                }
            } else {
                throw new CloneNotSupportedException();
            }
            newList.add(newMember);
        }
        return newList;
    }
    
    
    public XmlContainer getRoot() {
        XmlContainer root = this;
        while (true) {
            if (! (root instanceof XmlElement)) {
                break;
            }
            XmlElement el = (XmlElement) root;
            if (el.getParent() != null) {
                root = el.getParent();
            } else {
                break;
            }
        }
        return root;
    }
    
    //----- generic methods
    
    public XmlContainer getParent() {
        return parent;
    }
    
    public void setParent(XmlContainer parent) {
        if (parent != null) {
            // check that parent has me as child
            //            if(parent instanceof XmlElement) {
            //                Iterator iter = ((XmlElement)parent).children();
            //                boolean found = false;
            //                while (iter.hasNext())
            //                {
            //                    Object element = iter.next();
            //                    if(element == this) {
            //                        found = true;
            //                        break;
            //                    }
            //                }
            //                if(!found) {
            //                    throw new XmlBuilderException(
            //                        "this element must be child of parent to set its parent");
            //                }
            //            } else
            if (parent instanceof XmlDocument) {
                XmlDocument doc = (XmlDocument) parent;
                if (doc.getDocumentElement() != this) {
                    throw new XmlBuilderException(
                        "this element must be root document element to have document set as parent"
                        + " but already different element is set as root document element");
                }
            }
        }
        this.parent = parent;
    }
    
    public XmlNamespace getNamespace() {
        return namespace;
    }
    
    public String getNamespaceName() {
        return namespace != null ? namespace.getName() : null;
    }
    
    public void setNamespace(XmlNamespace namespace) {
        this.namespace = namespace;
    }
    
    //    public String getPrefix() {
    //        return prefix;
    //    }
    //
    //    public void setPrefix(String prefix) {
    //        this.prefix = prefix;
    //    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public String toString() {
        return "name[" + name + "]"
            + (namespace != null ? " namespace[" + namespace.getName() + "]" : "");
    }
    public String getBaseUri() {
        // TODO
        throw new XmlBuilderException("not implemented");
    }
    
    public void setBaseUri(String baseUri) {
        // TODO
        throw new XmlBuilderException("not implemented");
    }
    
    
    //Attributes
    
    public Iterable attributes() {
        if (attrs == null) {
            return EMPTY_ITERABLE;
        }
        //return attrs.iterator();
        //return attrs; //JDK5
        return new Iterable() { //NOTE: CG7 JDK1.4 emulation problem - cant use "return (Iterable) children;"
            public Iterator iterator() {
                return attrs.iterator();
            }
        };
    }
    
    public XmlElement setAttribute(XmlAttribute attributeValueToAdd) {
        if (attrs == null) ensureAttributesCapacity(5);
        //check that there is no attribute duplication (including namespaces?)
        XmlAttribute att = findAttribute(attributeValueToAdd.getNamespaceName(),
                                         attributeValueToAdd.getName());
        if (att != null) {
            removeAttribute(att);
        }
        attrs.add(attributeValueToAdd);
        //return attributeValueToAdd;
        return this;
    }
    
    public XmlElement setAttributeValue(XmlNamespace namespace, String name, String value) {
        return setAttribute("CDATA", namespace, name, value, false);
    }
    
    public XmlElement setAttributeValue(String name, String value) {
        return setAttribute("CDATA", null, name, value, false);
    }
    
    public XmlElement setAttribute(String attributeType, XmlNamespace namespace, String name, String value) {
        return setAttribute(attributeType, namespace, name, value, false);
    }
    
    public XmlElement setAttribute(String attributeType, XmlNamespace namespace, String name,
                                   String value, boolean specified) {
        
        if (value == null) {
            XmlAttribute oldAttr = attribute(namespace, name);
            if (oldAttr != null) {
                removeAttribute(oldAttr);
            }
        } else {
            XmlAttribute a = new XmlAttributeImpl(this, attributeType, namespace, name, value, specified);
            setAttribute(a);
        }
        return this;
    }
    
    public XmlElement setAttribute(String attributeType,
                                   String attributePrefix,
                                   String attributeNamespace,
                                   String attributeName,
                                   String attributeValue,
                                   boolean specified) {
        XmlNamespace n = newNamespace(attributePrefix, attributeNamespace);
        return setAttribute(attributeType, n, attributeName, attributeValue, specified);
    }
    
    public void ensureAttributesCapacity(int minCapacity) {
        if (attrs == null) {
            attrs = new ArrayList(minCapacity);
        } else {
            ((ArrayList)attrs).ensureCapacity(minCapacity);
        }
    }
    
    
    public String attributeValue(String attributeName) {
        return attributeValue((String)null, attributeName);
    }
    
    public String attributeValue(XmlNamespace attributeNamespace, String attributeName) {
        return attributeValue(attributeNamespace.getName(), attributeName);
    }
    
    protected String attributeValue(String attributeNamespaceName,
                                    String attributeName) {
        XmlAttribute xat = findAttribute(attributeNamespaceName, attributeName);
        if (xat != null) {
            return xat.getValue();
        }
        return null;
    }
    
    public String requiredAttributeValue(String attributeName) throws XmlBuilderException {
        XmlAttribute xat = findAttribute((String)null, attributeName);
        if (xat != null) {
            return xat.getValue();
        } else {
            throw new XmlBuilderException("could not find attribute with name '" + attributeName + "'");
        }
    }
    
    public String requiredAttributeValue(XmlNamespace attributeNamespace,
                                         String attributeName)  throws XmlBuilderException {
        XmlAttribute xat = findAttribute(attributeNamespace.getName(), attributeName);
        if (xat != null) {
            return xat.getValue();
        } else {
            throw new XmlBuilderException("could not find attribute with name '{" +
                                          attributeNamespace.getName() + "}" +
                                          attributeName + "'");
        }
    }
    
    public boolean hasAttributes() {
        return attrs != null && attrs.size() > 0;
    }
    
    public XmlAttribute attribute(String attributeName) {
        return attribute(null, attributeName);
    }
    
    public XmlAttribute attribute(XmlNamespace attributeNamespace,
                                  String attributeName) {
        return findAttribute(
            attributeNamespace != null ? attributeNamespace.getName() : null,
            attributeName);
    }
    
    public XmlAttribute requiredAttribute(String attributeName) throws XmlBuilderException {
        XmlAttribute att = attribute(attributeName);
        if (att != null) {
            return att;
        } else {
            throw new XmlBuilderException("could not find attribute with name '" + attributeName + "'");
        }
    }
    
    public XmlAttribute requiredAttribute(XmlNamespace attributeNamespace,
                                          String attributeName) throws XmlBuilderException {
        XmlAttribute att = attribute(attributeNamespace, attributeName);
        if (att != null) {
            return att;
        } else {
            throw new XmlBuilderException("could not find attribute with name '{" +
                                          attributeNamespace.getName() + "}"
                                          + attributeName + "'");
        }
    }
    
    //todo: verify me
    //if you enforce that namespace "" and null are equivalent this could be
    //rewritten
    protected XmlAttribute findAttribute(String attributeNamespace, String attributeName) {
        if (attributeName == null) {
            throw new IllegalArgumentException("attribute name ca not ber null");
        }
        
        //addtional condition ---> test if there are some attrs
        if (attrs == null) {
            return null;
        }
        
        int length = attrs.size();
        
        for (int i = 0; i < length; i++) {
            XmlAttribute a = (XmlAttribute) attrs.get(i);
            String aName = a.getName();
            if (aName == attributeName  // fast if strings are itnerned
                || attributeName.equals(aName)) {
                if (attributeNamespace != null) {
                    String aNamespace = a.getNamespaceName();
                    if (attributeNamespace.equals(aNamespace)) {
                        return a;
                    } else if ((attributeNamespace == "") && (aNamespace == null)) {
                        return a;
                    }
                    //                    XmlNamespace aNamespace = a.getNamespace();
                    //                    if(aNamespace != null) {
                    //                        String aNamespaceName = aNamespace.getNamespaceName();
                    //                        if(aNamespaceName == attributeName
                    //                           || aNamespace.equals(aNamespaceName))
                    //                        {
                    //                            return a;
                    //                        }
                    //                    }
                } else {
                    if (a.getNamespace() == null) {
                        return a;
                    } else {
                        if (a.getNamespace().getName() == "") {
                            return a;
                        }
                    }
                }
                
            }
        }
        return null;
    }
    
    public void removeAllAttributes() {
        attrs = null;
    }
    
    public void removeAttribute(XmlAttribute attr) {
        if (attrs == null) {
            throw new XmlBuilderException("this element has no attributes to remove");
        }
        for (int i = 0; i < attrs.size(); i++) {
            if (attrs.get(i).equals(attr)) {
                attrs.remove(i);
                break;
            }
        }
    }
    
    
    //------------ Namespaces
    
    public XmlNamespace declareNamespace(String prefix, String namespaceName) {
        if (prefix == null) {
            throw new XmlBuilderException("namespace added to element must have not null prefix");
        }
        XmlNamespace n = newNamespace(prefix, namespaceName);
        return declareNamespace(n);
    }
    
    public XmlNamespace declareNamespace(XmlNamespace n) {
        if (n.getPrefix() == null) {
            throw new XmlBuilderException("namespace added to element must have not null prefix");
        }
        if (nsList == null) ensureNamespaceDeclarationsCapacity(5);
        //TODO  check for duplicates
        nsList.add(n);
        return n;
    }
    
    public boolean hasNamespaceDeclarations() {
        return nsList != null && nsList.size() > 0;
    }
    
    public XmlNamespace lookupNamespaceByPrefix(String namespacePrefix) {
        if (namespacePrefix == null) {
            throw new IllegalArgumentException("namespace prefix can not be null");
        }
        if (hasNamespaceDeclarations()) {
            int length = nsList.size();
            for (int i = 0; i < length; i++) {
                XmlNamespace n = nsList.get(i);
                if (namespacePrefix.equals(n.getPrefix())) {
                    return n;
                }
            }
        }
        if (parent != null && parent instanceof XmlElement) {
            return ((XmlElement)parent).lookupNamespaceByPrefix(namespacePrefix);
        } else {
            return null;
        }
    }
    
    public XmlNamespace lookupNamespaceByName(String namespaceName) {
        if (namespaceName == null) {
            throw new IllegalArgumentException("namespace name can not ber null");
        }
        if (hasNamespaceDeclarations()) {
            int length = nsList.size();
            for (int i = 0; i < length; i++) {
                XmlNamespace n = nsList.get(i);
                if (namespaceName.equals(n.getName())) {
                    return n;
                }
            }
        }
        if (parent != null && parent instanceof XmlElement) {
            return ((XmlElement)parent).lookupNamespaceByName(namespaceName);
        } else {
            return null;
        }
    }
    
    public Iterable namespaces() {
        if (nsList == null) {
            return EMPTY_ITERABLE;
        }
        //return nsList.iterator();
        //return nsList; //JDK5
        return new Iterable() { //NOTE: CG7 JDK1.4 emulation problem - cant use "return (Iterable) children;"
            public Iterator iterator() {
                return nsList.iterator();
            }
        };
    }
    
    public XmlNamespace newNamespace(String namespaceName) {
        return newNamespace(null, namespaceName);
    }
    
    public XmlNamespace newNamespace(String prefix, String namespaceName) {
        return new XmlNamespaceImpl(prefix, namespaceName);
    }
    
    public void ensureNamespaceDeclarationsCapacity(int minCapacity) {
        //        if(attrs == null) {
        if (nsList == null) {
            nsList = new ArrayList(minCapacity);
        } else {
            ((ArrayList)nsList).ensureCapacity(minCapacity);
        }
    }
    
    public void removeAllNamespaceDeclarations() {
        nsList = null;
    }
    
    
    //---------------- Elements
    
    public void addChild(Object child) {
        if (child == null) throw new NullPointerException();
        if (children == null) ensureChildrenCapacity(1);
        //checkChildParent(child);
        children.add(child);
        //setChildParent(child);
    }
    
    public void addChild(int index, Object child) {
        if (children == null) ensureChildrenCapacity(1);
        //checkChildParent(child);
        children.add(index, child);
        //setChildParent(child);
    }
    
    private void checkChildParent(Object child) {
        if (child instanceof XmlContainer) {
            if (child instanceof XmlElement) {
                XmlElement elChild = (XmlElement) child;
                XmlContainer childParent = elChild.getParent();
                if (childParent != null) {
                    if (childParent != parent) {
                        throw new XmlBuilderException(
                            "child must have no parent to be added to this node");
                    }
                }
            } else if (child instanceof XmlDocument) {
                throw new XmlBuilderException("docuemet can not be stored as element child");
            }
        }
    }
    
    private void setChildParent(Object child) {
        if (child instanceof XmlElement) {
            XmlElement elChild = (XmlElement) child;
            elChild.setParent(this);
        }
    }
    
    public XmlElement addElement(XmlElement element) {
        checkChildParent(element);
        addChild(element);
        setChildParent(element);
        return element;
    }
    
    
    public XmlElement addElement(int pos, XmlElement element) {
        checkChildParent(element);
        addChild(pos, element);
        setChildParent(element);
        return element;
    }
    
    public XmlElement addElement(XmlNamespace namespace, String name) {
        XmlElement el = newElement(namespace, name);
        addChild(el);
        setChildParent(el);
        return el;
    }
    
    public XmlElement addElement(String name) {
        return addElement(null, name);
    }
    
    public XmlComment addComment(String content) {
        XmlCommentImpl comment = new XmlCommentImpl(content);
        addChild(comment);
        return comment;
    }
    
    public Iterable children() {
        if (children == null) {
            //return EMPTY_ITERATOR;
            return EMPTY_ITERABLE;
        }
        //return children.iterator();
        //return children; //JDK5
        return new Iterable() { //NOTE: CG7 JDK1.4 emulation problem - cant use "return (Iterable) children;"
            public Iterator iterator() {
                return children.iterator();
            }
        };
    }
    
    public Iterable requiredElementContent() {
        if (children == null) {
            return EMPTY_ITERABLE;
        }
        return new Iterable() {
            public Iterator iterator() {
                return new RequiredElementContentIterator(children.iterator());
            }
        };
    }
    
    public String requiredText() {
        if (children == null) {
            //            throw new XmlBuilderException("element {"+getNamespace().getNamespaceName()+"}"
            //                                              +getName()+" has no content");
            return "";
        }
        if (children.size() == 0) {
            return "";
        } else if (children.size() == 1) {
            Object child = children.get(0);
            if (child instanceof String) {
                return child.toString();
            } else if (child instanceof XmlCharacters) {
                return ((XmlCharacters)child).getText();
            } else {
                throw new XmlBuilderException("expected text content and not "
                                              + (child != null ? child.getClass() : null)
                                              + " with '" + child + "'");
            }
        }
        Iterator i = children().iterator();
        StringBuffer buf = new StringBuffer();
        while (i.hasNext()) {
            Object child = i.next();
            if (child instanceof String) {
                buf.append(child.toString());
            } else if (child instanceof XmlCharacters) {
                buf.append(((XmlCharacters)child).getText());
            } else {
                throw new XmlBuilderException("expected text content and not " + child.getClass()
                                              + " with '" + child + "'");
            }
        }
        return buf.toString();
    }
    
    public void ensureChildrenCapacity(int minCapacity) {
        if (children == null) {
            children = new ArrayList(minCapacity);
        } else {
            ((ArrayList)children).ensureCapacity(minCapacity);
        }
    }
    
    public XmlElement element(int position) {
        if (children == null) return null;
        int length = children.size();
        int count = 0;
        if (position >= 0 && position < length) {
            int pos = 0;
            while (pos < length) {
                Object child = children.get(pos);
                if (child instanceof XmlElement) {
                    if (count == position) {
                        return (XmlElement) child;
                    }
                    ++count;
                }
                ++pos;
            }
        } else  { //TODO:CTX
            throw new IndexOutOfBoundsException(position + " bigger than " + length + " children");
        } //TODO:CTX
        throw new IndexOutOfBoundsException(position + " too big as only " + count + " elements available");
    }
    
    
    public XmlElement requiredElement(String name)  throws XmlBuilderException {
        return requiredElement(null, name);
    }
    
    public XmlElement element(String name) {
        return element(null, name);
    }
    
    public XmlElement requiredElement(XmlNamespace n, String name) throws XmlBuilderException {
        XmlElement el = element(n, name);
        if (el == null) { //TODO:CTX
            throw new XmlBuilderException("could not find element with name " + name
                                          + " in namespace " + (n != null ? n.getName() : null));
        }
        return el;
    }
    
    public XmlElement element(XmlNamespace n, String name) {
        return element(n, name, false);
    }
    public XmlElement element(XmlNamespace n, String name, boolean create) {
        XmlElement e = n != null ? findElementByName(n.getName(), name) : findElementByName(name);
        if (e != null) {
            return e;
        }
        //e =new XmlElementImpl(n, name);
        if (create) {
            return addElement(n, name);
        } else {
            return null;
        }
    }
    
    public Iterable elements(final XmlNamespace n, final String name) {
        if (children == null) {
            return EMPTY_ITERABLE;
        } else {
            return new Iterable() {
                public Iterator iterator() {
                    //return new ElementsSimpleIterator(n, name, children().iterator());
                    return new ElementsSimpleIterator(n, name, children.iterator());
                }
            };
        }
    }
    
    
    public XmlElement findElementByName(String name) {
        if (children == null) return null;
        int length = children.size();
        for (int i = 0; i < length; i++) {
            Object child = children.get(i);
            if (child instanceof XmlElement) {
                XmlElement childEl = (XmlElement) child;
                if (name.equals(childEl.getName())) {
                    return childEl;
                }
            }
        }
        return null;
    }
    
    public XmlElement findElementByName(String namespaceName, String name,
                                        XmlElement elementToStartLooking) {
        // TODO
        throw new UnsupportedOperationException();
    }
    
    public XmlElement findElementByName(String name,
                                        XmlElement elementToStartLooking) {
        // TODO
        throw new UnsupportedOperationException();
    }
    
    public XmlElement findElementByName(String namespaceName, String name) {
        if (children == null) return null;
        int length = children.size();
        for (int i = 0; i < length; i++) {
            Object child = children.get(i);
            if (child instanceof XmlElement) {
                XmlElement childEl = (XmlElement) child;
                XmlNamespace namespace = childEl.getNamespace();
                if (namespace != null) {
                    if ((name.equals(childEl.getName())) && (namespaceName.equals(namespace.getName()))) {
                        return childEl;
                    }
                } else {
                    if ((name.equals(childEl.getName())) && (namespaceName == null)) {
                        return childEl;
                    }
                }
            }
        }
        
        return null;
    }
    
    
    public boolean hasChild(Object child) {
        if (children == null) {
            return false;
        }
        for (int i = 0; i < children.size(); i++) {
            if (children.get(i) == child) {
                return true;
            }
        }
        return false;
    }
    
    
    public boolean hasChildren() {
        return children != null && children.size() > 0;
    }
    
    public void insertChild(int pos, Object childToInsert) {
        if (children == null) ensureChildrenCapacity(1);
        children.add(pos, childToInsert);
    }
    
    
    public XmlElement newElement(String name) {
        return newElement((XmlNamespace)null, name);
    }
    
    public XmlElement newElement(String namespace, String name) {
        return new XmlElementImpl(namespace, name);
    }
    
    public XmlElement newElement(XmlNamespace namespace, String name) {
        return new XmlElementImpl(namespace, name);
    }
    
    public XmlComment newComment(String content) {
        return new XmlCommentImpl(content);
    }
    
    public void replaceChild(Object newChild, Object oldChild) {
        if (newChild == null) {
            throw new IllegalArgumentException("new child to replace can not be null");
        }
        if (oldChild == null) {
            throw new IllegalArgumentException("old child to replace can not be null");
        }
        if (!hasChildren()) {
            throw new XmlBuilderException("no children available for replacement");
        }
        int pos = children.indexOf(oldChild);
        if (pos == -1) {
            throw new XmlBuilderException("could not find child to replace");
        }
        children.set(pos, newChild);
    }

    public void replaceElement(XmlElement newElement, XmlElement oldElement) {
        replaceChild(newElement, oldElement);
        oldElement.setParent(null);
        setChildParent(newElement);
    }
        
    public void replaceLikeElementsWith(XmlElement element) {
        if (element == null) {
            throw new IllegalArgumentException("element can not be null");
        }
        checkChildParent(element);
        if (children == null) ensureChildrenCapacity(1);
        int pos = -1;
        int n = children.size() - 1;
        if (n >= 0) {
            final XmlNamespace ns = element.getNamespace();
            final String name = element.getName();
            while (n >= 0) {
                Object child = children.get(n);
                if (child instanceof XmlElement) {
                    XmlElement childEl = (XmlElement) child;
                    if (ns.equals(childEl.getNamespace()) && name.equals(childEl.getName())) {
                        pos = n;
                        children.remove(pos);
                        childEl.setParent(null);
                    }
                }
                --n;
            }
        }
        if (pos != -1) {
            children.add(pos, element);
            setChildParent(element);
        } else {
            addElement(element);
        }
    }
    
    
    public void removeAllChildren() {
        children = null;
    }
    
    public void removeChild(Object child) {
        if (child == null) {
            throw new IllegalArgumentException("child to remove can not be null");
        }
        if (!hasChildren()) {
            throw new XmlBuilderException("no children to remove");
        }
        int pos = children.indexOf(child);
        if (pos != -1) {
            children.remove(pos);
        }
        //      int length = children.size();
        //      for (int i = 0; i < length; i++)
        //      {
        //          Object o = children.get(i);
        //          if(o == child) {
        //          }
        //      }
    }
    
    public void removeElement(XmlElement el) {
        removeChild(el);
        el.setParent(null);
    }
    
    
    public void setText(String textContent) {
        removeAllChildren();
        addChild(textContent);
    }
    
    private static final boolean isWhiteSpace(String txt) {
        for (int i = 0; i < txt.length(); i++) {
            if ((txt.charAt(i) != ' ') &&
                (txt.charAt(i) != '\n') &&
                (txt.charAt(i) != '\t') &&
                (txt.charAt(i) != '\r')) {
                return false;
            }
        }
        
        return true;
    }
    
    //public XmlElementView viewAs(Class someViewClass) throws XmlBuilderException {
    public  T viewAs(Class someViewClass) throws XmlBuilderException {
        throw new XmlBuilderException(
            "this class does not support views - builder must be reconfigured");
    }
    
    public void addView(XmlElementView newView) throws XmlBuilderException {
        throw new XmlBuilderException(
            "this class does not support views - builder must be reconfigured");
    }
    
    public  Iterable elements(XmlNamespace n, String name,
                                                           Class someViewClass) {
        throw new XmlBuilderException(
            "this class does not support views - builder must be reconfigured");
    }
    
    private class ElementsSimpleIterator implements Iterator {
        
        private Iterator children;
        private XmlElement currentEl;
        
        private XmlNamespace n;
        
        private String name;
        
        ElementsSimpleIterator(final XmlNamespace n, final String name, Iterator children) {
            this.children = children;
            this.n = n;
            this.name = name;
            findNextEl();
        }
        
        private void findNextEl() {
            currentEl = null;
            while (children.hasNext()) {
                Object child = children.next();
                if (child instanceof XmlElement) {
                    XmlElement el = (XmlElement) child;
                    if ((name == null || el.getName() == name || name.equals(el.getName()))
                        && (n == null || el.getNamespace() == n || n.equals(el.getNamespace()))
                        ) {
                        currentEl = el;
                        break;
                    }
                }
            }
        }
        
        public boolean hasNext() {
            return currentEl != null;
        }
        
        public Object next() {
            if (currentEl == null) {
                throw new XmlBuilderException(
                    "this iterator has no content and next() is not allowed");
            }
            XmlElement el = currentEl;
            findNextEl();
            return el;
        }
        
        public void remove() {
            throw new XmlBuilderException(
                "this element iterator does nto support remove()");
        }
        
    }
    
    private static class RequiredElementContentIterator implements Iterator {
        
        private Iterator children;
        private XmlElement currentEl;
        
        RequiredElementContentIterator(Iterator children) {
            this.children = children;
            findNextEl();
        }
        
        private void findNextEl() {
            currentEl = null;
            while (children.hasNext()) {
                Object child = children.next();
                if (child instanceof XmlElement) {
                    currentEl = (XmlElement) child;
                    break;
                } else if (child instanceof String) {
                    String s = child.toString();
                    if (false == isWhiteSpace(s)) {
                        throw new XmlBuilderException( //TODO parent.getPositionDesc() ...
                            "only whitespace string children allowed for non mixed element content");
                    }
                } else if (child instanceof XmlCharacters) {
                    XmlCharacters xc = (XmlCharacters) child;
                    if (!Boolean.TRUE.equals(xc.isWhitespaceContent())
                        || false == isWhiteSpace(xc.getText())) {
                        throw new XmlBuilderException( //TODO parent.getPositionDesc() ...
                            "only whitespace characters children allowed for non mixed element content");
                    }
                } else if (child instanceof XmlComment) {
                    // do nothing
                } else {
                    throw new XmlBuilderException( //TODO parent.getPositionDesc() ...
                        "only whitespace characters and element children allowed " +
                        "for non mixed element content and not " + child.getClass());
                }
            }
        }
        
        public boolean hasNext() {
            return currentEl != null;
        }
        
        public Object next() {
            if (currentEl == null) {
                throw new XmlBuilderException(
                    "this iterator has no content and next() is not allowed");
            }
            XmlElement el = currentEl;
            findNextEl();
            return el;
        }
        
        public void remove() {
            throw new XmlBuilderException(
                "this iterator does nto support remove()");
        }
    }
    
    private static class EmptyIterator implements Iterator {
        public boolean hasNext() {
            return false;
        }
        
        public T next() {
            throw new XmlBuilderException(
                "this iterator has no content and next() is not allowed");
        }
        
        public void remove() {
            throw new XmlBuilderException(
                "this iterator has no content and remove() is not allowed");
        }
    }
    
    private static final Iterator EMPTY_ITERATOR = new EmptyIterator();
    private static final Iterator EMPTY_ATTR_ITERATOR
    = new EmptyIterator();
    
    private static final Iterable EMPTY_ITERABLE = new Iterable() {
        
        public Iterator iterator() {
            return EMPTY_ITERATOR;
        }
    };
    
    
}