--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ElementImpl.java Wed Jul 05 20:50:41 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ElementImpl.java Fri Sep 25 16:42:19 2015 -0700
@@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
@@ -17,70 +18,75 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.sun.org.apache.xerces.internal.dom;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
+import org.w3c.dom.ElementTraversal;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
-
import org.w3c.dom.TypeInfo;
import com.sun.org.apache.xerces.internal.util.URI;
/**
- * Elements represent most of the "markup" and structure of the
- * document. They contain both the data for the element itself
- * (element name and attributes), and any contained nodes, including
- * document text (as children).
+ * Elements represent most of the "markup" and structure of the document. They
+ * contain both the data for the element itself (element name and attributes),
+ * and any contained nodes, including document text (as children).
* <P>
* Elements may have Attributes associated with them; the API for this is
* defined in Node, but the function is implemented here. In general, XML
* applications should retrive Attributes as Nodes, since they may contain
- * entity references and hence be a fairly complex sub-tree. HTML users will
- * be dealing with simple string values, and convenience methods are provided
- * to work in terms of Strings.
+ * entity references and hence be a fairly complex sub-tree. HTML users will be
+ * dealing with simple string values, and convenience methods are provided to
+ * work in terms of Strings.
* <P>
* ElementImpl does not support Namespaces. ElementNSImpl, which inherits from
* it, does.
+ *
* @see ElementNSImpl
*
* @xerces.internal
*
- * @author Arnaud Le Hors, IBM
+ * @author Arnaud Le Hors, IBM
* @author Joe Kesselman, IBM
* @author Andy Clark, IBM
* @author Ralf Pfeiffer, IBM
- * @since PR-DOM-Level-1-19980818.
+ * @since PR-DOM-Level-1-19980818.
*/
public class ElementImpl
- extends ParentNode
- implements Element, TypeInfo {
+ extends ParentNode
+ implements Element, ElementTraversal, TypeInfo {
//
// Constants
//
-
- /** Serialization version. */
+ /**
+ * Serialization version.
+ */
static final long serialVersionUID = 3717253516652722278L;
//
// Data
//
- /** Element name. */
+ /**
+ * Element name.
+ */
protected String name;
- /** Attributes. */
+ /**
+ * Attributes.
+ */
protected AttributeMap attributes;
//
// Constructors
//
-
- /** Factory constructor. */
+ /**
+ * Factory constructor.
+ */
public ElementImpl(CoreDocumentImpl ownerDoc, String name) {
super(ownerDoc);
this.name = name;
@@ -88,7 +94,8 @@
}
// for ElementNSImpl
- protected ElementImpl() {}
+ protected ElementImpl() {
+ }
// Support for DOM Level 3 renameNode method.
// Note: This only deals with part of the pb. CoreDocumentImpl
@@ -97,26 +104,45 @@
if (needsSyncData()) {
synchronizeData();
}
- this.name = name;
+ if (ownerDocument.errorChecking) {
+ int colon1 = name.indexOf(':');
+ if (colon1 != -1) {
+ String msg
+ = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NAMESPACE_ERR",
+ null);
+ throw new DOMException(DOMException.NAMESPACE_ERR, msg);
+ }
+ if (!CoreDocumentImpl.isXMLName(name, ownerDocument.isXML11Version())) {
+ String msg = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "INVALID_CHARACTER_ERR", null);
+ throw new DOMException(DOMException.INVALID_CHARACTER_ERR,
+ msg);
+ }
+ }
+ this.name = name;
reconcileDefaultAttributes();
}
//
// Node methods
//
-
-
/**
- * A short integer indicating what type of node this is. The named
- * constants for this value are defined in the org.w3c.dom.Node interface.
+ * A short integer indicating what type of node this is. The named constants
+ * for this value are defined in the org.w3c.dom.Node interface.
*/
public short getNodeType() {
return Node.ELEMENT_NODE;
}
/**
- * Returns the element name
+ * Returns the node name
+ *
+ * @return the node name
*/
+ @Override
public String getNodeName() {
if (needsSyncData()) {
synchronizeData();
@@ -129,7 +155,10 @@
* from Node rather than specified on Element; in fact only Elements will
* ever have Attributes, but they want to allow folks to "blindly" operate
* on the tree as a set of Nodes.
+ *
+ * @return all Attributes
*/
+ @Override
public NamedNodeMap getAttributes() {
if (needsSyncData()) {
@@ -143,12 +172,13 @@
} // getAttributes():NamedNodeMap
/**
- * Return a duplicate copy of this Element. Note that its children
- * will not be copied unless the "deep" flag is true, but Attributes
- * are <i>always</i> replicated.
+ * Return a duplicate copy of this Element. Note that its children will not
+ * be copied unless the "deep" flag is true, but Attributes are
+ * {@code always} replicated.
*
* @see org.w3c.dom.Node#cloneNode(boolean)
*/
+ @Override
public Node cloneNode(boolean deep) {
ElementImpl newnode = (ElementImpl) super.cloneNode(deep);
@@ -160,10 +190,12 @@
} // cloneNode(boolean):Node
- /**
- * DOM Level 3 WD - Experimental.
- * Retrieve baseURI
+ /**
+ * DOM Level 3 WD - Experimental. Retrieve baseURI
+ *
+ * @return the baseURI
*/
+ @Override
public String getBaseURI() {
if (needsSyncData()) {
@@ -174,62 +206,61 @@
// 1. The base URI specified by an xml:base attribute on the element,
// if one exists
if (attributes != null) {
- Attr attrNode = (Attr)attributes.getNamedItem("xml:base");
+ final Attr attrNode = getXMLBaseAttribute();
if (attrNode != null) {
- String uri = attrNode.getNodeValue();
- if (uri.length() != 0 ) {// attribute value is always empty string
+ final String uri = attrNode.getNodeValue();
+ if (uri.length() != 0) {// attribute value is always empty string
try {
- uri = new URI(uri).toString();
- }
- catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e) {
- // This may be a relative URI.
+ URI _uri = new URI(uri, true);
+ // If the URI is already absolute return it; otherwise it's relative and we need to resolve it.
+ if (_uri.isAbsoluteURI()) {
+ return _uri.toString();
+ }
// Make any parentURI into a URI object to use with the URI(URI, String) constructor
String parentBaseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null;
- if (parentBaseURI != null){
- try{
- uri = new URI(new URI(parentBaseURI), uri).toString();
- }
- catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex){
+ if (parentBaseURI != null) {
+ try {
+ URI _parentBaseURI = new URI(parentBaseURI);
+ _uri.absolutize(_parentBaseURI);
+ return _uri.toString();
+ } catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex) {
// This should never happen: parent should have checked the URI and returned null if invalid.
return null;
}
- return uri;
}
+ // REVISIT: what should happen in this case?
+ return null;
+ } catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException ex) {
return null;
}
- return uri;
}
}
}
// 2.the base URI of the element's parent element within the
// document or external entity, if one exists
- // 3. the base URI of the document entity or external entity
- // containing the element
-
- // ownerNode serves as a parent or as document
- String baseURI = (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null ;
- //base URI of parent element is not null
- if(baseURI != null){
- try {
- //return valid absolute base URI
- return new URI(baseURI).toString();
- }
- catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
- return null;
- }
- }
- return null;
+ // 3. the base URI of the document entity or external entity
+ // containing the element
+ // ownerNode serves as a parent or as document
+ return (this.ownerNode != null) ? this.ownerNode.getBaseURI() : null;
} //getBaseURI
-
+ /**
+ * NON-DOM Returns the xml:base attribute.
+ *
+ * @return the xml:base attribute
+ */
+ protected Attr getXMLBaseAttribute() {
+ return (Attr) attributes.getNamedItem("xml:base");
+ } // getXMLBaseAttribute():Attr
/**
- * NON-DOM
- * set the ownerDocument of this node, its children, and its attributes
+ * NON-DOM set the ownerDocument of this node, its children, and its
+ * attributes
*/
- void setOwnerDocument(CoreDocumentImpl doc) {
+ @Override
+ protected void setOwnerDocument(CoreDocumentImpl doc) {
super.setOwnerDocument(doc);
if (attributes != null) {
attributes.setOwnerDocument(doc);
@@ -239,15 +270,14 @@
//
// Element methods
//
-
/**
- * Look up a single Attribute by name. Returns the Attribute's
- * string value, or an empty string (NOT null!) to indicate that the
- * name did not map to a currently defined attribute.
+ * Look up a single Attribute by name. Returns the Attribute's string value,
+ * or an empty string (NOT null!) to indicate that the name did not map to a
+ * currently defined attribute.
* <p>
- * Note: Attributes may contain complex node trees. This method
- * returns the "flattened" string obtained from Attribute.getValue().
- * If you need the structure information, see getAttributeNode().
+ * Note: Attributes may contain complex node trees. This method returns the
+ * "flattened" string obtained from Attribute.getValue(). If you need the
+ * structure information, see getAttributeNode().
*/
public String getAttribute(String name) {
@@ -257,16 +287,15 @@
if (attributes == null) {
return "";
}
- Attr attr = (Attr)(attributes.getNamedItem(name));
+ Attr attr = (Attr) (attributes.getNamedItem(name));
return (attr == null) ? "" : attr.getValue();
} // getAttribute(String):String
-
/**
- * Look up a single Attribute by name. Returns the Attribute Node,
- * so its complete child tree is available. This could be important in
- * XML, where the string rendering may not be sufficient information.
+ * Look up a single Attribute by name. Returns the Attribute Node, so its
+ * complete child tree is available. This could be important in XML, where
+ * the string rendering may not be sufficient information.
* <p>
* If no matching attribute is available, returns null.
*/
@@ -278,36 +307,32 @@
if (attributes == null) {
return null;
}
- return (Attr)attributes.getNamedItem(name);
+ return (Attr) attributes.getNamedItem(name);
} // getAttributeNode(String):Attr
-
/**
- * Returns a NodeList of all descendent nodes (children,
- * grandchildren, and so on) which are Elements and which have the
- * specified tag name.
+ * Returns a NodeList of all descendent nodes (children, grandchildren, and
+ * so on) which are Elements and which have the specified tag name.
* <p>
- * Note: NodeList is a "live" view of the DOM. Its contents will
- * change as the DOM changes, and alterations made to the NodeList
- * will be reflected in the DOM.
+ * Note: NodeList is a "live" view of the DOM. Its contents will change as
+ * the DOM changes, and alterations made to the NodeList will be reflected
+ * in the DOM.
*
- * @param tagname The type of element to gather. To obtain a list of
- * all elements no matter what their names, use the wild-card tag
- * name "*".
+ * @param tagname The type of element to gather. To obtain a list of all
+ * elements no matter what their names, use the wild-card tag name "*".
*
* @see DeepNodeListImpl
*/
public NodeList getElementsByTagName(String tagname) {
- return new DeepNodeListImpl(this,tagname);
+ return new DeepNodeListImpl(this, tagname);
}
/**
- * Returns the name of the Element. Note that Element.nodeName() is
- * defined to also return the tag name.
+ * Returns the name of the Element. Note that Element.nodeName() is defined
+ * to also return the tag name.
* <p>
- * This is case-preserving in XML. HTML should uppercasify it on the
- * way in.
+ * This is case-preserving in XML. HTML should uppercasify it on the way in.
*/
public String getTagName() {
if (needsSyncData()) {
@@ -326,9 +351,9 @@
* <p>
* To normalize a Document, normalize its top-level Element child.
* <p>
- * As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of
- * Text -- is considered "markup" and will _not_ be merged either with
- * normal Text or with other CDATASections.
+ * As of PR-DOM-Level-1-19980818, CDATA -- despite being a subclass of Text
+ * -- is considered "markup" and will _not_ be merged either with normal
+ * Text or with other CDATASections.
*/
public void normalize() {
// No need to normalize if already normalized.
@@ -347,35 +372,27 @@
// 1) There is an adjacent text node
// 2) There is no adjacent text node, but kid is
// an empty text node.
- if ( kid.getNodeType() == Node.TEXT_NODE )
- {
+ if (kid.getNodeType() == Node.TEXT_NODE) {
// If an adjacent text node, merge it with kid
- if ( next!=null && next.getNodeType() == Node.TEXT_NODE )
- {
- ((Text)kid).appendData(next.getNodeValue());
- removeChild( next );
+ if (next != null && next.getNodeType() == Node.TEXT_NODE) {
+ ((Text) kid).appendData(next.getNodeValue());
+ removeChild(next);
next = kid; // Don't advance; there might be another.
- }
- else
- {
+ } else {
// If kid is empty, remove it
- if ( kid.getNodeValue() == null || kid.getNodeValue().length() == 0 ) {
- removeChild( kid );
+ if (kid.getNodeValue() == null || kid.getNodeValue().length() == 0) {
+ removeChild(kid);
}
}
- }
-
- // Otherwise it might be an Element, which is handled recursively
+ } // Otherwise it might be an Element, which is handled recursively
else if (kid.getNodeType() == Node.ELEMENT_NODE) {
kid.normalize();
}
}
// We must also normalize all of the attributes
- if ( attributes!=null )
- {
- for( int i=0; i<attributes.getLength(); ++i )
- {
+ if (attributes != null) {
+ for (int i = 0; i < attributes.getLength(); ++i) {
Node attr = attributes.item(i);
attr.normalize();
}
@@ -383,21 +400,20 @@
// changed() will have occurred when the removeChild() was done,
// so does not have to be reissued.
-
isNormalized(true);
} // normalize()
/**
- * Remove the named attribute from this Element. If the removed
- * Attribute has a default value, it is immediately replaced thereby.
+ * Remove the named attribute from this Element. If the removed Attribute
+ * has a default value, it is immediately replaced thereby.
* <P>
* The default logic is actually implemented in NamedNodeMapImpl.
- * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some
- * of this behavior is likely to change in future versions. ?????
+ * PR-DOM-Level-1-19980818 doesn't fully address the DTD, so some of this
+ * behavior is likely to change in future versions. ?????
* <P>
- * Note that this call "succeeds" even if no attribute by this name
- * existed -- unlike removeAttributeNode, which will throw a not-found
- * exception in that case.
+ * Note that this call "succeeds" even if no attribute by this name existed
+ * -- unlike removeAttributeNode, which will throw a not-found exception in
+ * that case.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
* readonly.
@@ -421,16 +437,14 @@
} // removeAttribute(String)
-
/**
- * Remove the specified attribute/value pair. If the removed
- * Attribute has a default value, it is immediately replaced.
+ * Remove the specified attribute/value pair. If the removed Attribute has a
+ * default value, it is immediately replaced.
* <p>
- * NOTE: Specifically removes THIS NODE -- not the node with this
- * name, nor the node with these contents. If the specific Attribute
- * object passed in is not stored in this Element, we throw a
- * DOMException. If you really want to remove an attribute by name,
- * use removeAttribute().
+ * NOTE: Specifically removes THIS NODE -- not the node with this name, nor
+ * the node with these contents. If the specific Attribute object passed in
+ * is not stored in this Element, we throw a DOMException. If you really
+ * want to remove an attribute by name, use removeAttribute().
*
* @return the Attribute object that was removed.
* @throws DOMException(NOT_FOUND_ERR) if oldattr is not an attribute of
@@ -439,7 +453,7 @@
* readonly.
*/
public Attr removeAttributeNode(Attr oldAttr)
- throws DOMException {
+ throws DOMException {
if (ownerDocument.errorChecking && isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
@@ -458,19 +472,18 @@
} // removeAttributeNode(Attr):Attr
-
/**
- * Add a new name/value pair, or replace the value of the existing
- * attribute having that name.
+ * Add a new name/value pair, or replace the value of the existing attribute
+ * having that name.
*
- * Note: this method supports only the simplest kind of Attribute,
- * one whose value is a string contained in a single Text node.
- * If you want to assert a more complex value (which XML permits,
- * though HTML doesn't), see setAttributeNode().
+ * Note: this method supports only the simplest kind of Attribute, one whose
+ * value is a string contained in a single Text node. If you want to assert
+ * a more complex value (which XML permits, though HTML doesn't), see
+ * setAttributeNode().
*
- * The attribute is created with specified=true, meaning it's an
- * explicit value rather than inherited from the DTD as a default.
- * Again, setAttributeNode can be used to achieve other results.
+ * The attribute is created with specified=true, meaning it's an explicit
+ * value rather than inherited from the DTD as a default. Again,
+ * setAttributeNode can be used to achieve other results.
*
* @throws DOMException(INVALID_NAME_ERR) if the name is not acceptable.
* (Attribute factory will do that test for us.)
@@ -478,54 +491,52 @@
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if the node is
* readonly.
*/
- public void setAttribute(String name, String value) {
+ public void setAttribute(String name, String value) {
- if (ownerDocument.errorChecking && isReadOnly()) {
- String msg =
- DOMMessageFormatter.formatMessage(
- DOMMessageFormatter.DOM_DOMAIN,
- "NO_MODIFICATION_ALLOWED_ERR",
- null);
- throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
- }
+ if (ownerDocument.errorChecking && isReadOnly()) {
+ String msg
+ = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NO_MODIFICATION_ALLOWED_ERR",
+ null);
+ throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
+ }
- if (needsSyncData()) {
- synchronizeData();
- }
+ if (needsSyncData()) {
+ synchronizeData();
+ }
- Attr newAttr = getAttributeNode(name);
- if (newAttr == null) {
- newAttr = getOwnerDocument().createAttribute(name);
+ Attr newAttr = getAttributeNode(name);
+ if (newAttr == null) {
+ newAttr = getOwnerDocument().createAttribute(name);
- if (attributes == null) {
- attributes = new AttributeMap(this, null);
- }
+ if (attributes == null) {
+ attributes = new AttributeMap(this, null);
+ }
- newAttr.setNodeValue(value);
- attributes.setNamedItem(newAttr);
- }
- else {
- newAttr.setNodeValue(value);
- }
+ newAttr.setNodeValue(value);
+ attributes.setNamedItem(newAttr);
+ } else {
+ newAttr.setNodeValue(value);
+ }
- } // setAttribute(String,String)
+ } // setAttribute(String,String)
/**
- * Add a new attribute/value pair, or replace the value of the
- * existing attribute with that name.
+ * Add a new attribute/value pair, or replace the value of the existing
+ * attribute with that name.
* <P>
* This method allows you to add an Attribute that has already been
* constructed, and hence avoids the limitations of the simple
- * setAttribute() call. It can handle attribute values that have
- * arbitrarily complex tree structure -- in particular, those which
- * had entity references mixed into their text.
+ * setAttribute() call. It can handle attribute values that have arbitrarily
+ * complex tree structure -- in particular, those which had entity
+ * references mixed into their text.
*
- * @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object
- * has already been assigned to another Element.
+ * @throws DOMException(INUSE_ATTRIBUTE_ERR) if the Attribute object has
+ * already been assigned to another Element.
*/
public Attr setAttributeNode(Attr newAttr)
- throws DOMException
- {
+ throws DOMException {
if (needsSyncData()) {
synchronizeData();
@@ -535,13 +546,13 @@
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
}
if (newAttr.getOwnerDocument() != ownerDocument) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
- throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
+ throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
}
}
@@ -556,19 +567,16 @@
//
// DOM2: Namespace methods
//
-
/**
- * Introduced in DOM Level 2. <p>
+ * Introduced in DOM Level 2.
+ * <p>
*
* Retrieves an attribute value by local name and namespace URI.
*
- * @param namespaceURI
- * The namespace URI of the attribute to
- * retrieve.
- * @param localName The local name of the attribute to retrieve.
- * @return String The Attr value as a string, or empty string
- * if that attribute
- * does not have a specified or default value.
+ * @param namespaceURI The namespace URI of the attribute to retrieve.
+ * @param localName The local name of the attribute to retrieve.
+ * @return String The Attr value as a string, or empty string if that
+ * attribute does not have a specified or default value.
* @since WD-DOM-Level-2-19990923
*/
public String getAttributeNS(String namespaceURI, String localName) {
@@ -581,89 +589,85 @@
return "";
}
- Attr attr = (Attr)(attributes.getNamedItemNS(namespaceURI, localName));
+ Attr attr = (Attr) (attributes.getNamedItemNS(namespaceURI, localName));
return (attr == null) ? "" : attr.getValue();
} // getAttributeNS(String,String):String
/**
- * Introduced in DOM Level 2. <p>
- *
- * Adds a new attribute.
- * If the given namespaceURI is null or an empty string and the
- * qualifiedName has a prefix that is "xml", the new attribute is bound to
- * the predefined namespace "http://www.w3.org/XML/1998/namespace"
- * [Namespaces]. If an attribute with the same local name and namespace
- * URI is already present on the element, its prefix is changed to be the
- * prefix part of the qualifiedName, and its value is changed to be the
- * value parameter. This value is a simple string, it is not parsed as it
- * is being set. So any markup (such as syntax to be recognized as an
- * entity reference) is treated as literal text, and needs to be
- * appropriately escaped by the implementation when it is written out. In
- * order to assign an attribute value that contains entity references, the
- * user must create an Attr node plus any Text and EntityReference nodes,
- * build the appropriate subtree, and use setAttributeNodeNS or
- * setAttributeNode to assign it as the value of an attribute.
+ * Introduced in DOM Level 2.
+ * <p>
*
- * @param namespaceURI The namespace URI of the attribute to create
- * or alter.
- * @param qualifiedName The qualified name of the attribute to create or
- * alter.
- * @param value The value to set in string form.
- * @throws INVALID_CHARACTER_ERR: Raised if the specified
- * name contains an invalid character.
+ * Adds a new attribute. If the given namespaceURI is null or an empty
+ * string and the qualifiedName has a prefix that is "xml", the new
+ * attribute is bound to the predefined namespace
+ * "http://www.w3.org/XML/1998/namespace" [Namespaces]. If an attribute with
+ * the same local name and namespace URI is already present on the element,
+ * its prefix is changed to be the prefix part of the qualifiedName, and its
+ * value is changed to be the value parameter. This value is a simple
+ * string, it is not parsed as it is being set. So any markup (such as
+ * syntax to be recognized as an entity reference) is treated as literal
+ * text, and needs to be appropriately escaped by the implementation when it
+ * is written out. In order to assign an attribute value that contains
+ * entity references, the user must create an Attr node plus any Text and
+ * EntityReference nodes, build the appropriate subtree, and use
+ * setAttributeNodeNS or setAttributeNode to assign it as the value of an
+ * attribute.
*
- * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
- * node is readonly.
+ * @param namespaceURI The namespace URI of the attribute to create or
+ * alter.
+ * @param qualifiedName The qualified name of the attribute to create or
+ * alter.
+ * @param value The value to set in string form.
+ * @throws INVALID_CHARACTER_ERR: Raised if the specified name contains an
+ * invalid character.
*
- * @throws NAMESPACE_ERR: Raised if the qualifiedName
- * has a prefix that is "xml" and the namespaceURI
- * is neither null nor an empty string nor
- * "http://www.w3.org/XML/1998/namespace", or if
- * the qualifiedName has a prefix that is "xmlns"
- * but the namespaceURI is neither null nor an
- * empty string, or if if the qualifiedName has a
- * prefix different from "xml" and "xmlns" and the
- * namespaceURI is null or an empty string.
+ * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ *
+ * @throws NAMESPACE_ERR: Raised if the qualifiedName has a prefix that is
+ * "xml" and the namespaceURI is neither null nor an empty string nor
+ * "http://www.w3.org/XML/1998/namespace", or if the qualifiedName has a
+ * prefix that is "xmlns" but the namespaceURI is neither null nor an empty
+ * string, or if if the qualifiedName has a prefix different from "xml" and
+ * "xmlns" and the namespaceURI is null or an empty string.
* @since WD-DOM-Level-2-19990923
*/
- public void setAttributeNS(String namespaceURI,String qualifiedName,
- String value) {
- if (ownerDocument.errorChecking && isReadOnly()) {
- String msg =
- DOMMessageFormatter.formatMessage(
- DOMMessageFormatter.DOM_DOMAIN,
- "NO_MODIFICATION_ALLOWED_ERR",
- null);
- throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
- }
- if (needsSyncData()) {
- synchronizeData();
- }
- int index = qualifiedName.indexOf(':');
- String prefix, localName;
- if (index < 0) {
- prefix = null;
- localName = qualifiedName;
- }
- else {
- prefix = qualifiedName.substring(0, index);
- localName = qualifiedName.substring(index + 1);
- }
- Attr newAttr = getAttributeNodeNS(namespaceURI, localName);
- if (newAttr == null) {
+ public void setAttributeNS(String namespaceURI, String qualifiedName,
+ String value) {
+ if (ownerDocument.errorChecking && isReadOnly()) {
+ String msg
+ = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NO_MODIFICATION_ALLOWED_ERR",
+ null);
+ throw new DOMException(
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
+ }
+ if (needsSyncData()) {
+ synchronizeData();
+ }
+ int index = qualifiedName.indexOf(':');
+ String prefix, localName;
+ if (index < 0) {
+ prefix = null;
+ localName = qualifiedName;
+ } else {
+ prefix = qualifiedName.substring(0, index);
+ localName = qualifiedName.substring(index + 1);
+ }
+ Attr newAttr = getAttributeNodeNS(namespaceURI, localName);
+ if (newAttr == null) {
// REVISIT: this is not efficient, we are creating twice the same
// strings for prefix and localName.
- newAttr = getOwnerDocument().createAttributeNS(
- namespaceURI,
- qualifiedName);
- if (attributes == null) {
- attributes = new AttributeMap(this, null);
- }
- newAttr.setNodeValue(value);
- attributes.setNamedItemNS(newAttr);
+ newAttr = getOwnerDocument().createAttributeNS(
+ namespaceURI,
+ qualifiedName);
+ if (attributes == null) {
+ attributes = new AttributeMap(this, null);
+ }
+ newAttr.setNodeValue(value);
+ attributes.setNamedItemNS(newAttr);
}
else {
if (newAttr instanceof AttrNSImpl){
@@ -694,25 +698,24 @@
attributes.setNamedItemNS(newAttr);
}
- newAttr.setNodeValue(value);
- }
+ newAttr.setNodeValue(value);
+ }
} // setAttributeNS(String,String,String)
-
/**
- * Introduced in DOM Level 2. <p>
+ * Introduced in DOM Level 2.
+ * <p>
*
* Removes an attribute by local name and namespace URI. If the removed
- * attribute has a default value it is immediately replaced.
- * The replacing attribute has the same namespace URI and local name,
- * as well as the original prefix.<p>
+ * attribute has a default value it is immediately replaced. The replacing
+ * attribute has the same namespace URI and local name, as well as the
+ * original prefix.<p>
*
- * @param namespaceURI The namespace URI of the attribute to remove.
+ * @param namespaceURI The namespace URI of the attribute to remove.
*
- * @param localName The local name of the attribute to remove.
- * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this
- * node is readonly.
+ * @param localName The local name of the attribute to remove.
+ * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
* @since WD-DOM-Level-2-19990923
*/
public void removeAttributeNS(String namespaceURI, String localName) {
@@ -737,15 +740,13 @@
/**
* Retrieves an Attr node by local name and namespace URI.
*
- * @param namespaceURI The namespace URI of the attribute to
- * retrieve.
- * @param localName The local name of the attribute to retrieve.
- * @return Attr The Attr node with the specified attribute
- * local name and namespace
- * URI or null if there is no such attribute.
+ * @param namespaceURI The namespace URI of the attribute to retrieve.
+ * @param localName The local name of the attribute to retrieve.
+ * @return Attr The Attr node with the specified attribute local name and
+ * namespace URI or null if there is no such attribute.
* @since WD-DOM-Level-2-19990923
*/
- public Attr getAttributeNodeNS(String namespaceURI, String localName){
+ public Attr getAttributeNodeNS(String namespaceURI, String localName) {
if (needsSyncData()) {
synchronizeData();
@@ -753,40 +754,34 @@
if (attributes == null) {
return null;
}
- return (Attr)attributes.getNamedItemNS(namespaceURI, localName);
+ return (Attr) attributes.getNamedItemNS(namespaceURI, localName);
} // getAttributeNodeNS(String,String):Attr
/**
- * Introduced in DOM Level 2. <p>
+ * Introduced in DOM Level 2.
+ * <p>
*
- * Adds a new attribute. If an attribute with that local name and
- * namespace URI is already present in the element, it is replaced
- * by the new one.
+ * Adds a new attribute. If an attribute with that local name and namespace
+ * URI is already present in the element, it is replaced by the new one.
*
- * @param Attr The Attr node to add to the attribute list. When
- * the Node has no namespaceURI, this method behaves
- * like setAttributeNode.
- * @return Attr If the newAttr attribute replaces an existing attribute
- * with the same local name and namespace URI, the *
- * previously existing Attr node is returned, otherwise
- * null is returned.
- * @throws WRONG_DOCUMENT_ERR: Raised if newAttr
- * was created from a different document than the one that
- * created the element.
+ * @param newAttr The Attr node to add to the attribute list. When the Node
+ * has no namespaceURI, this method behaves like setAttributeNode.
+ * @return Attr If the newAttr attribute replaces an existing attribute with
+ * the same local name and namespace URI, the * previously existing Attr
+ * node is returned, otherwise null is returned.
+ * @throws WRONG_DOCUMENT_ERR: Raised if newAttr was created from a
+ * different document than the one that created the element.
*
- * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if
- * this node is readonly.
+ * @throws NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
*
- * @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is
- * already an attribute of another Element object. The
- * DOM user must explicitly clone Attr nodes to re-use
- * them in other elements.
+ * @throws INUSE_ATTRIBUTE_ERR: Raised if newAttr is already an attribute of
+ * another Element object. The DOM user must explicitly clone Attr nodes to
+ * re-use them in other elements.
* @since WD-DOM-Level-2-19990923
*/
public Attr setAttributeNodeNS(Attr newAttr)
- throws DOMException
- {
+ throws DOMException {
if (needsSyncData()) {
synchronizeData();
@@ -794,9 +789,9 @@
if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
- throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
+ throw new DOMException(
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
}
if (newAttr.getOwnerDocument() != ownerDocument) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
@@ -813,9 +808,9 @@
} // setAttributeNodeNS(Attr):Attr
/**
- * NON-DOM: sets attribute node for this element
- */
- protected int setXercesAttributeNode (Attr attr){
+ * NON-DOM: sets attribute node for this element
+ */
+ protected int setXercesAttributeNode(Attr attr) {
if (needsSyncData()) {
synchronizeData();
@@ -829,9 +824,9 @@
}
/**
- * NON-DOM: get inded of an attribute
- */
- protected int getXercesAttribute(String namespaceURI, String localName){
+ * NON-DOM: get inded of an attribute
+ */
+ protected int getXercesAttribute(String namespaceURI, String localName) {
if (needsSyncData()) {
synchronizeData();
@@ -868,32 +863,30 @@
}
/**
- * Introduced in DOM Level 2. <p>
+ * Introduced in DOM Level 2.
+ * <p>
*
* Returns a NodeList of all the Elements with a given local name and
* namespace URI in the order in which they would be encountered in a
* preorder traversal of the Document tree, starting from this node.
*
- * @param namespaceURI The namespace URI of the elements to match
- * on. The special value "*" matches all
- * namespaces. When it is null or an empty
- * string, this method behaves like
- * getElementsByTagName.
- * @param localName The local name of the elements to match on.
- * The special value "*" matches all local names.
- * @return NodeList A new NodeList object containing all the matched
- * Elements.
+ * @param namespaceURI The namespace URI of the elements to match on. The
+ * special value "*" matches all namespaces. When it is null or an empty
+ * string, this method behaves like getElementsByTagName.
+ * @param localName The local name of the elements to match on. The special
+ * value "*" matches all local names.
+ * @return NodeList A new NodeList object containing all the matched
+ * Elements.
* @since WD-DOM-Level-2-19990923
*/
public NodeList getElementsByTagNameNS(String namespaceURI,
- String localName) {
+ String localName) {
return new DeepNodeListImpl(this, namespaceURI, localName);
}
/**
- * DOM Level 3 WD- Experimental.
- * Override inherited behavior from NodeImpl and ParentNode to check on
- * attributes
+ * DOM Level 3 WD- Experimental. Override inherited behavior from NodeImpl
+ * and ParentNode to check on attributes
*/
public boolean isEqualNode(Node arg) {
if (!super.isEqualNode(arg)) {
@@ -917,10 +910,9 @@
if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
return false;
}
- }
- else {
+ } else {
Node n2 = map2.getNamedItemNS(n1.getNamespaceURI(),
- n1.getLocalName());
+ n1.getLocalName());
if (n2 == null || !((NodeImpl) n1).isEqualNode(n2)) {
return false;
}
@@ -941,8 +933,8 @@
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
}
if (at.getOwnerElement() != this) {
@@ -953,8 +945,7 @@
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
- }
- else {
+ } else {
ownerDocument.putIdentifier(at.getValue(), this);
}
}
@@ -968,19 +959,19 @@
}
Attr at = getAttributeNode(name);
- if( at == null){
- String msg = DOMMessageFormatter.formatMessage(
- DOMMessageFormatter.DOM_DOMAIN,
- "NOT_FOUND_ERR", null);
+ if (at == null) {
+ String msg = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- }
+ }
- if (ownerDocument.errorChecking) {
+ if (ownerDocument.errorChecking) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
}
if (at.getOwnerElement() != this) {
@@ -992,8 +983,7 @@
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
- }
- else {
+ } else {
ownerDocument.putIdentifier(at.getValue(), this);
}
}
@@ -1002,51 +992,52 @@
* DOM Level 3: register the given attribute node as an ID attribute
*/
public void setIdAttributeNS(String namespaceURI, String localName,
- boolean makeId) {
+ boolean makeId) {
if (needsSyncData()) {
synchronizeData();
}
//if namespace uri is empty string, set it to 'null'
if (namespaceURI != null) {
- namespaceURI = (namespaceURI.length() == 0)? null : namespaceURI;
+ namespaceURI = (namespaceURI.length() == 0) ? null : namespaceURI;
}
Attr at = getAttributeNodeNS(namespaceURI, localName);
- if( at == null){
- String msg = DOMMessageFormatter.formatMessage(
- DOMMessageFormatter.DOM_DOMAIN,
- "NOT_FOUND_ERR", null);
+ if (at == null) {
+ String msg = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
- }
+ }
- if (ownerDocument.errorChecking) {
+ if (ownerDocument.errorChecking) {
if (isReadOnly()) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
+ String msg = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
- msg);
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ msg);
}
if (at.getOwnerElement() != this) {
- String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
+ String msg = DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null);
throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
}
}
((AttrImpl) at).isIdAttribute(makeId);
if (!makeId) {
ownerDocument.removeIdentifier(at.getValue());
- }
- else {
+ } else {
ownerDocument.putIdentifier(at.getValue(), this);
}
- }
+ }
/**
* @see org.w3c.dom.TypeInfo#getTypeName()
*/
- public String getTypeName() {
+ public String getTypeName() {
return null;
- }
+ }
/**
* @see org.w3c.dom.TypeInfo#getTypeNamespace()
@@ -1056,33 +1047,32 @@
}
/**
- * Introduced in DOM Level 3. <p>
+ * Introduced in DOM Level 3.
+ * <p>
* Checks if a type is derived from another by restriction. See:
* http://www.w3.org/TR/DOM-Level-3-Core/core.html#TypeInfo-isDerivedFrom
*
- * @param ancestorNS
- * The namspace of the ancestor type declaration
- * @param ancestorName
- * The name of the ancestor type declaration
- * @param type
- * The reference type definition
+ * @param typeNamespaceArg The namspace of the ancestor type declaration
+ * @param typeNameArg The name of the ancestor type declaration
+ * @param derivationMethod The derivation method
*
- * @return boolean True if the type is derived by restriciton for the
- * reference type
+ * @return boolean True if the type is derived by restriction for the
+ * reference type
*/
public boolean isDerivedFrom(String typeNamespaceArg,
- String typeNameArg,
- int derivationMethod) {
+ String typeNameArg,
+ int derivationMethod) {
return false;
}
- /**
- * Method getSchemaTypeInfo.
- * @return TypeInfo
- */
- public TypeInfo getSchemaTypeInfo(){
- if(needsSyncData()) {
+ /**
+ * Method getSchemaTypeInfo.
+ *
+ * @return TypeInfo
+ */
+ public TypeInfo getSchemaTypeInfo() {
+ if (needsSyncData()) {
synchronizeData();
}
return this;
@@ -1091,25 +1081,24 @@
//
// Public methods
//
-
/**
* NON-DOM: Subclassed to flip the attributes' readonly switch as well.
+ *
* @see NodeImpl#setReadOnly
*/
public void setReadOnly(boolean readOnly, boolean deep) {
- super.setReadOnly(readOnly,deep);
+ super.setReadOnly(readOnly, deep);
if (attributes != null) {
- attributes.setReadOnly(readOnly,true);
+ attributes.setReadOnly(readOnly, true);
}
}
-
-
//
// Protected methods
//
-
- /** Synchronizes the data (name and value) for fast nodes. */
+ /**
+ * Synchronizes the data (name and value) for fast nodes.
+ */
protected void synchronizeData() {
// no need to sync in the future
@@ -1141,7 +1130,9 @@
}
}
- /** Setup the default attributes. */
+ /**
+ * Setup the default attributes.
+ */
protected void setupDefaultAttributes() {
NamedNodeMapImpl defaults = getDefaultAttributes();
if (defaults != null) {
@@ -1149,7 +1140,9 @@
}
}
- /** Reconcile default attributes. */
+ /**
+ * Reconcile default attributes.
+ */
protected void reconcileDefaultAttributes() {
if (attributes != null) {
NamedNodeMapImpl defaults = getDefaultAttributes();
@@ -1157,17 +1150,19 @@
}
}
- /** Get the default attributes. */
+ /**
+ * Get the default attributes.
+ */
protected NamedNodeMapImpl getDefaultAttributes() {
- DocumentTypeImpl doctype =
- (DocumentTypeImpl) ownerDocument.getDoctype();
+ DocumentTypeImpl doctype
+ = (DocumentTypeImpl) ownerDocument.getDoctype();
if (doctype == null) {
return null;
}
- ElementDefinitionImpl eldef =
- (ElementDefinitionImpl)doctype.getElements()
- .getNamedItem(getNodeName());
+ ElementDefinitionImpl eldef
+ = (ElementDefinitionImpl) doctype.getElements()
+ .getNamedItem(getNodeName());
if (eldef == null) {
return null;
}
@@ -1175,4 +1170,208 @@
} // getDefaultAttributes()
+ //
+ // ElementTraversal methods
+ //
+ /**
+ * @see <a
+ * href="http://www.w3.org/TR/2008/REC-ElementTraversal-20081222/#attribute-childElementCount">
+ * Element Traversal Specification</a>
+ */
+ @Override
+ public final int getChildElementCount() {
+ int count = 0;
+ Element child = getFirstElementChild();
+ while (child != null) {
+ ++count;
+ child = ((ElementImpl) child).getNextElementSibling();
+ }
+ return count;
+ } // getChildElementCount():int
+
+ /**
+ * @see <a
+ * href="http://www.w3.org/TR/2008/REC-ElementTraversal-20081222/#attribute-firstElementChild">
+ * Element Traversal Specification</a>
+ */
+ @Override
+ public final Element getFirstElementChild() {
+ Node n = getFirstChild();
+ while (n != null) {
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return (Element) n;
+ case Node.ENTITY_REFERENCE_NODE:
+ final Element e = getFirstElementChild(n);
+ if (e != null) {
+ return e;
+ }
+ break;
+ }
+ n = n.getNextSibling();
+ }
+ return null;
+ } // getFirstElementChild():Element
+
+ /**
+ * @see <a
+ * href="http://www.w3.org/TR/2008/REC-ElementTraversal-20081222/#attribute-lastElementChild">
+ * Element Traversal Specification</a>
+ */
+ @Override
+ public final Element getLastElementChild() {
+ Node n = getLastChild();
+ while (n != null) {
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return (Element) n;
+ case Node.ENTITY_REFERENCE_NODE:
+ final Element e = getLastElementChild(n);
+ if (e != null) {
+ return e;
+ }
+ break;
+ }
+ n = n.getPreviousSibling();
+ }
+ return null;
+ } // getLastElementChild():Element
+
+ /**
+ * @see <a
+ * href="http://www.w3.org/TR/2008/REC-ElementTraversal-20081222/#attribute-nextElementSibling">
+ * Element Traversal Specification</a>
+ */
+ @Override
+ public final Element getNextElementSibling() {
+ Node n = getNextLogicalSibling(this);
+ while (n != null) {
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return (Element) n;
+ case Node.ENTITY_REFERENCE_NODE:
+ final Element e = getFirstElementChild(n);
+ if (e != null) {
+ return e;
+ }
+ break;
+ }
+ n = getNextLogicalSibling(n);
+ }
+ return null;
+ } // getNextElementSibling():Element
+
+ /**
+ * @see <a
+ * href="http://www.w3.org/TR/2008/REC-ElementTraversal-20081222/#attribute-previousElementSibling">
+ * Element Traversal Specification</a>
+ */
+ @Override
+ public final Element getPreviousElementSibling() {
+ Node n = getPreviousLogicalSibling(this);
+ while (n != null) {
+ switch (n.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ return (Element) n;
+ case Node.ENTITY_REFERENCE_NODE:
+ final Element e = getLastElementChild(n);
+ if (e != null) {
+ return e;
+ }
+ break;
+ }
+ n = getPreviousLogicalSibling(n);
+ }
+ return null;
+ } // getPreviousElementSibling():Element
+
+ // Returns the first element node found from a
+ // non-recursive in order traversal of the given node.
+ private Element getFirstElementChild(Node n) {
+ final Node top = n;
+ while (n != null) {
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ return (Element) n;
+ }
+ Node next = n.getFirstChild();
+ while (next == null) {
+ if (top == n) {
+ break;
+ }
+ next = n.getNextSibling();
+ if (next == null) {
+ n = n.getParentNode();
+ if (n == null || top == n) {
+ return null;
+ }
+ }
+ }
+ n = next;
+ }
+ return null;
+ } // getFirstElementChild(Node):Element
+
+ // Returns the first element node found from a
+ // non-recursive reverse order traversal of the given node.
+ private Element getLastElementChild(Node n) {
+ final Node top = n;
+ while (n != null) {
+ if (n.getNodeType() == Node.ELEMENT_NODE) {
+ return (Element) n;
+ }
+ Node next = n.getLastChild();
+ while (next == null) {
+ if (top == n) {
+ break;
+ }
+ next = n.getPreviousSibling();
+ if (next == null) {
+ n = n.getParentNode();
+ if (n == null || top == n) {
+ return null;
+ }
+ }
+ }
+ n = next;
+ }
+ return null;
+ } // getLastElementChild(Node):Element
+
+ // Returns the next logical sibling with respect to the given node.
+ private Node getNextLogicalSibling(Node n) {
+ Node next = n.getNextSibling();
+ // If "n" has no following sibling and its parent is an entity reference node we
+ // need to continue the search through the following siblings of the entity
+ // reference as these are logically siblings of the given node.
+ if (next == null) {
+ Node parent = n.getParentNode();
+ while (parent != null && parent.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ next = parent.getNextSibling();
+ if (next != null) {
+ break;
+ }
+ parent = parent.getParentNode();
+ }
+ }
+ return next;
+ } // getNextLogicalSibling(Node):Node
+
+ // Returns the previous logical sibling with respect to the given node.
+ private Node getPreviousLogicalSibling(Node n) {
+ Node prev = n.getPreviousSibling();
+ // If "n" has no previous sibling and its parent is an entity reference node we
+ // need to continue the search through the previous siblings of the entity
+ // reference as these are logically siblings of the given node.
+ if (prev == null) {
+ Node parent = n.getParentNode();
+ while (parent != null && parent.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
+ prev = parent.getPreviousSibling();
+ if (prev != null) {
+ break;
+ }
+ parent = parent.getParentNode();
+ }
+ }
+ return prev;
+ } // getPreviousLogicalSibling(Node):Node
} // class ElementImpl