/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
CharacterData is an abstract Node that can carry character data as its
Value. It provides shared behavior for Text, CData, and
possibly other node types. All offsets are 0-based.
Since ProcessingInstructionImpl inherits from this class to reuse the
setNodeValue method, this class isn't declared as implementing the interface
CharacterData. This is done by relevant subclasses (TexImpl, CommentImpl).
This class doesn't directly support mutation events, however, it notifies
the document when mutations are performed so that the document class do so.
@xerces.internal Since: PR-DOM-Level-1-19980818.
/**
* CharacterData is an abstract Node that can carry character data as its
* Value. It provides shared behavior for Text, CData, and
* possibly other node types. All offsets are 0-based.
* <p>
* Since ProcessingInstructionImpl inherits from this class to reuse the
* setNodeValue method, this class isn't declared as implementing the interface
* CharacterData. This is done by relevant subclasses (TexImpl, CommentImpl).
* <p>
* This class doesn't directly support mutation events, however, it notifies
* the document when mutations are performed so that the document class do so.
*
* @xerces.internal
*
* @since PR-DOM-Level-1-19980818.
*/
public abstract class CharacterDataImpl
extends ChildNode {
//
// Constants
//
Serialization version. /** Serialization version. */
static final long serialVersionUID = 7931170150428474230L;
//
// Data
//
protected String data;
Empty child nodes. /** Empty child nodes. */
private static transient NodeList singletonNodeList = new NodeList() {
public Node item(int index) { return null; }
public int getLength() { return 0; }
};
//
// Constructors
//
public CharacterDataImpl(){}
Factory constructor. /** Factory constructor. */
protected CharacterDataImpl(CoreDocumentImpl ownerDocument, String data) {
super(ownerDocument);
this.data = data;
}
//
// Node methods
//
Returns an empty node list. /** Returns an empty node list. */
public NodeList getChildNodes() {
return singletonNodeList;
}
/*
* returns the content of this node
*/
public String getNodeValue() {
if (needsSyncData()) {
synchronizeData();
}
return data;
}
Convenience wrapper for calling setNodeValueInternal when
we are not performing a replacement operation
/** Convenience wrapper for calling setNodeValueInternal when
* we are not performing a replacement operation
*/
protected void setNodeValueInternal (String value) {
setNodeValueInternal(value, false);
}
This function added so that we can distinguish whether
setNodeValue has been called from some other DOM functions.
or by the client.
This is important, because we do one type of Range fix-up,
from the high-level functions in CharacterData, and another
type if the client simply calls setNodeValue(value).
/** This function added so that we can distinguish whether
* setNodeValue has been called from some other DOM functions.
* or by the client.<p>
* This is important, because we do one type of Range fix-up,
* from the high-level functions in CharacterData, and another
* type if the client simply calls setNodeValue(value).
*/
protected void setNodeValueInternal(String value, boolean replace) {
CoreDocumentImpl ownerDocument = ownerDocument();
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);
}
// revisit: may want to set the value in ownerDocument.
// Default behavior, overridden in some subclasses
if (needsSyncData()) {
synchronizeData();
}
// keep old value for document notification
String oldvalue = this.data;
// notify document
ownerDocument.modifyingCharacterData(this, replace);
this.data = value;
// notify document
ownerDocument.modifiedCharacterData(this, oldvalue, value, replace);
}
Sets the content, possibly firing related events,
and updating ranges (via notification to the document)
/**
* Sets the content, possibly firing related events,
* and updating ranges (via notification to the document)
*/
public void setNodeValue(String value) {
setNodeValueInternal(value);
// notify document
ownerDocument().replacedText(this);
}
//
// CharacterData methods
//
Retrieve character data currently stored in this node.
Throws: - DOMExcpetion – (DOMSTRING_SIZE_ERR) In some implementations,
the stored data may exceed the permitted length of strings. If so,
getData() will throw this DOMException advising the user to
instead retrieve the data in chunks via the substring() operation.
/**
* Retrieve character data currently stored in this node.
*
* @throws DOMExcpetion(DOMSTRING_SIZE_ERR) In some implementations,
* the stored data may exceed the permitted length of strings. If so,
* getData() will throw this DOMException advising the user to
* instead retrieve the data in chunks via the substring() operation.
*/
public String getData() {
if (needsSyncData()) {
synchronizeData();
}
return data;
}
Report number of characters currently stored in this node's
data. It may be 0, meaning that the value is an empty string.
/**
* Report number of characters currently stored in this node's
* data. It may be 0, meaning that the value is an empty string.
*/
public int getLength() {
if (needsSyncData()) {
synchronizeData();
}
return data.length();
}
Concatenate additional characters onto the end of the data
stored in this node. Note that this, and insert(), are the paths
by which a DOM could wind up accumulating more data than the
language's strings can easily handle. (See above discussion.)
Throws: - DOMException – (NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
/**
* Concatenate additional characters onto the end of the data
* stored in this node. Note that this, and insert(), are the paths
* by which a DOM could wind up accumulating more data than the
* language's strings can easily handle. (See above discussion.)
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
*/
public void appendData(String data) {
if (isReadOnly()) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
}
if (data == null) {
return;
}
if (needsSyncData()) {
synchronizeData();
}
setNodeValue(this.data + data);
} // appendData(String)
Remove a range of characters from the node's value. Throws a
DOMException if the offset is beyond the end of the
string. However, a deletion _count_ that exceeds the available
data is accepted as a delete-to-end request.
Throws: - DOMException – (INDEX_SIZE_ERR) if offset is negative or
greater than length, or if count is negative.
- DOMException – (NO_MODIFICATION_ALLOWED_ERR) if node is
readonly.
/**
* Remove a range of characters from the node's value. Throws a
* DOMException if the offset is beyond the end of the
* string. However, a deletion _count_ that exceeds the available
* data is accepted as a delete-to-end request.
*
* @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
* greater than length, or if count is negative.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is
* readonly.
*/
public void deleteData(int offset, int count)
throws DOMException {
internalDeleteData(offset, count, false);
} // deleteData(int,int)
NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
to control which mutation events are spawned. This version of the
deleteData operation allows us to do so. It is not intended
for use by application programs.
/** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
* to control which mutation events are spawned. This version of the
* deleteData operation allows us to do so. It is not intended
* for use by application programs.
*/
void internalDeleteData (int offset, int count, boolean replace)
throws DOMException {
CoreDocumentImpl ownerDocument = ownerDocument();
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);
}
if (count < 0) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
throw new DOMException(DOMException.INDEX_SIZE_ERR, msg);
}
}
if (needsSyncData()) {
synchronizeData();
}
int tailLength = Math.max(data.length() - count - offset, 0);
try {
String value = data.substring(0, offset) +
(tailLength > 0 ? data.substring(offset + count, offset + count + tailLength) : "");
setNodeValueInternal(value, replace);
// notify document
ownerDocument.deletedText(this, offset, count);
}
catch (StringIndexOutOfBoundsException e) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
throw new DOMException(DOMException.INDEX_SIZE_ERR, msg);
}
} // internalDeleteData(int,int,boolean)
Insert additional characters into the data stored in this node,
at the offset specified.
Throws: - DOMException – (INDEX_SIZE_ERR) if offset is negative or
greater than length.
- DOMException – (NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
/**
* Insert additional characters into the data stored in this node,
* at the offset specified.
*
* @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
* greater than length.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
*/
public void insertData(int offset, String data)
throws DOMException {
internalInsertData(offset, data, false);
} // insertData(int,int)
NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
to control which mutation events are spawned. This version of the
insertData operation allows us to do so. It is not intended
for use by application programs.
/** NON-DOM INTERNAL: Within DOM actions, we sometimes need to be able
* to control which mutation events are spawned. This version of the
* insertData operation allows us to do so. It is not intended
* for use by application programs.
*/
void internalInsertData (int offset, String data, boolean replace)
throws DOMException {
CoreDocumentImpl ownerDocument = ownerDocument();
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();
}
try {
String value =
new StringBuffer(this.data).insert(offset, data).toString();
setNodeValueInternal(value, replace);
// notify document
ownerDocument.insertedText(this, offset, data.length());
}
catch (StringIndexOutOfBoundsException e) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
throw new DOMException(DOMException.INDEX_SIZE_ERR, msg);
}
} // internalInsertData(int,String,boolean)
Replace a series of characters at the specified (zero-based)
offset with a new string, NOT necessarily of the same
length. Convenience method, equivalent to a delete followed by an
insert. Throws a DOMException if the specified offset is beyond
the end of the existing data.
Params: - offset – The offset at which to begin replacing.
- count – The number of characters to remove,
interpreted as in the delete() method.
- data – The new string to be inserted at offset in place of
the removed data. Note that the entire string will
be inserted -- the count parameter does not affect
insertion, and the new data may be longer or shorter
than the substring it replaces.
Throws: - DOMException – (INDEX_SIZE_ERR) if offset is negative or
greater than length, or if count is negative.
- DOMException – (NO_MODIFICATION_ALLOWED_ERR) if node is
readonly.
/**
* Replace a series of characters at the specified (zero-based)
* offset with a new string, NOT necessarily of the same
* length. Convenience method, equivalent to a delete followed by an
* insert. Throws a DOMException if the specified offset is beyond
* the end of the existing data.
*
* @param offset The offset at which to begin replacing.
*
* @param count The number of characters to remove,
* interpreted as in the delete() method.
*
* @param data The new string to be inserted at offset in place of
* the removed data. Note that the entire string will
* be inserted -- the count parameter does not affect
* insertion, and the new data may be longer or shorter
* than the substring it replaces.
*
* @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
* greater than length, or if count is negative.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is
* readonly.
*/
public void replaceData(int offset, int count, String data)
throws DOMException {
CoreDocumentImpl ownerDocument = ownerDocument();
// The read-only check is done by deleteData()
// ***** This could be more efficient w/r/t Mutation Events,
// specifically by aggregating DOMAttrModified and
// DOMSubtreeModified. But mutation events are
// underspecified; I don't feel compelled
// to deal with it right now.
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();
}
//notify document
ownerDocument.replacingData(this);
// keep old value for document notification
String oldvalue = this.data;
internalDeleteData(offset, count, true);
internalInsertData(offset, data, true);
ownerDocument.replacedCharacterData(this, oldvalue, this.data);
} // replaceData(int,int,String)
Store character data into this node.
Throws: - DOMException – (NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
/**
* Store character data into this node.
*
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if node is readonly.
*/
public void setData(String value)
throws DOMException {
setNodeValue(value);
}
Substring is more than a convenience function. In some
implementations of the DOM, where the stored data may exceed the
length that can be returned in a single string, the only way to
read it all is to extract it in chunks via this method.
Params: - offset – Zero-based offset of first character to retrieve.
- count – Number of characters to retrieve.
If the sum of offset and count exceeds the length, all characters
to end of data are returned.
Throws: - DOMException – (INDEX_SIZE_ERR) if offset is negative or
greater than length, or if count is negative.
- DOMException – (WSTRING_SIZE_ERR) In some implementations,
count may exceed the permitted length of strings. If so,
substring() will throw this DOMException advising the user to
instead retrieve the data in smaller chunks.
/**
* Substring is more than a convenience function. In some
* implementations of the DOM, where the stored data may exceed the
* length that can be returned in a single string, the only way to
* read it all is to extract it in chunks via this method.
*
* @param offset Zero-based offset of first character to retrieve.
* @param count Number of characters to retrieve.
*
* If the sum of offset and count exceeds the length, all characters
* to end of data are returned.
*
* @throws DOMException(INDEX_SIZE_ERR) if offset is negative or
* greater than length, or if count is negative.
*
* @throws DOMException(WSTRING_SIZE_ERR) In some implementations,
* count may exceed the permitted length of strings. If so,
* substring() will throw this DOMException advising the user to
* instead retrieve the data in smaller chunks.
*/
public String substringData(int offset, int count)
throws DOMException {
if (needsSyncData()) {
synchronizeData();
}
int length = data.length();
if (count < 0 || offset < 0 || offset > length - 1) {
String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null);
throw new DOMException(DOMException.INDEX_SIZE_ERR, msg);
}
int tailIndex = Math.min(offset + count, length);
return data.substring(offset, tailIndex);
} // substringData(int,int):String
} // class CharacterDataImpl