blob: 3b0843747f2897abc0ebb875c0d5df1452a42d6f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2012 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation
*
******************************************************************************/
package org.eclipse.persistence.tools.mapping.orm.dom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.persistence.tools.mapping.orm.ExternalForm;
import org.eclipse.persistence.tools.utility.ObjectTools;
import org.eclipse.persistence.tools.utility.StringTools;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* This abstract implementation of an {@link ExternalForm} defines common behavior for accessing and
* manipulating an XML document.
* <p>
* Provisional API: This interface is part of an interim API that is still under development and
* expected to change significantly before reaching stability. It is available at this early stage
* to solicit feedback from pioneering adopters on the understanding that any code that uses this
* API will almost certainly be broken (repeatedly) as the API evolves.<p>
*
* @see ExternalForm
*
* @version 2.5
* @author TopLink Workbench Team
*/
@SuppressWarnings("nls")
public abstract class AbstractExternalForm implements ExternalForm {
/**
* A list of attribute names that will be used to insert a property at the right position.
*/
private List<String> attributeNamesOrder;
/**
* A list of element names that will be used to insert a new child element at the right position.
*/
private List<String> elementNamesOrder;
/**
* The parent of this external form or <code>null</code> if this is the root object.
*/
private AbstractExternalForm parent;
/**
* The attribute name of the child text node for version.
*/
public static final String VERSION = "version";
/**
* The XML attribute identifier for the xml namespace.
*/
protected static final String XMLNS_ATTRIBUTE = "xmlns";
public static final java.lang.String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
public static final java.lang.String XMLNS_XSI = "xmlns:xsi";
/**
* The XML schema namespace.
*/
protected static final String XSD_URI = "http://www.w3.org/2001/XMLSchema";
/**
* The XML attribute identifier for the schema location URI.
*/
protected static final String XSD_URI_ATTRIBUTE = "xsi:schemaLocation";
public static final java.lang.String XSI_SLOC = "xsi:schemaLocation";
public static final java.lang.String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
/**
* Creates a new <code>AbstractExternalForm</code>.
*
* @param parent The parent of this external form or <code>null</code> if this is the root object
*/
protected AbstractExternalForm(AbstractExternalForm parent) {
super();
this.parent = parent;
this.initialize();
}
/**
* Adds a new child element to the element represented by the given parent external form. The
* child element will be added at the end of the list of children.
*
* @param parent The external form representing the parent element where the child element will
* be added
* @param elementName The name of the new child element
* @return The newly created child element
*/
protected final Element addChild(AbstractExternalForm parent, String elementName) {
Element element = parent.getElement();
if (element == null) {
element = parent.addSelf();
}
return addChild(element, elementName);
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
*
* @param parent The external form representing the parent element where the child element will
* be added
* @param elementName The name of the new child element
* @param index The index of insertion within the collection of children
* @return The newly created child element
*/
protected final Element addChild(AbstractExternalForm parent, String elementName, int index) {
Element element = parent.getElement();
if (element == null) {
element = parent.addSelf();
}
return addChild(element, elementName, index);
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
*
* @param parent The external form representing the parent element where the child element will
* be added
* @param elementName The name of the new child element
* @param index The index of insertion within the collection of children
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created child element
*/
protected final Element addChild(AbstractExternalForm parent,
String elementName,
int index,
List<String> elementNamesOrder) {
Element element = parent.getElement();
if (element == null) {
element = parent.addSelf();
}
return addChild(element, elementName, index, elementNamesOrder);
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
* <p>
* Note: This method is used when the child elements have an order.
*
* @param parent The external form representing the parent element where the child element will
* be added
* @param elementName The name of the new child element
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created child element
*/
protected final Element addChild(AbstractExternalForm parent,
String elementName,
List<String> elementNamesOrder) {
Element element = parent.getElement();
if (element == null) {
element = parent.addSelf();
}
return addChild(element, elementName, elementNamesOrder);
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @return The newly created child element
*/
protected Element addChild(Element element, String elementName) {
return addChild(element, elementName, getElementNamesOrder());
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param index The index of insertion within the collection of children
* @return The newly created child element
*/
protected final Element addChild(Element element,
String elementName,
int index) {
// Retrieve the child at the specified index in order to insert the new
// child after it
List<Element> children = getChildren(element);
Element child = index < children.size() ? children.get(index) : null;
// Insert the new child
Element childElement = getDocument().createElement(elementName);
element.insertBefore(childElement, child);
return childElement;
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
* <p>
* Note: This method is used when the child elements have an order.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param index The index of insertion within the collection of children
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created child element
*/
protected final Element addChild(Element element,
String elementName,
int index,
List<String> elementNamesOrder) {
// Retrieve the child at the specified index in order to insert the new
// child after it
List<Element> children = getChildren(element, elementName);
Element elementOfInsertion = index < children.size() ? children.get(index) : null;
// No element of insertion was found, use the list instead
if (elementOfInsertion == null) {
elementOfInsertion = elementOfInsertion(element, elementName, elementNamesOrder);
}
// Insert the new child node at the right location
Element childElement = getDocument().createElement(elementName);
element.insertBefore(childElement, elementOfInsertion);
return childElement;
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of children.
* <p>
* Note: This method is used when the child elements have an order.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created child element
*/
protected final Element addChild(Element element,
String elementName,
List<String> elementNamesOrder) {
// Create the child node
Element childElement = getDocument().createElement(elementName);
// Insert the new child node at the right location
Element elementOfInsertion = elementOfInsertion(element, elementName, elementNamesOrder);
element.insertBefore(childElement, elementOfInsertion);
return childElement;
}
/**
* Adds a new child element to the element represented by this external form. The child element
* will be added at the end of the list of element's children.
*
* @param elementName The name of the new child element
* @return The newly created child element
*/
protected final Element addChild(String elementName) {
Element element = getElement();
if (element == null) {
element = addSelf();
}
return addChild(element, elementName);
}
/**
* Adds a new child element to the given element. The child element will be added at the end of
* the list of element's children.
*
* @param elementName The name of the new child element
* @param index The index of insertion within the children
* @return The newly created child element
*/
protected final Element addChild(String elementName, int index) {
Element element = getElement();
if (element == null) {
element = addSelf();
}
return addChild(element, elementName, index);
}
/**
* Adds a new child element to the element represented by this external form. The child element
* will be added at the end of the list of element's children.
*
* @param elementName The name of the new child element
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created child element
*/
protected final Element addChild(String elementName, List<String> elementNamesOrder) {
Element element = getElement();
if (element == null) {
element = addSelf();
}
return addChild(element, elementName, elementNamesOrder);
}
/**
* Adds a child text node to the given parent element.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param value The node's text
* @return The newly created element
*/
protected final Element addChildTextNode(Element element, String elementName, String value) {
return addChildTextNode(element, elementName, value, getElementNamesOrder());
}
/**
* Adds a child text node to the given parent element.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param value The node's text
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created element
*/
protected final Element addChildTextNode(Element element,
String elementName,
String value,
List<String> elementNamesOrder) {
// It seems we can't create a text node with a value only containing
// white spaces, so we ignore the addition
if (StringTools.isBlank(value)) {
return null;
}
// Create the child text node
Element childElement = getDocument().createElement(elementName);
Text text = getDocument().createTextNode(value);
text.setNodeValue(value);
childElement.appendChild(text);
// Insert the new child text node at the right location
Element elementOfInsertion = elementOfInsertion(element, elementName, elementNamesOrder);
element.insertBefore(childElement, elementOfInsertion);
return childElement;
}
/**
* Adds a child text node to the given parent {@link Element}.
*
* @param elementName The name of the new child {@link Element}
* @param value The node's text
* @return The newly created {@link Element}
*/
protected final Element addChildTextNode(String elementName, String value) {
return addChildTextNode(elementName, value, getElementNamesOrder());
}
/**
* Adds a child text node to the given parent {@link Element}.
*
* @param elementName The name of the new child {@link Element}
* @param value The node's text
* @param elementNamesOrder The list of element names used to determine the insertion point
* @return The newly created {@link Element}
*/
protected final Element addChildTextNode(String elementName, String value, List<String> elementNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return null;
}
if (element == null) {
element = addSelf();
}
return addChildTextNode(element, elementName, value, elementNamesOrder);
}
/**
* Adds a new child element to the parent element that represents this model.
*
* @return The newly created child element
*/
public Element addSelf() {
return addSelf(getElementName());
}
/**
* Adds a new child element to the parent element that represents this model.
*
* @param elementNamesOrder The list of element names used to determine the
* insertion point
* @return The newly created child element
*/
protected Element addSelf(List<String> elementNamesOrder) {
return addSelf(getElementName(), elementNamesOrder);
}
/**
* Adds a new child element to the parent {@link Element} that represents this model.
*
* @param elementName The new name of the node
* @return The newly created child element
*/
protected Element addSelf(String elementName) {
return addSelf(elementName, getParent().getElementNamesOrder());
}
/**
* Adds a new child element to the parent element that represents this model.
*
* @param elementName The new name of the node
* @param elementNamesOrder The list of element names used to determine the
* insertion point
* @return The newly created child element
*/
protected Element addSelf(String elementName, List<String> elementNamesOrder) {
return addChild(getParent(), elementName, elementNamesOrder);
}
/**
* Adds an xmlns: attribute to the given element to register the given prefix. Does no checking
* for uniqueness. Also doesn't handle setting default namespace.
*/
protected void addXmlns(Element ownerElement, String prefix, String uri) {
ownerElement.setAttributeNS(XMLNS_URI, "xmlns:" + prefix, uri);
}
/**
* Creates a list of attribute names that will be used to insert a property at the right position.
*
* @return The list of properties specifying the order
*/
protected List<String> buildAttributeNamesOrder() {
return Collections.emptyList();
}
/**
* Creates a list of element names that will be used to insert a new child {@link Element} at the
* right position.
*
* @return The list of element names specifying the order
*/
protected List<String> buildElementNamesOrder() {
return Collections.emptyList();
}
/**
* Creates a fully qualified name by prepending the prefix to the given name.
*
* @param name The name to qualify with the prefix
* @return The fully qualified name if a prefix exists; otherwise the given
* name is returned
*/
protected final String buildQualifiedName(String name) {
String prefix = getPrefix();
if (prefix == null) {
return name;
}
StringBuilder qualifiedName = new StringBuilder();
qualifiedName.append(prefix);
qualifiedName.append(":");
qualifiedName.append(name);
return qualifiedName.toString();
}
/**
* Retrieves the element that should follow the element with the given name by using the list of
* ordered element names.
*
* @param element The element to which a new child element will be added
* @param elementName The name of the new child element
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected Element elementOfInsertion(Element element,
String elementName,
List<String> elementNamesOrder) {
return (Element) nodeOfInsertion(
element,
getChildren(element),
elementName,
elementNamesOrder
);
}
/**
* Retrieves the {@link Text} node from the given element if one exists.
*
* @param element The {@link Element} from which its {@link Text} node will be returned
* @return The child {@link Text} node if it exists or <code>null</code> if none was found
*/
private Text findTextNode(Element element) {
NodeList children = element.getChildNodes();
if (children == null) {
return null;
}
for (int index = children.getLength(); --index >= 0; ) {
Node childNode = children.item(index);
if (isText(childNode)) {
return (Text) childNode;
}
}
return null;
}
/**
* Retrieves all the children of the element represented by this external form, elements and
* non-elements are included in the list.
*
* @return The list of children or an empty list if no children are present
*/
protected final List<Node> getAllChildren() {
Element element = getElement();
if (element != null) {
return getAllChildren(element);
}
return Collections.emptyList();
}
/**
* Retrieves all the children of the given element, elements and non-elements
* are included in the list.
*
* @param node The node to retrieve its children
* @return The list of children or an empty list if no children are present
*/
protected final List<Node> getAllChildren(Node node) {
List<Node> children = new ArrayList<Node>();
NodeList childrenList = node.getChildNodes();
if (childrenList != null) {
for (int index = childrenList.getLength(); --index >= 0;) {
Node child = childrenList.item(index);
children.add(0, child);
}
}
return children;
}
/**
* Retrieves the count of the children the element represented by this external form. The count
* includes any type of child (elements and comments).
*
* @return The total count of children
*/
protected final int getAllChildrenSize() {
Element element = getElement();
if (element != null) {
return getAllChildrenSize(element);
}
return 0;
}
/**
* Retrieves all the children of the given node.
*
* @param node The parent node for which its children are requested
* @return The children of the given node or an empty list is returned if none was found
*/
protected final int getAllChildrenSize(Node node) {
NodeList childrenList = node.getChildNodes();
if (childrenList != null) {
return childrenList.getLength();
}
return 0;
}
/**
* Retrieves an attribute's value associated with the given property name from the given element.
*
* @param element The element used to retrieve the value of one of its properties
* @param attributeName The attribute name to retrieve it's value
* @return The value mapped to the given property name; an empty string is returned if it
* couldn't be retrieved
*/
protected final String getAttribute(Element element, String attributeName) {
if (element.hasAttribute(attributeName)) {
return element.getAttribute(attributeName);
}
return null;
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final String getAttribute(String attributeName) {
Element element = getElement();
if (element != null) {
return getAttribute(element, attributeName);
}
return null;
}
/**
* Returns the order of the attributes of the element represented by this external form.
*
* @return The list of property names that determines the order of insertion
*/
protected final List<String> getAttributeNamesOrder() {
return attributeNamesOrder;
}
/**
* Retrieves an attribute's value associated with the given property name from the given element.
*
* @param element The element used to retrieve the value of one of its properties
* @param attributeName The name of the attribute, which will be prepended by the namespace
* @return The value mapped to the given property name; an empty string is returned if it
* couldn't be retrieved
*/
protected final String getAttributeNS(Element element, String attributeName) {
if (element.hasAttributeNS(XSI_URI, attributeName)) {
return element.getAttributeNS(XSI_URI, attributeName);
}
return null;
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param attributeName The name of the attribute, which will be prepended by the namespace
* @return The attribute's value
*/
protected final String getAttributeNS(String attributeName) {
Element element = getElement();
if (element != null) {
return getAttributeNS(element, attributeName);
}
return null;
}
/**
* Retrieves the list of attributes for the given element.
*
* @param element The element to retrieve its list of attributes
* @return The attributes for the given element
*/
private List<Attr> getAttributes(Element element) {
List<Attr> attributes = new ArrayList<Attr>();
NamedNodeMap map = element.getAttributes();
if (map != null) {
for (int index = map.getLength(); --index >= 0;) {
Node node = map.item(index);
if (isAttribute(node)) {
attributes.add(0, (Attr) node);
}
}
}
return attributes;
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param element The element where the attribute's value is located
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final Boolean getBooleanAttribute(Element element, String attributeName) {
String value = getAttribute(element, attributeName);
if (value == null) {
return null;
}
return Boolean.valueOf(value);
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final Boolean getBooleanAttribute(String attributeName) {
Element element = getElement();
if (element == null) {
return null;
}
return getBooleanAttribute(element, attributeName);
}
/**
* Retrieves the {@link Element} with the given name.
*
* @param parent The parent of this external form used to retrieve the parent element
* @param elementName The name of the child to retrieve if it could not be found
*/
protected final Element getChild(AbstractExternalForm parent, String elementName) {
return getChild(parent.getElement(), elementName);
}
/**
* Retrieves the {@link Element} with the given name.
*
* @param parent The parent of this external form used to retrieve the parent element
* @param elementName The name of the child to retrieve
* @param index The position of the child to retrieve among the children
* @return The {@link Element} with the given name or <code>null</code> if it could not be found
*/
protected final Element getChild(AbstractExternalForm parent, String elementName, int index) {
return getChild(parent.getElement(), elementName, index);
}
/**
* Retrieves the XML {@link Element} with the given name that is the direct child of the given
* parent node.
*
* @param node The node for which one of its children is requested
* @param index The position of the child to retrieve among the children
* @return The {@link Element} at the given position if it was found; <code>null</code> otherwise
*/
protected final Element getChild(Node node, int index) {
List<Element> children = getChildren(node);
if (index >= children.size()) {
return null;
}
return children.get(index);
}
/**
* Retrieves the XML {@link Element} with the given name that is the direct child of the given node.
*
* @param node The parent node for which one of its children is requested
* @param elementName The name of the children to retrieve
* @return The {@link Element} with the given name if it was found; <code>null</code> otherwise
*/
protected final Element getChild(Node node, String elementName) {
for (Element child : getChildren(node)) {
if (ObjectTools.equals(child.getNodeName(), elementName)) {
return child;
}
}
return null;
}
/**
* Retrieves the {@link Element} with the given name.
*
* @param node The parent element from which to search for the child element
* @param elementName The name of the child to retrieve
* @param index The position of the child to retrieve among the children
* @return The {@link Element} with the given name or <code>null</code> if it could not be found
*/
protected final Element getChild(Node node, String elementName, int index) {
if (index < 0) {
return null;
}
List<Element> children = getChildren(node, elementName);
if (index >= children.size()) {
return null;
}
return children.get(index);
}
/**
* Retrieves the {@link Element} with the given name that is a child of the {@link Element}
* represented by this model.
*
* @param elementName The name of the child element to retrieve
* @return The {@link Element} with the given name or <code>null</code> if it could not be found
*/
protected final Element getChild(String elementName) {
Element element = getElement();
if (element != null) {
element = getChild(element, elementName);
}
return element;
}
/**
* Retrieves the {@link Element} with the given name that is a child of the {@link Element}
* represented by this model.
*
* @param elementName The name of the child element to retrieve
* @param index
* @return The {@link Element} with the given name or <code>null</code> if it could not be found
*/
protected final Element getChild(String elementName, int index) {
Element element = getElement();
if (element != null) {
element = getChild(element, elementName, index);
}
return element;
}
/**
* Retrieves the attribute's value associated with the given attribute name that is defined in
* the child element with the given name.
*
* @param childName The name of the child for which the attribute's value is retrieved
* @param attributeName The name of the attribute to retrieve its value
* @return The value of the attribute
*/
protected final String getChildAttribute(String childName, String attributeName) {
Element element = getChild(childName);
if (element == null) {
return null;
}
return getAttribute(element, attributeName);
}
/**
* Returns the <code>Boolean</code> representation of the child node's text.
*
* @param elementName The name of the child element to retrieve its value
* @return The <code>Boolean</code> value of the child node's value
*/
protected final Boolean getChildBooleanNode(Node element, String elementName) {
String value = getChildTextNode(element, elementName);
if (value != null) {
return Boolean.valueOf(value);
}
return null;
}
/**
* Returns the <code>Boolean</code> representation of the child node's text.
*
* @param elementName The name of the child element to retrieve its value
* @return The <code>Boolean</code> value of the child node's value
*/
protected final Boolean getChildBooleanNode(String elementName) {
Element element = getElement();
if (element != null) {
return getChildBooleanNode(element, elementName);
}
return null;
}
/**
* Returns the {@link Enum} representation of the child node's text.
*
* @param node The parent node to retrieve its child
* @param elementName The name of the child to retrieve
* @param enumClass The type of the enumeration used to retrieve the constant
* @param <T> The type of the enumeration
* @return The {@link Enum} value of the child node's value
*/
protected final <T extends Enum<T>> T getChildEnumNode(Node node,
String elementName,
Class<T> enumClass) {
String value = getChildTextNode(node, elementName);
if (value != null) {
try {
return Enum.valueOf(enumClass, value);
}
catch (Exception e) {
// Ignore, it's not a valid enum constant
}
}
return null;
}
/**
* Returns the {@link Enum} representation of the child node's text.
*
* @param elementName The name of the child to retrieve
* @param enumClass The type of the enumeration used to retrieve the constant
* @param <T> The type of the enumeration
* @return The {@link Enum} value of the child node's value
*/
protected final <T extends Enum<T>> T getChildEnumNode(String elementName, Class<T> enumClass) {
Element element = getElement();
if (element != null) {
return getChildEnumNode(element, elementName, enumClass);
}
return null;
}
/**
* Returns the {@link Integer} value of a child text node that is the child of the given element.
*
* @param element The parent element
* @param elementName The name of the child element to retrieve its value
* @return The {@link Integer} of the child element or <code>null</code> if the element is not defined
*/
protected final Integer getChildIntegerNode(Node element, String elementName) {
String value = getChildTextNode(element, elementName);
if (value == null) {
return null;
}
try {
return Integer.valueOf(value);
}
catch (Exception e) {
return null;
}
}
/**
* Returns the {@link Integer} value of a child text node that is the child of the element
* represented by this external form.
*
* @param elementName The name of the child element to retrieve its value
* @return The {@link Integer} of the child element or <code>null</code> if the element is not defined
*/
protected final Integer getChildIntegerNode(String elementName) {
Element element = getElement();
if (element != null) {
return getChildIntegerNode(element, elementName);
}
return null;
}
/**
* Retrieves the elements that are the direct children of the given parent node.
*
* @return The {@link Element}s that are children of the parent node or an empty list is returned
* if none was found
*/
protected final List<Element> getChildren() {
Element element = getElement();
if (element != null) {
return getChildren(element);
}
return Collections.emptyList();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param node The node for which its children are requested
* @return The {@link Element}s that are children of the parent node or an empty list is returned
* if none was found
*/
protected final List<Element> getChildren(Node node) {
List<Element> children = new ArrayList<Element>();
NodeList childrenList = node.getChildNodes();
if (childrenList != null) {
for (int index = childrenList.getLength(); --index >= 0;) {
Node child = childrenList.item(index);
if (isElement(child)) {
children.add(0, (Element) child);
}
}
}
return children;
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param node The parent node for which its children are requested
* @param elementNames The collection of names that count as a child of the given node
* @return The {@link Element}s that are children of the parent node or an empty list is returned
* if none was found
*/
protected final List<Element> getChildren(Node node, Collection<String> elementNames) {
List<Element> children = getChildren(node);
for (Iterator<Element> iter = children.iterator(); iter.hasNext();) {
Element element = iter.next();
String elementName = element.getNodeName();
if (!elementNames.contains(elementName)) {
iter.remove();
}
}
return children;
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param node The parent node for which its children are requested
* @param elementName The name of the element to retrieve
* @return The {@link Element}s that are children of the parent node or an empty list is returned
* if none was found
*/
protected final List<Element> getChildren(Node node, String elementName) {
List<Element> children = getChildren(node);
for (Iterator<Element> iter = children.iterator(); iter.hasNext();) {
Element element = iter.next();
if (ObjectTools.notEquals(element.getNodeName(), elementName)) {
iter.remove();
}
}
return children;
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param elementName The name of the element to retrieve
* @return The {@link Element}s that are children of the parent node or an empty list is returned
* if none was found
*/
protected final List<Element> getChildren(String elementName) {
Element element = getElement();
if (element != null) {
return getChildren(element, elementName);
}
return Collections.emptyList();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @return The count of child nodes
*/
protected final int getChildrenSize() {
return getChildren().size();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param node The count of children for this node
* @return The count of child nodes listed under the given node
*/
protected final int getChildrenSize(Node node) {
return getChildren(node).size();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param element The parent element to retrieve the count of child nodes it has with the given
* element name
* @param elementNames The collection of names that count as a child of the given node
* @return The count of child nodes with the given element name
*/
protected final int getChildrenSize(Node element, Collection<String> elementNames) {
return getChildren(element, elementNames).size();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param element The parent element to retrieve the count of child nodes it has with the given
* element name
* @param elementName The name of the element to retrieve
* @return The count of child nodes with the given element name
*/
protected final int getChildrenSize(Node element, String elementName) {
return getChildren(element, elementName).size();
}
/**
* Retrieves the XML {@link Element}s that are the direct children of the given parent node.
*
* @param elementName The name of the element to retrieve
* @return The count of child nodes with the given element name
*/
protected final int getChildrenSize(String elementName) {
return getChildren(elementName).size();
}
/**
* Returns the texts of the text nodes that are the children of the given parent.
* <p>
* Form: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param node The parent element
* @param elementName The name of the child element to retrieve its value
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final List<String> getChildrenTextNode(Node node, String elementName) {
List<String> values = new ArrayList<String>();
for (Element element : getChildren(node, elementName)) {
values.add(element.getTextContent());
}
return values;
}
/**
* Returns the texts of the text nodes that are the children of the given parent.
* <p>
* Form: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param elementName The name of the child element to retrieve its value
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final List<String> getChildrenTextNode(String elementName) {
Element element = getElement();
if (element != null) {
return getChildrenTextNode(element, elementName);
}
return Collections.emptyList();
}
/**
* Returns the text of a child node that is the child of the given element.
* <p>Form: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param node The parent node
* @param elementName The name of the child element to retrieve its value
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final String getChildTextNode(Node node, String elementName) {
Element child = getChild(node, elementName);
if (child != null) {
return getTextNode(child);
}
return null;
}
/**
* Returns the child node that is the child of the given element with the given text.
* <p>Form: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param node The parent node
* @param elementName The name of the child element to retrieve its value
* @param text The text of the child element to retrieve its {@link TextRange}
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final Element getChildTextNode(Node node, String elementName, String text) {
for (Element child : getChildren(node, elementName)) {
String childText = getTextNode(child);
if (childText.equals(text)) {
return child;
}
}
return null;
}
/**
* Returns the text of a child node: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param elementName The name of the child element to retrieve its value
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final String getChildTextNode(String elementName) {
Element element = getElement();
if (element != null) {
return getChildTextNode(element, elementName);
}
return null;
}
/**
* Returns the text of a child node that is the child of the given element.
* <p>Form: &lt;elementName&gt;text&lt;/elementName&gt;.
*
* @param childName The child to retrieve it's child text node's value
* @param elementName The name of the child element to retrieve its value
* @return The text of the child element or <code>null</code> if the element is not defined
*/
protected final String getChildTextNode(String childName, String elementName) {
Element child = getChild(childName);
if (child != null) {
return getChildTextNode(child, elementName);
}
return null;
}
/**
* Retrieves the XML document.
*
* @return The XML document
*/
protected Document getDocument() {
return getParent().getDocument();
}
/**
* Retrieves the XML {@link Element} representing this model.
*
* @return The child element retrieved from its parent element that represents the XML structure
* of this model
*/
protected Element getElement() {
return getChild(getParent(), getElementName());
}
/**
* Returns the name used to store the information in the XML document.
*
* @return A non-<code>null</code> value used to retrieve the element from the XML document
*/
protected abstract String getElementName();
/**
* Returns the order of the child elements.
*
* @return The list of element names that determines the order of insertion
*/
protected final List<String> getElementNamesOrder() {
return elementNamesOrder;
}
/**
* Retrieves the attribute's value having the given name from this model's
* element.
*
* @param element The element where the attribute's value is located
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final <T extends Enum<T>> T getEnumAttribute(Element element,
String attributeName,
Class<T> enumClass) {
String value = getAttribute(element, attributeName);
if (value != null) {
try {
return Enum.valueOf(enumClass, value);
}
catch (Exception e) {
// Invalid property
}
}
return null;
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final <T extends Enum<T>> T getEnumAttribute(String attributeName, Class<T> enumClass) {
Element element = getElement();
if (element == null) {
return null;
}
return getEnumAttribute(element, attributeName, enumClass);
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param element The element where the attribute's value is located
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final Integer getIntegerAttribute(Element element, String attributeName) {
String value = getAttribute(attributeName);
if (value != null) {
try {
return Integer.valueOf(value);
}
catch (Exception e) {
// Invalid property
}
}
return null;
}
/**
* Retrieves the attribute's value having the given name from this model's element.
*
* @param attributeName The name of the attribute
* @return The attribute's value
*/
protected final Integer getIntegerAttribute(String attributeName) {
Element element = getElement();
if (element == null) {
return null;
}
return getIntegerAttribute(element, attributeName);
}
/**
* Returns the namespace of the root element for this external form.
*
* @param uri The URI of the namespace
*/
protected String getNamespace() {
return getAttribute(XMLNS_ATTRIBUTE);
}
/**
* Retrieves the name of the given node.
* <p>
* Example: &lt;name&gt;...&lt;/name&gt; where "name" will be returned for the element.
* <p>
* Example: &lt;node "key"="value"/&gt; where "key" will be returned for the attribute.
*
* @param node The node to retrieve its name
* @return The element name of the given node
*/
protected final String getNodeName(Node node) {
return node.getNodeName();
}
/**
* Returns the parent of this object.
*
* @return The parent of this object, <code>null</code> is never returned
*/
protected AbstractExternalForm getParent() {
return parent;
}
/**
* Retrieves the XML {@link Element} representing by the parent model.
*
* @return The {@link Element} of the parent form
*/
protected final Element getParentElement() {
return getParent().getElement();
}
/**
* Retrieves the prefix representing the XML schema nodes. It is declared in the root element's
* properties.
*
* @return The prefix defined in the root element properties or <code>null</code> if it is not defined
*/
protected final String getPrefix() {
// The root element needs to be retrieved before acquiring a read lock
// in case the root element doesn't yet exist
Element element = getRootElement();
NamedNodeMap attributes = element.getAttributes();
if (attributes != null) {
for (int index = attributes.getLength(); --index >= 0;) {
Node node = attributes.item(index);
String localName = node.getNodeName();
String value = node.getNodeValue();
if (localName != null &&
localName.startsWith("xmlns:") &&
XSI_URI.equals(value)) {
return localName.substring("xmlns:".length());
}
}
}
return null;
}
/**
* Retrieves the root of the model object hierarchy.
*
* @return The top node of the model object hierarchy
*/
protected final AbstractExternalForm getRoot() {
return (parent == null) ? this : parent.getRoot();
}
/**
* Retrieves the root element from the XML document. If the element could not be found, it will
* be automatically added.
*
* @return The root of the XML model hierarchy
*/
protected final Element getRootElement() {
Document document = getDocument();
String rootElementName = getRoot().getElementName();
Element element = getChild(document, rootElementName);
if (element == null) {
// First make sure there are no root element with a different name
for (Element child : getChildren(document)) {
if (ObjectTools.notEquals(child.getNodeName(), rootElementName)) {
// A root element was found, simply rename it to comply
// with the document's XSD
setElementName(child, rootElementName);
return getRootElement();
}
}
// No root element was found, simply create it
element = addSelf();
}
return element;
}
/**
* Returns the schema location defined in the root element of this form.
*
* @return URI of the XML schema.
*/
protected String getSchemaLocation() {
return getAttribute(XSD_URI_ATTRIBUTE);
}
/**
* Retrieves the text content from the text node handled by this form.
*
* @return The text contained within the text node or <code>null</code> if the element does not exist
*/
protected final String getTextNode() {
Element element = getElement();
if (element != null) {
return getTextNode(element);
}
return null;
}
/**
* Retrieves the text content from the given text node.
*
* @param element The node from which the text is retrieved
* @return The text contained within the given text node
*/
protected final String getTextNode(Node element) {
return element.getTextContent();
}
/**
* Returns the version attribute value specified on this form.
*
* @return The version attribute value specified on this form
*/
public final String getVersion() {
return getAttribute(VERSION);
}
/**
* Determines whether the element represented by this external form has any children, which
* includes comments and elements.
*
* @return <code>true</code> if the element is not a leaf and has children; <code>false</code> if
* the element is a leaf
*/
protected final boolean hasAnyChildren() {
Element element = getElement();
if (element != null) {
return hasAnyChildren(element);
}
return false;
}
/**
* Determines whether the given node has any children, which includes comments and elements.
*
* @param node The node checked for having children
* @return <code>true</code> if the element is not a leaf and has children; <code>false</code> if
* the element is a leaf
*/
protected final boolean hasAnyChildren(Node node) {
return getAllChildrenSize(node) > 0;
}
/**
* Determines whether the given element has an attribute with the given name.
*
* @param element The element used to check if an attribute with the given name exists
* @param elementName The name of the attribute
* @return <code>true</code> if the attribute is present; <code>false</code> otherwise
*/
protected final boolean hasAttribute(Element element, String elementName) {
return getAttribute(element, elementName) != null;
}
/**
* Determines whether the element represented by this external form has an attribute with the
* given name.
*
* @param attributeName The name of the attribute
* @return <code>true</code> if the attribute is present; <code>false</code> otherwise
*/
protected final boolean hasAttribute(String attributeName) {
return getAttribute(attributeName) != null;
}
/**
* Determines whether the given element has an attribute NS with the given name.
*
* @param element The element used to check if an attribute NS with the given name exists
* @param elementName The name of the attribute
* @return <code>true</code> if the attribute NS is present; <code>false</code> otherwise
*/
protected final boolean hasAttributeNS(Element element, String elementName) {
return getAttributeNS(element, elementName) != null;
}
/**
* Determines whether the element represented by this external form has an attribute NS with the
* given name.
*
* @param elementName The name of the attribute
* @return <code>true</code> if the attribute NS is present; <code>false</code> otherwise
*/
protected final boolean hasAttributeNS(String elementName) {
return getAttributeNS(elementName) != null;
}
/**
* Determines whether the element represented by this external form has any attributes.
*
* @return <code>true</code> if there is at least one attribute; <code>false</code> otherwise
*/
protected final boolean hasAttributes() {
Element element = getElement();
if (element != null) {
return hasAttributes(element);
}
return false;
}
/**
* Determines whether the given element has any attributes.
*
* @param element The element to check if it has attributes
* @return <code>true</code> if there is at least one attribute; <code>false</code> otherwise
*/
protected final boolean hasAttributes(Element element) {
NamedNodeMap attributes = element.getAttributes();
if (attributes == null) {
return false;
}
return attributes.getLength() > 0;
}
/**
* Determines whether the given element has a child with the given element name.
*
* @param element The element used to check if it has a child with the given name
* @param elementName The name of the element
* @return <code>true</code> if a child with the given name was found; <code>false</code> otherwise
*/
protected final boolean hasChild(Element element, String elementName) {
return getChild(element, elementName) != null;
}
/**
* Determines whether the element represented by this external form has a child with the given
* element name.
*
* @param elementName The name of the element
* @return <code>true</code> if a child with the given name was found; <code>false</code> otherwise
*/
protected final boolean hasChild(String elementName) {
Element element = getElement();
if (element != null) {
return hasChild(element, elementName);
}
return false;
}
/**
* Determines whether the {@link Element} represented by this external form has any children,
* non-elements are not included into the check.
*
* @return <code>true</code> if the {@link Element} has at least one child; <code>false</code>
* otherwise
*/
protected final boolean hasChildren() {
Element element = getElement();
if (element != null) {
return hasChildren(element);
}
return false;
}
/**
* Determines whether the given {@link Element} has any children, non-elements are not included
* into the check.
*
* @param element The {@link Element} used to check if it has child elements
* @return <code>true</code> if the element has at least one child; <code>false</code> otherwise
*/
protected final boolean hasChildren(Element element) {
NodeList childrenList = element.getChildNodes();
int count = 0;
if (childrenList != null) {
for (int index = childrenList.getLength(); --index >= 0;) {
Node child = childrenList.item(index);
if (isElement(child)) {
count++;
}
}
return (count > 0);
}
return false;
}
/**
* Determines whether the {@link Element} represented by this external form is present in the XML
* document.
*
* @return <code>true</code> if the element exists; <code>false</code> if it does not
*/
protected final boolean hasElement() {
return getElement() != null;
}
/**
* Initializes this external form.
*/
protected void initialize() {
attributeNamesOrder = buildAttributeNamesOrder();
elementNamesOrder = buildElementNamesOrder();
}
/**
* Returns true if node is non-null and is of type ATTRIBUTE_NODE.
*/
protected boolean isAttribute(Node node) {
return isNodeType(node, Node.ATTRIBUTE_NODE);
}
/**
* Returns true if node is non-null and is of type ELEMENT_NODE.
*/
protected boolean isElement(Node node) {
return isNodeType(node, Node.ELEMENT_NODE);
}
/**
* Wrapper around {@link Node#getNodeType} test that returns false for a <code>null</code> node.
*/
protected boolean isNodeType(Node node, int type) {
return (node != null) && (node.getNodeType() == type);
}
/**
* Returns true if node is non-null and is of type TEXT_NODE.
*/
protected boolean isText(Node node) {
return isNodeType(node, Node.TEXT_NODE);
}
/**
* Retrieves the node that should follow the element with the given name by using the list of
* ordered node names.
*
* @param element The element to which a new child element will be added
* @param nodeName The name of the new node
* @param namesOrder The list of names used to determine the insertion point
* @return The node used to indicate the new node needs to be inserted before that node or
* <code>null</code> if no node was found
*/
private Node nodeOfInsertion(Element element,
List<? extends Node> children,
String nodeName,
List<String> namesOrder) {
if (namesOrder.isEmpty()) {
return null;
}
int count = namesOrder.size();
for (Node child : children) {
String childName = getNodeName(child);
for (int index = namesOrder.indexOf(nodeName) + 1; index < count; index++) {
String name = namesOrder.get(index);
if (ObjectTools.equals(childName, name)) {
return child;
}
}
}
return null;
}
/**
* Removes the given {@link Element} from its parent {@link Element}. The parent {@link Element}
* is the {@link Element} encapsulated by this model.
*
* @param element The child element to remove from its parent
*/
protected final void remove(Element element) {
Element parent = getElement();
if (parent != null) {
remove(parent, element);
}
}
/**
* Removes the given {@link Element} from its parent {@link Element}.
*
* @param element The parent of the {@link Element} to remove
* @param childElement The child to remove from its parent
*/
protected final void remove(Element element, Element childElement) {
element.removeChild(childElement);
}
/**
* Removes the child {@link Element} from its parent {@link Element} at the given position. The
* parent element is the element encapsulated by this model.
*
* @param parent The parent of this external form used to retrieve the parent element
* @param elementName The name of the child element to remove
* @param index The index of the child that has the given element name to remove
*/
protected final void removeChild(AbstractExternalForm parent, String elementName, int index) {
removeChild(parent.getElement(), elementName, index);
}
/**
* Removes the child {@link Element} from its parent {@link Element} at the given position. The
* parent {@link Element} is the element encapsulated by this model.
*
* @param element The {@link Element} from which the child at the given index will be removed
* @param elementName The name of the child {@link Element} to remove
* @param index The index of the child that has the given {@link Element} name to remove
*/
protected final void removeChild(Element element, int index) {
Element childElement = getChild(element, index);
if (childElement != null) {
remove(element, childElement);
}
}
/**
* Removes the child {@link Element} from its parent {@link Element} at the given position. The
* parent {@link Element} is the element encapsulated by this model.
*
* @param element The {@link Element} from which the child with the given name will be removed
* @param elementName The name of the child {@link Element} to remove
*/
protected final void removeChild(Element element, String elementName) {
Element childElement = getChild(element, elementName);
if (childElement != null) {
remove(element, childElement);
}
}
/**
* Removes the child element from its parent element at the given position. The parent element is
* the element encapsulated by this model.
*
* @param element The element from which the child at the given position with the given name will
* be removed
* @param elementName The name of the child element to remove
* @param index The index of the child that has the given element name to remove
*/
protected final void removeChild(Element element, String elementName, int index) {
Element childElement = getChild(element, elementName, index);
if (childElement != null) {
remove(element, childElement);
}
}
/**
* Removes the child element from its parent element. The parent element is the element
* encapsulated by this model.
*
* @param elementName The name of the child element to remove
*/
protected final void removeChild(String elementName) {
Element element = getChild(elementName);
if (element != null) {
remove(getElement(), element);
}
}
/**
* Removes the child element from its parent element at the given position. The parent element is
* the element encapsulated by this model.
*
* @param elementName The name of the child element to remove
* @param index The index of the child that has the given element name to remove
*/
protected final void removeChild(String elementName, int index) {
removeChild(getElement(), elementName, index);
}
/**
* Removes the child element from its parent element. The parent element is the element
* encapsulated by this model.
*
* @param node The node from which the children with the given name will be removed
* @param elementName The name of the child element to remove
*/
protected final void removeChildren(Node node, String elementName) {
for (Element childElement : getChildren(node, elementName)) {
node.removeChild(childElement);
}
}
/**
* Removes the child element from its parent element. The parent element is the element
* encapsulated by this model.
*
* @param elementName The name of the child element to remove
*/
protected final void removeChildren(String elementName) {
Element element = getElement();
if (element != null) {
removeChildren(element, elementName);
}
}
/**
* Removes this model's element from its parent element.
*/
public void removeSelf() {
Element element = getElement();
if ((parent != null) && (element != null)) {
parent.remove(element);
}
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(Element element, String attributeName, Boolean value) {
setAttribute(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(Element element,
String attributeName,
Boolean value,
List<String> attributeNamesOrder) {
setAttribute(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(Element element, String attributeName, Enum<?> value) {
setAttribute(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(Element element,
String attributeName,
Enum<?> value,
List<String> attributeNamesOrder) {
setAttribute(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(Element element, String attributeName, Number value) {
setAttribute(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(Element element,
String attributeName,
Number value,
List<String> attributeNamesOrder) {
setAttribute(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(Element element, String attributeName, String value) {
setAttribute(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value.
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(Element element,
String attributeName,
String value,
List<String> attributeNamesOrder) {
// Remove the attribute
if (value == null) {
element.removeAttribute(attributeName);
}
// Update the attribute's value
else if (hasAttribute(attributeName)) {
element.setAttribute(attributeName, value);
}
// Add a new attribute
else {
// Create the attribute node
Attr newAttribute = getDocument().createAttribute(attributeName);
newAttribute.setValue(value);
// Insert the new attribute node at the right location
List<Attr> attributes = getAttributes(element);
Attr elementOfInsertion = (Attr) nodeOfInsertion(element, attributes, attributeName, attributeNamesOrder);
// The attribute needs to be inserted before another attribute.
// Remove the attributes so they can be re-added in proper order
if (elementOfInsertion != null) {
int indexOfInsertion = attributes.indexOf(elementOfInsertion);
// Remove the attributes
for (int index = attributes.size(); --index >= 0; ) {
Node attributeNode = attributes.get(index);
element.removeAttribute(attributeNode.getNodeName());
}
// Inserts the new attribute at the right location
attributes.add(indexOfInsertion, newAttribute);
// Re-add the attributes
for (int index = 0; index < attributes.size(); index++) {
Attr attribute = attributes.get(index);
element.setAttributeNode(attribute);
}
}
// This will insert the attribute at the end of the list of attributes
else {
element.setAttribute(attributeName, value);
}
}
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(String attributeName, Boolean value) {
setAttribute(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(String attributeName,
Boolean value,
List<String> attributeNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return;
}
if (element == null) {
element = addSelf();
}
setAttribute(element, attributeName, value, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(String attributeName, Enum<?> value) {
setAttribute(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(String attributeName,
Enum<?> value,
List<String> attributeNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return;
}
if (element == null) {
element = addSelf();
}
setAttribute(element, attributeName, value, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(String attributeName, Number value) {
setAttribute(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(String attributeName,
Number value,
List<String> attributeNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return;
}
if (element == null) {
element = addSelf();
}
setAttribute(element, attributeName, value, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttribute(String attributeName, String value) {
setAttribute(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value.
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttribute(String attributeName,
String value,
List<String> attributeNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return;
}
if (element == null) {
element = addSelf();
}
setAttribute(element, attributeName, value, attributeNamesOrder);
}
/**
* Sets an attribute on the given element with the given value. The name will be formatted with
* the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(Element element, String attributeName, Boolean value) {
setAttributeNS(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value. The name will be formatted with
* the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(Element element,
String attributeName,
Boolean value,
List<String> attributeNamesOrder) {
setAttributeNS(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value. The name will be formatted with
* the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(Element element, String attributeName, Enum<?> value) {
setAttributeNS(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value. The name will be formatted with
* the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(Element element,
String attributeName,
Enum<?> value,
List<String> attributeNamesOrder) {
setAttributeNS(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value. The name will
* be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>,
* then the attribute will be removed
*/
protected final void setAttributeNS(Element element, String attributeName, Number value) {
setAttributeNS(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value. The name will
* be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>,
* then the attribute will be removed
*/
protected final void setAttributeNS(Element element,
String attributeName,
Number value,
List<String> attributeNamesOrder) {
setAttributeNS(
element,
attributeName,
(value != null) ? value.toString() : null,
attributeNamesOrder
);
}
/**
* Sets an attribute on the given element with the given value. The name will
* be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>,
* then the attribute will be removed
*/
protected final void setAttributeNS(Element element, String attributeName, String value) {
setAttributeNS(element, attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the given element with the given value. The name will be formatted with
* the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param element The element to have one of its attributes updated
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(Element element,
String attributeName,
String value,
List<String> attributeNamesOrder) {
StringBuilder sb = new StringBuilder();
sb.append("Update attribute: ");
sb.append(getPrefix());
sb.append(":");
sb.append(attributeName);
sb.append(" = ");
sb.append(value);
// Remove the attribute
if (value == null) {
element.removeAttributeNS(XSI_URI, attributeName);
}
// Update the attribute's value
else if (hasAttribute(attributeName)) {
attributeName = buildQualifiedName(attributeName);
element.setAttributeNS(XSI_URI, attributeName, value);
}
// Add a new attribute
else {
// Create the attribute node
attributeName = buildQualifiedName(attributeName);
Attr newAttribute = getDocument().createAttributeNS(XSI_URI, attributeName);
newAttribute.setValue(value);
// Insert the new attribute node at the right location
List<Attr> attributes = getAttributes(element);
Attr elementOfInsertion = (Attr) nodeOfInsertion(element, attributes, attributeName, attributeNamesOrder);
// The attribute needs to be inserted before another attribute.
// Remove the attributes so they can be re-added in proper order
if (elementOfInsertion != null) {
int indexOfInsertion = attributes.indexOf(elementOfInsertion);
// Remove the attributes
for (int index = attributes.size(); --index >= 0;) {
Node attributeNode = attributes.get(index);
element.removeAttribute(attributeNode.getNodeName());
}
// Inserts the new attribute at the right location
attributes.add(indexOfInsertion, newAttribute);
// Re-add the attributes
for (int index = 0, count = attributes.size(); index < count; index++) {
Attr attribute = attributes.get(index);
element.setAttributeNode(attribute);
}
}
// This will insert the attribute at the end of the list of attributes
else {
element.setAttributeNS(XSI_URI, attributeName, value);
}
}
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(String attributeName, Boolean value) {
setAttributeNS(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(String attributeName,
Boolean value,
List<String> attributeNamesOrder) {
setAttributeNS(attributeName, value != null ? value.toString() : null, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(String attributeName, Enum<?> value) {
setAttributeNS(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(String attributeName,
Enum<?> value,
List<String> attributeNamesOrder) {
setAttributeNS(attributeName, value != null ? value.toString() : null, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(String attributeName, Number value) {
setAttributeNS(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(String attributeName,
Number value,
List<String> attributeNamesOrder) {
setAttributeNS(attributeName, value != null ? value.toString() : null, attributeNamesOrder);
}
/**
* Sets an attribute on the element represented by this external form with the
* given value. The name will be formatted with the namespace URI:
* "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
*/
protected final void setAttributeNS(String attributeName, String value) {
setAttributeNS(attributeName, value, getAttributeNamesOrder());
}
/**
* Sets an attribute on the element represented by this external form with the given value. The
* name will be formatted with the namespace URI: "&lt;namespaceURI&gt;:attributeName".
*
* @param attributeName The name of the attribute
* @param value The value of the attribute. If the value is <code>null</code>, then the attribute
* will be removed
* @param attributeNamesOrder The list of attribute names used to determine the insertion
*/
protected final void setAttributeNS(String attributeName,
String value,
List<String> attributeNamesOrder) {
Element element = getElement();
if ((element == null) && (value == null)) {
return;
}
if (element == null) {
element = addSelf();
}
setAttributeNS(element, attributeName, value, attributeNamesOrder);
}
/**
* Renames the given element represented by this external form.
*
* @param element The element to rename
* @param elementName The new name of the element
*/
protected final void setElementName(Element element, String elementName) {
// First remove the existing node and add the new node
getDocument().removeChild(element);
Element newElement = addSelf(elementName, getElementNamesOrder());
// Now add the new node, which will have the new element name
// Copy all the children to the new node
for (Node childNode : getAllChildren(element)) {
newElement.appendChild(childNode);
}
}
/**
* Sets the namespace with the given one.
*
* @param uri The URI of the namespace
*/
protected final void setNamespace(String uri) {
Element element = getRootElement();
element.setAttributeNS("http://www.w3.org/2000/xmlns/", XMLNS_ATTRIBUTE, uri);
}
/**
* Sets the schema location with the given one.
*
* @param uri The URI of the XML schema
*/
protected final void setSchemaLocation(String uri) {
Element element = getRootElement();
element.setAttributeNS(XSI_URI, XSD_URI_ATTRIBUTE, uri);
}
/**
* Updates the given {@link Element}'s text value.
*
* @param element The {@link Element} to update its text value
* @param value The new value of the given {@link Element}
*/
protected final void setTextNode(Element element, String value) {
updateTextNode(element, getElementName(), value);
}
/**
* Updates this external form's {@link Element} text value.
*
* @param value The new value of this form's {@link Element}
*/
protected final void setTextNode(String value) {
updateTextNode(
getParent().getElement(),
getElementName(),
value,
getParent().getElementNamesOrder()
);
}
/**
* Sets the version attribute of this element to the provided version.
*
* @param version version attribute value.
*/
public final void setVersion(String version) {
setAttribute(VERSION, version);
}
/**
* Updates the attribute's value of a child {@link Element}.
*
* @param childName The name of the child to update one of its attributes
* @param attributeName The name of the attribute to update its value
* @param value The new value of the attribute
*/
protected final void updateChildAttribute(String childName, String attributeName, Boolean value) {
updateChildAttribute(childName, attributeName, (value != null) ? value.toString() : null);
}
/**
* Updates the attribute's value of a child {@link Element}.
*
* @param childName The name of the child to update one of its attributes
* @param attributeName The name of the attribute to update its value
* @param value The new value of the attribute
*/
protected final void updateChildAttribute(String childName, String attributeName, Enum<?> value) {
updateChildAttribute(childName, attributeName, (value != null) ? value.name() : null);
}
/**
* Updates the attribute's value of a child {@link Element}.
*
* @param childName The name of the child to update one of its attributes
* @param attributeName The name of the attribute to update its value
* @param value The new value of the attribute
*/
protected final void updateChildAttribute(String childName, String attributeName, Number value) {
updateChildAttribute(childName, attributeName, (value != null) ? value.toString() : null);
}
/**
* Updates the attribute's value of a child {@link Element}.
*
* @param childName The name of the child to update one of its attributes
* @param attributeName The name of the attribute to update its value
* @param value The new value of the attribute
*/
protected final void updateChildAttribute(String childName, String attributeName, String value) {
Element element = getChild(childName);
if ((element == null) && (value != null)) {
element = addChild(childName);
}
if (value != null) {
setAttribute(element, attributeName, value);
}
else if (element != null) {
removeChild(childName);
}
}
/**
* Updates the child text node of a child element.
*
* @param parentChildName The name of the child to retrieve its child with the given child name
* @param childName The child of a child to update its text value
* @param value The new value of the text node
*/
protected final void updateChildChildTextNode(String parentChildName,
String childName,
Boolean value) {
updateChildChildTextNode(parentChildName, childName, (value != null) ? value.toString() : null);
}
/**
* Updates the child text node of a child element.
*
* @param parentChildName The name of the child to retrieve its child with the given child name
* @param childName The child of a child to update its text value
* @param value The new value of the text node
*/
protected final void updateChildChildTextNode(String parentChildName,
String childName,
Enum<?> value) {
updateChildChildTextNode(parentChildName, childName, (value != null) ? value.name() : null);
}
/**
* Updates the child text node of a child element.
*
* @param parentChildName The name of the child to retrieve its child with the given child name
* @param childName The child of a child to update its text value
* @param value The new value of the text node
*/
protected final void updateChildChildTextNode(String parentChildName,
String childName,
Number value) {
updateChildChildTextNode(parentChildName, childName, (value != null) ? value.toString() : null);
}
/**
* Updates the child text node of a child element.
*
* @param parentChildName The name of the child to retrieve its child with the given child name
* @param childName The child of a child to update its text value
* @param value The new value of the text node
*/
protected final void updateChildChildTextNode(String parentChildName, String childName, String value) {
Element element = getChild(parentChildName);
if ((element == null) && (value != null)) {
element = addChild(parentChildName);
}
updateTextNode(element, childName, value);
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateChildTextNode(String elementName, Boolean value) {
updateChildTextNode(elementName, value, getElementNamesOrder());
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateChildTextNode(String elementName,
Boolean value,
List<String> elementNamesOrder) {
updateChildTextNode(elementName, (value != null) ? value.toString() : null, elementNamesOrder);
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateChildTextNode(String elementName, Enum<?> value) {
updateChildTextNode(elementName, value, getElementNamesOrder());
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateChildTextNode(String elementName,
Enum<?> value,
List<String> elementNamesOrder) {
updateChildTextNode(elementName, (value != null) ? value.toString() : null, elementNamesOrder);
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateChildTextNode(String elementName, Number value) {
updateChildTextNode(elementName, value, getElementNamesOrder());
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateChildTextNode(String elementName,
Number value,
List<String> elementNamesOrder) {
updateChildTextNode(elementName, (value != null) ? value.toString() : null, elementNamesOrder);
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateChildTextNode(String elementName, String value) {
updateChildTextNode(elementName, value, getElementNamesOrder());
}
/**
* Updates the child element's text with the given value. If the value is <code>null</code>, then
* the element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateChildTextNode(String elementName,
String value,
List<String> elementNamesOrder) {
Element element = getElement();
// Nothing to change
if ((element == null) && (value == null)) {
return;
}
// Automatically create the element
if (element == null) {
element = addSelf();
}
// Create or update the child text node
updateTextNode(element, elementName, value, elementNamesOrder);
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateTextNode(Element element, String elementName, Boolean value) {
updateTextNode(element, elementName, value, getElementNamesOrder());
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateTextNode(Element element,
String elementName,
Boolean value,
List<String> elementNamesOrder) {
updateTextNode(element, elementName, (value == null) ? null : value.toString(), elementNamesOrder);
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateTextNode(Element element, String elementName, Enum<?> value) {
updateTextNode(element, elementName, value, getElementNamesOrder());
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateTextNode(Element element,
String elementName,
Enum<?> value,
List<String> elementNamesOrder) {
updateTextNode(element, elementName, (value != null) ? value.toString() : null, elementNamesOrder);
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be
* added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateTextNode(Element element, String elementName, Number value) {
updateTextNode(element, elementName, value, getElementNamesOrder());
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be
* added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateTextNode(Element element,
String elementName,
Number value,
List<String> elementNamesOrder) {
updateTextNode(element, elementName, (value != null) ? value.toString() : null, elementNamesOrder);
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then it will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
*/
protected final void updateTextNode(Element element, String elementName, String value) {
updateTextNode(element, elementName, value, getElementNamesOrder());
}
/**
* Updates the child text node with the given value. If the value is <code>null</code>, then the
* child element will be removed. If the value is not <code>null</code> but the element is
* <code>null</code> then the child will be added.
*
* @param element The parent element used to retrieve the child element
* @param elementName The child element's name
* @param value The new element's text
* @param elementNamesOrder The list of element names used to determine the insertion point
*/
protected final void updateTextNode(Element element,
String elementName,
String value,
List<String> elementNamesOrder) {
// It seems we can't create a text node with a value only containing
// white spaces, so we convert it into null. Maybe there is a way to
// remove the validation?!?
if (StringTools.isBlank(value)) {
value = null;
}
Element childElement = getChild(element, elementName);
// Remove the child element if the value is null
if ((childElement != null) && (value == null)) {
remove(element, childElement);
return;
}
boolean valueNotEmpty = !StringTools.isBlank(value);
// Add a text node if the element is null and the value isn't
if ((childElement == null) && valueNotEmpty) {
addChildTextNode(element, elementName, value, elementNamesOrder);
}
// Update the element's text content
else if ((childElement != null) && valueNotEmpty) {
Text text = findTextNode(childElement);
if (text == null) {
text = getDocument().createTextNode(value);
childElement.appendChild(text);
}
else {
text.setNodeValue(value);
}
}
}
}