/*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*
* This software is open source.
* See the bottom of this file for the licence.
*/
package org.dom4j.tree;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.IllegalAddException;
import org.dom4j.Namespace;
import org.dom4j.Node;
import org.dom4j.ProcessingInstruction;
import org.dom4j.QName;
/**
* <p>
* <code>DefaultElement</code> is the default DOM4J default implementation of
* an XML element.
* </p>
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
* @version $Revision: 1.59 $
*/
public class DefaultElement extends AbstractElement {
/** The <code>DocumentFactory</code> instance used by default */
private static final transient DocumentFactory DOCUMENT_FACTORY =
DocumentFactory.getInstance();
/** The <code>QName</code> for this element */
private QName qname;
/**
* Stores the parent branch of this node which is either a Document if this
* element is the root element in a document, or another Element if it is a
* child of the root document, or null if it has not been added to a
* document yet.
*/
private Branch parentBranch;
/**
* Stores null for no content, a Node for a single content node or a List
* for multiple content nodes. The List will be lazily constructed when
* required.
*/
private Object content;
/** Lazily constructes list of attributes */
private Object attributes;
public DefaultElement(String name) {
this.qname = DOCUMENT_FACTORY.createQName(name);
}
public DefaultElement(QName qname) {
this.qname = qname;
}
public DefaultElement(QName qname, int attributeCount) {
this.qname = qname;
if (attributeCount > 1) {
this.attributes = new ArrayList(attributeCount);
}
}
public DefaultElement(String name, Namespace namespace) {
this.qname = DOCUMENT_FACTORY.createQName(name, namespace);
}
public Element getParent() {
Element result = null;
if (parentBranch instanceof Element) {
result = (Element) parentBranch;
}
return result;
}
public void setParent(Element parent) {
if (parentBranch instanceof Element || (parent != null)) {
parentBranch = parent;
}
}
public Document getDocument() {
if (parentBranch instanceof Document) {
return (Document) parentBranch;
} else if (parentBranch instanceof Element) {
Element parent = (Element) parentBranch;
return parent.getDocument();
}
return null;
}
public void setDocument(Document document) {
if (parentBranch instanceof Document || (document != null)) {
parentBranch = document;
}
}
public boolean supportsParent() {
return true;
}
public QName getQName() {
return qname;
}
public void setQName(QName name) {
this.qname = name;
}
public String getText() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
return super.getText();
} else {
if (contentShadow != null) {
return getContentAsText(contentShadow);
} else {
return "";
}
}
}
public String getStringValue() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
if (size > 0) {
if (size == 1) {
// optimised to avoid StringBuffer creation
return getContentAsStringValue(list.get(0));
} else {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < size; i++) {
Object node = list.get(i);
String string = getContentAsStringValue(node);
if (string.length() > 0) {
if (USE_STRINGVALUE_SEPARATOR) {
if (buffer.length() > 0) {
buffer.append(' ');
}
}
buffer.append(string);
}
}
return buffer.toString();
}
}
} else {
if (contentShadow != null) {
return getContentAsStringValue(contentShadow);
}
}
return "";
}
public Object clone() {
DefaultElement answer = (DefaultElement) super.clone();
if (answer != this) {
answer.content = null;
answer.attributes = null;
answer.appendAttributes(this);
answer.appendContent(this);
}
return answer;
}
public Namespace getNamespaceForPrefix(String prefix) {
if (prefix == null) {
prefix = "";
}
if (prefix.equals(getNamespacePrefix())) {
return getNamespace();
} else if (prefix.equals("xml")) {
return Namespace.XML_NAMESPACE;
} else {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Namespace) {
Namespace namespace = (Namespace) object;
if (prefix.equals(namespace.getPrefix())) {
return namespace;
}
}
}
} else if (contentShadow instanceof Namespace) {
Namespace namespace = (Namespace) contentShadow;
if (prefix.equals(namespace.getPrefix())) {
return namespace;
}
}
}
Element parent = getParent();
if (parent != null) {
Namespace answer = parent.getNamespaceForPrefix(prefix);
if (answer != null) {
return answer;
}
}
if ((prefix == null) || (prefix.length() <= 0)) {
return Namespace.NO_NAMESPACE;
}
return null;
}
public Namespace getNamespaceForURI(String uri) {
if ((uri == null) || (uri.length() <= 0)) {
return Namespace.NO_NAMESPACE;
} else if (uri.equals(getNamespaceURI())) {
return getNamespace();
} else {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Namespace) {
Namespace namespace = (Namespace) object;
if (uri.equals(namespace.getURI())) {
return namespace;
}
}
}
} else if (contentShadow instanceof Namespace) {
Namespace namespace = (Namespace) contentShadow;
if (uri.equals(namespace.getURI())) {
return namespace;
}
}
Element parent = getParent();
if (parent != null) {
return parent.getNamespaceForURI(uri);
}
return null;
}
}
public List<Namespace> declaredNamespaces() {
BackedList answer = createResultList();
// if (getNamespaceURI().length() > 0) {
//
// answer.addLocal(getNamespace());
//
// }
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Namespace) {
answer.addLocal(object);
}
}
} else {
if (contentShadow instanceof Namespace) {
answer.addLocal(contentShadow);
}
}
return answer;
}
public List<Namespace> additionalNamespaces() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
BackedList answer = createResultList();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Namespace) {
Namespace namespace = (Namespace) object;
if (!namespace.equals(getNamespace())) {
answer.addLocal(namespace);
}
}
}
return answer;
} else {
if (contentShadow instanceof Namespace) {
Namespace namespace = (Namespace) contentShadow;
if (namespace.equals(getNamespace())) {
return createEmptyList();
}
return createSingleResultList(namespace);
} else {
return createEmptyList();
}
}
}
public List additionalNamespaces(String defaultNamespaceURI) {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
BackedList answer = createResultList();
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Namespace) {
Namespace namespace = (Namespace) object;
if (!defaultNamespaceURI.equals(namespace.getURI())) {
answer.addLocal(namespace);
}
}
}
return answer;
} else {
if (contentShadow instanceof Namespace) {
Namespace namespace = (Namespace) contentShadow;
if (!defaultNamespaceURI.equals(namespace.getURI())) {
return createSingleResultList(namespace);
}
}
}
return createEmptyList();
}
// Processing instruction API
public List<ProcessingInstruction> processingInstructions() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
BackedList answer = createResultList();
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof ProcessingInstruction) {
answer.addLocal(object);
}
}
return answer;
} else {
if (contentShadow instanceof ProcessingInstruction) {
return createSingleResultList(contentShadow);
}
return createEmptyList();
}
}
public List<ProcessingInstruction> processingInstructions(String target) {
final Object shadow = content;
if (shadow instanceof List) {
List list = (List) shadow;
BackedList answer = createResultList();
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) object;
if (target.equals(pi.getName())) {
answer.addLocal(pi);
}
}
}
return answer;
} else {
if (shadow instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) shadow;
if (target.equals(pi.getName())) {
return createSingleResultList(pi);
}
}
return createEmptyList();
}
}
public ProcessingInstruction processingInstruction(String target) {
final Object shadow = content;
if (shadow instanceof List) {
List list = (List) shadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) object;
if (target.equals(pi.getName())) {
return pi;
}
}
}
} else {
if (shadow instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) shadow;
if (target.equals(pi.getName())) {
return pi;
}
}
}
return null;
}
public boolean removeProcessingInstruction(String target) {
final Object shadow = content;
if (shadow instanceof List) {
List list = (List) shadow;
for (Iterator iter = list.iterator(); iter.hasNext();) {
Object object = iter.next();
if (object instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) object;
if (target.equals(pi.getName())) {
iter.remove();
return true;
}
}
}
} else {
if (shadow instanceof ProcessingInstruction) {
ProcessingInstruction pi = (ProcessingInstruction) shadow;
if (target.equals(pi.getName())) {
this.content = null;
return true;
}
}
}
return false;
}
public Element element(String name) {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Element) {
Element element = (Element) object;
if (name.equals(element.getName())) {
return element;
}
}
}
} else {
if (contentShadow instanceof Element) {
Element element = (Element) contentShadow;
if (name.equals(element.getName())) {
return element;
}
}
}
return null;
}
public Element element(QName qName) {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Object object = list.get(i);
if (object instanceof Element) {
Element element = (Element) object;
if (qName.equals(element.getQName())) {
return element;
}
}
}
} else {
if (contentShadow instanceof Element) {
Element element = (Element) contentShadow;
if (qName.equals(element.getQName())) {
return element;
}
}
}
return null;
}
public Element element(String name, Namespace namespace) {
return element(getDocumentFactory().createQName(name, namespace));
}
public void setContent(List<Node> content) {
contentRemoved();
if (content instanceof ContentListFacade) {
content = ((ContentListFacade) content).getBackingList();
}
if (content == null) {
this.content = null;
} else {
int size = content.size();
List newContent = createContentList(size);
for (int i = 0; i < size; i++) {
Object object = content.get(i);
if (object instanceof Node) {
Node node = (Node) object;
Element parent = node.getParent();
if ((parent != null) && (parent != this)) {
node = (Node) node.clone();
}
newContent.add(node);
childAdded(node);
} else if (object != null) {
String text = object.toString();
Node node = getDocumentFactory().createText(text);
newContent.add(node);
childAdded(node);
}
}
this.content = newContent;
}
}
public void clearContent() {
if (content != null) {
contentRemoved();
content = null;
}
}
public Node node(int index) {
if (index >= 0) {
final Object contentShadow = content;
Object node;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
if (index >= list.size()) {
return null;
}
node = list.get(index);
} else {
node = (index == 0) ? contentShadow : null;
}
if (node != null) {
if (node instanceof Node) {
return (Node) node;
} else {
return new DefaultText(node.toString());
}
}
}
return null;
}
public int indexOf(Node node) {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
return list.indexOf(node);
} else {
if ((contentShadow != null) && contentShadow.equals(node)) {
return 0;
} else {
return -1;
}
}
}
public int nodeCount() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
return list.size();
} else {
return (contentShadow != null) ? 1 : 0;
}
}
public Iterator<Node> nodeIterator() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
List list = (List) contentShadow;
return list.iterator();
} else {
if (contentShadow != null) {
return createSingleIterator(contentShadow);
} else {
return EMPTY_ITERATOR;
}
}
}
public List<Attribute> attributes() {
return new ContentListFacade(this, attributeList());
}
public void setAttributes(List<Attribute> attributes) {
if (attributes instanceof ContentListFacade) {
attributes = ((ContentListFacade) attributes).getBackingList();
}
this.attributes = attributes;
}
public Iterator<Attribute> attributeIterator() {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
return list.iterator();
} else if (attributesShadow != null) {
return createSingleIterator(attributesShadow);
} else {
return EMPTY_ITERATOR;
}
}
public Attribute attribute(int index) {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
return (Attribute) list.get(index);
} else if ((attributesShadow != null) && (index == 0)) {
return (Attribute) attributesShadow;
} else {
return null;
}
}
public int attributeCount() {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
return list.size();
} else {
return (attributesShadow != null) ? 1 : 0;
}
}
public Attribute attribute(String name) {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Attribute attribute = (Attribute) list.get(i);
if (name.equals(attribute.getName())) {
return attribute;
}
}
} else if (attributesShadow != null) {
Attribute attribute = (Attribute) attributesShadow;
if (name.equals(attribute.getName())) {
return attribute;
}
}
return null;
}
public Attribute attribute(QName qName) {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
int size = list.size();
for (int i = 0; i < size; i++) {
Attribute attribute = (Attribute) list.get(i);
if (qName.equals(attribute.getQName())) {
return attribute;
}
}
} else if (attributesShadow != null) {
Attribute attribute = (Attribute) attributesShadow;
if (qName.equals(attribute.getQName())) {
return attribute;
}
}
return null;
}
public Attribute attribute(String name, Namespace namespace) {
return attribute(getDocumentFactory().createQName(name, namespace));
}
public void add(Attribute attribute) {
if (attribute.getParent() != null) {
String message = "The Attribute already has an existing parent \""
+ attribute.getParent().getQualifiedName() + "\"";
throw new IllegalAddException(this, attribute, message);
}
if (attribute.getValue() == null) {
// try remove a previous attribute with the same
// name since adding an attribute with a null value
// is equivalent to removing it.
Attribute oldAttribute = attribute(attribute.getQName());
if (oldAttribute != null) {
remove(oldAttribute);
}
} else {
if (attributes == null) {
attributes = attribute;
} else {
attributeList().add(attribute);
}
childAdded(attribute);
}
}
public boolean remove(Attribute attribute) {
boolean answer = false;
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
List list = (List) attributesShadow;
answer = list.remove(attribute);
if (!answer) {
// we may have a copy of the attribute
Attribute copy = attribute(attribute.getQName());
if (copy != null) {
list.remove(copy);
answer = true;
}
}
} else if (attributesShadow != null) {
if (attribute.equals(attributesShadow)) {
this.attributes = null;
answer = true;
} else {
// we may have a copy of the attribute
Attribute other = (Attribute) attributesShadow;
if (attribute.getQName().equals(other.getQName())) {
attributes = null;
answer = true;
}
}
}
if (answer) {
childRemoved(attribute);
}
return answer;
}
// Implementation methods
// -------------------------------------------------------------------------
protected void addNewNode(Node node) {
final Object contentShadow = content;
if (contentShadow == null) {
this.content = node;
} else {
if (contentShadow instanceof List) {
List list = (List) contentShadow;
list.add(node);
} else {
List list = createContentList();
list.add(contentShadow);
list.add(node);
this.content = list;
}
}
childAdded(node);
}
protected boolean removeNode(Node node) {
boolean answer = false;
final Object contentShadow = content;
if (contentShadow != null) {
if (contentShadow == node) {
this.content = null;
answer = true;
} else if (contentShadow instanceof List) {
List list = (List) contentShadow;
answer = list.remove(node);
}
}
if (answer) {
childRemoved(node);
}
return answer;
}
protected List contentList() {
final Object contentShadow = content;
if (contentShadow instanceof List) {
return (List) contentShadow;
} else {
List list = createContentList();
if (contentShadow != null) {
list.add(contentShadow);
}
this.content = list;
return list;
}
}
protected List attributeList() {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
return (List) attributesShadow;
} else if (attributesShadow != null) {
List list = createAttributeList();
list.add(attributesShadow);
this.attributes = list;
return list;
} else {
List list = createAttributeList();
this.attributes = list;
return list;
}
}
protected List attributeList(int size) {
final Object attributesShadow = this.attributes;
if (attributesShadow instanceof List) {
return (List) attributesShadow;
} else if (attributesShadow != null) {
List list = createAttributeList(size);
list.add(attributesShadow);
this.attributes = list;
return list;
} else {
List list = createAttributeList(size);
this.attributes = list;
return list;
}
}
protected void setAttributeList(List attributeList) {
this.attributes = attributeList;
}
protected DocumentFactory getDocumentFactory() {
DocumentFactory factory = qname.getDocumentFactory();
return (factory != null) ? factory : DOCUMENT_FACTORY;
}
}
/*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name "DOM4J" must not be used to endorse or promote products derived
* from this Software without prior written permission of MetaStuff, Ltd. For
* written permission, please contact dom4j-info@metastuff.com.
*
* 4. Products derived from this Software may not be called "DOM4J" nor may
* "DOM4J" appear in their names without prior written permission of MetaStuff,
* Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
*
* 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
*
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*/