You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by nd...@apache.org on 2004/06/24 19:57:00 UTC
cvs commit: xml-xerces/java/src/org/apache/xerces/dom TextImpl.java
nddelima 2004/06/24 10:57:00
Modified: java/src/org/apache/xerces/dom TextImpl.java
Log:
Patch to fix problems with replaceWholeText.
Revision Changes Path
1.24 +252 -64 xml-xerces/java/src/org/apache/xerces/dom/TextImpl.java
Index: TextImpl.java
===================================================================
RCS file: /home/cvs/xml-xerces/java/src/org/apache/xerces/dom/TextImpl.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- TextImpl.java 24 Feb 2004 23:23:17 -0000 1.23
+++ TextImpl.java 24 Jun 2004 17:57:00 -0000 1.24
@@ -41,6 +41,12 @@
extends CharacterDataImpl
implements CharacterData, Text {
+ //
+ // Private Data members
+ //
+ //Used by replaceWholeText
+ private boolean fTextOnlyChildren = false;
+
//
// Constants
//
@@ -183,77 +189,258 @@
}
/**
- * DOM Level 3 WD - Experimental.
- */
- public Text replaceWholeText(String content)
- throws DOMException{
+ * Replaces the text of the current node and all logically-adjacent text
+ * nodes with the specified text. All logically-adjacent text nodes are
+ * removed including the current node unless it was the recipient of the
+ * replacement text.
+ *
+ * @param content
+ * The content of the replacing Text node.
+ * @return text - The Text node created with the specified content.
+ * @since DOM Level 3
+ */
+ public Text replaceWholeText(String content) throws DOMException {
if (needsSyncData()) {
synchronizeData();
}
-
- // make sure we can make the replacement
- if (!canModify(nextSibling)) {
- throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
- DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null));
- }
-
+ //if the content is null
Node parent = this.getParentNode();
if (content == null || content.length() == 0) {
// remove current node
- if (parent !=null) { // check if node in the tree
+ if (parent != null) { // check if node in the tree
parent.removeChild(this);
- return null;
}
+ return null;
}
+
+ //replace the text node
Text currentNode = null;
- if (isReadOnly()){
+ if (isReadOnly()) {
Text newNode = this.ownerDocument().createTextNode(content);
- if (parent !=null) { // check if node in the tree
+ if (parent != null) { // check if node in the tree
parent.insertBefore(newNode, this);
parent.removeChild(this);
currentNode = newNode;
} else {
return newNode;
}
- } else {
+ } else {
this.setData(content);
currentNode = this;
}
- Node sibling = currentNode.getNextSibling();
- while ( sibling !=null) {
- parent.removeChild(sibling);
- sibling = currentNode.getNextSibling();
- }
+ //check logically-adjacent text nodes
+ Node prev = this.getPreviousSibling();
+ while (prev != null) {
+ fTextOnlyChildren = false;
+
+ // make sure we can make the replacement
+ if (!canModifyPrev(prev)) {
+ throw new DOMException(
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NO_MODIFICATION_ALLOWED_ERR", null));
+ } else {
+ //If the logically-adjacent previous node can be replaced
+ //remove it. A logically adjacent node can be replaced if
+ //it is a Text or CDATASection node or an EntityReference with
+ //Text and CDATA only children
+ if ((prev.getNodeType() == Node.TEXT_NODE) || (prev
+ .getNodeType() == Node.CDATA_SECTION_NODE)||
+ (prev.getNodeType() == Node.ENTITY_REFERENCE_NODE && fTextOnlyChildren)) {
+ parent.removeChild(prev);
+ prev = this;
+ }
+ }
+ prev = prev.getPreviousSibling();
+ }
+
+ //check logically-adjacent text nodes
+ Node next = this.getNextSibling();
+ while (next != null) {
+ fTextOnlyChildren = false;
+
+ // make sure we can make the replacement
+ if (!canModifyNext(next)) {
+ throw new DOMException(
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ DOMMessageFormatter.formatMessage(
+ DOMMessageFormatter.DOM_DOMAIN,
+ "NO_MODIFICATION_ALLOWED_ERR", null));
+ } else {
+ //If the logically-adjacent next node can be replaced
+ //remove it. A logically adjacent node can be replaced if
+ //it is a Text or CDATASection node or an EntityReference with
+ //Text and CDATA only children
+ if ((next.getNodeType() == Node.TEXT_NODE) || (next
+ .getNodeType() == Node.CDATA_SECTION_NODE) ||
+ (next.getNodeType() == Node.ENTITY_REFERENCE_NODE && fTextOnlyChildren)) {
+ parent.removeChild(next);
+ next = this;
+ }
+ }
+ next = next.getNextSibling();
+ }
+
return currentNode;
}
/**
- * If any EntityReference to be removed has descendants
- * that are not EntityReference, Text, or CDATASection
- * nodes, the replaceWholeText method must fail before
- * performing any modification of the document, raising a
- * DOMException with the code NO_MODIFICATION_ALLOWED_ERR.
+ * If any EntityReference to be removed has descendants that are not
+ * EntityReference, Text, or CDATASection nodes, the replaceWholeText method
+ * must fail before performing any modification of the document, raising a
+ * DOMException with the code NO_MODIFICATION_ALLOWED_ERR. Traverse previous
+ * siblings of the node to be replaced. If a previous sibling is an
+ * EntityReference node, get it's last child. If the last child was a Text
+ * or CDATASection node and its previous siblings are neither a replaceable
+ * EntityReference or Text or CDATASection nodes, return false. IF the last
+ * child was neither Text nor CDATASection nor a replaceable EntityReference
+ * Node, then return true. If the last child was a Text or CDATASection node
+ * any its previous sibling was not or was an EntityReference that did not
+ * contain only Text or CDATASection nodes, return false. Check this recursively
+ * for EntityReference nodes.
*
* @param node
- * @return true - can replace text
- * false - can't replace exception must be raised
+ * @return true - can replace text false - can't replace exception must be
+ * raised
*/
- private boolean canModify(Node node){
- while (node != null) {
- short type = node.getNodeType();
- if (type == Node.ENTITY_REFERENCE_NODE) {
- if (!canModify(node.getFirstChild())){
- return false;
+ private boolean canModifyPrev(Node node) {
+ boolean textLastChild = false;
+
+ short type = node.getNodeType();
+
+ if (type == Node.ENTITY_REFERENCE_NODE) {
+ //If the previous sibling was entityreference
+ //check if its content is replaceable
+ Node lastChild = node.getLastChild();
+
+ //if the entity reference has no children
+ //return false
+ if (lastChild == null) {
+ fTextOnlyChildren = false;
+ return false;
+ }
+
+ //The replacement text of the entity reference should
+ //be either only text,cadatsections or replaceable entity
+ //reference nodes or the last child should be neither of these
+ while (lastChild != null) {
+ short lType = lastChild.getNodeType();
+
+ if (lType == Node.TEXT_NODE || lType == Node.CDATA_SECTION_NODE) {
+ textLastChild = true;
+ fTextOnlyChildren = true;
+ } else if (lType == Node.ENTITY_REFERENCE_NODE) {
+ if (!canModifyPrev(lastChild)) {
+ fTextOnlyChildren = false;
+ return false;
+ } else {
+ //If the EntityReference child contains
+ //only text, or non-text or ends with a
+ //non-text node.
+ textLastChild = true;
+ }
+
+ } else {
+ if (textLastChild) {
+ fTextOnlyChildren = false;
+ return false;
+ } else {
+ return true;
+ }
}
+ lastChild = lastChild.getPreviousSibling();
}
- else if (type != Node.TEXT_NODE &&
- type != Node.CDATA_SECTION_NODE) {
+ } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
+ //If the previous sibling was text or cdatasection move to next
+ fTextOnlyChildren = true;
+ } else {
+ //If the previous sibling was anything but text or
+ //cdatasection or an entity reference, stop search and
+ //return true
+ return true;
+ }
+ return true;
+ }
+
+ /**
+ * If any EntityReference to be removed has descendants that are not
+ * EntityReference, Text, or CDATASection nodes, the replaceWholeText method
+ * must fail before performing any modification of the document, raising a
+ * DOMException with the code NO_MODIFICATION_ALLOWED_ERR. Traverse previous
+ * siblings of the node to be replaced. If a previous sibling is an
+ * EntityReference node, get it's last child. If the first child was a Text
+ * or CDATASection node and its next siblings are neither a replaceable
+ * EntityReference or Text or CDATASection nodes, return false. IF the first
+ * child was neither Text nor CDATASection nor a replaceable EntityReference
+ * Node, then return true. If the first child was a Text or CDATASection node
+ * any its next sibling was not or was an EntityReference that did not
+ * contain only Text or CDATASection nodes, return false. Check this recursively
+ * for EntityReference nodes.
+ *
+ * @param node
+ * @return true - can replace text false - can't replace exception must be
+ * raised
+ */
+
+ private boolean canModifyNext(Node node) {
+ boolean textFirstChild = false;
+
+ short type = node.getNodeType();
+
+ if (type == Node.ENTITY_REFERENCE_NODE) {
+ //If the previous sibling was entityreference
+ //check if its content is replaceable
+ Node firstChild = node.getFirstChild();
+
+ //if the entity reference has no children
+ //return false
+ if (firstChild == null) {
+ fTextOnlyChildren = false;
return false;
}
-
- node = node.getNextSibling();
+
+ //The replacement text of the entity reference should
+ //be either only text,cadatsections or replaceable entity
+ //reference nodes or the last child should be neither of these
+ while (firstChild != null) {
+ short lType = firstChild.getNodeType();
+
+ if (lType == Node.TEXT_NODE || lType == Node.CDATA_SECTION_NODE) {
+ fTextOnlyChildren = true;
+ textFirstChild = true;
+ } else if (lType == Node.ENTITY_REFERENCE_NODE) {
+ if (!canModifyNext(firstChild)) {
+ fTextOnlyChildren = false;
+ return false;
+ } else {
+ //If the EntityReference child contains
+ //only text, or non-text or ends with a
+ //non-text node.
+ textFirstChild = true;
+ }
+ } else {
+ //If the first child was replaceable text and next
+ //children are not, then return false
+ if (textFirstChild) {
+ fTextOnlyChildren = false;
+ return false;
+ } else {
+ return true;
+ }
+ }
+ firstChild = firstChild.getNextSibling();
+ }
+ } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE) {
+ //If the previous sibling was text or cdatasection move to next
+ fTextOnlyChildren = true;
+ } else {
+ //If the next sibling was anything but text or
+ //cdatasection or an entity reference, stop search and
+ //return true
+ return true;
}
return true;
}
@@ -275,51 +462,53 @@
// Text methods
//
- /**
- * Break a text node into two sibling nodes. (Note that if the
- * current node has no parent, they won't wind up as "siblings" --
- * they'll both be orphans.)
- *
- * @param offset The offset at which to split. If offset is at the
- * end of the available data, the second node will be empty.
- *
- * @return A reference to the new node (containing data after the
- * offset point). The original node will contain data up to that
- * point.
- *
- * @throws DOMException(INDEX_SIZE_ERR) if offset is <0 or >length.
- *
- * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is read-only.
+ /**
+ * Break a text node into two sibling nodes. (Note that if the current node
+ * has no parent, they won't wind up as "siblings" -- they'll both be
+ * orphans.)
+ *
+ * @param offset
+ * The offset at which to split. If offset is at the end of the
+ * available data, the second node will be empty.
+ *
+ * @return A reference to the new node (containing data after the offset
+ * point). The original node will contain data up to that point.
+ *
+ * @throws DOMException(INDEX_SIZE_ERR)
+ * if offset is <0 or >length.
+ *
+ * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
+ * if node is read-only.
*/
public Text splitText(int offset)
throws DOMException {
- if (isReadOnly()) {
+ if (isReadOnly()) {
throw new DOMException(
- DOMException.NO_MODIFICATION_ALLOWED_ERR,
+ DOMException.NO_MODIFICATION_ALLOWED_ERR,
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null));
}
if (needsSyncData()) {
synchronizeData();
}
- if (offset < 0 || offset > data.length() ) {
+ if (offset < 0 || offset > data.length() ) {
throw new DOMException(DOMException.INDEX_SIZE_ERR,
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null));
}
-
+
// split text into two separate nodes
- Text newText =
+ Text newText =
getOwnerDocument().createTextNode(data.substring(offset));
- setNodeValue(data.substring(0, offset));
+ setNodeValue(data.substring(0, offset));
// insert new text node
Node parentNode = getParentNode();
- if (parentNode != null) {
- parentNode.insertBefore(newText, nextSibling);
+ if (parentNode != null) {
+ parentNode.insertBefore(newText, nextSibling);
}
- return newText;
+ return newText;
} // splitText(int):Text
@@ -341,6 +530,5 @@
data = "";
return olddata;
}
-
} // class TextImpl
---------------------------------------------------------------------
To unsubscribe, e-mail: xerces-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xerces-cvs-help@xml.apache.org