001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.xml.xdm.nodes;
043:
044: import java.util.List;
045: import java.util.regex.Pattern;
046: import org.netbeans.modules.xml.xdm.visitor.XMLNodeVisitor;
047:
048: /**
049: *
050: * @author Ajit
051: */
052: public class Text extends NodeImpl implements Node, org.w3c.dom.Text {
053:
054: public void accept(XMLNodeVisitor visitor) {
055: visitor.visit(this );
056: }
057:
058: Text() {
059: super ();
060: }
061:
062: Text(String text) {
063: this ();
064: setText(text);
065: }
066:
067: @Override
068: public String getNodeValue() {
069: return getText();
070: }
071:
072: public short getNodeType() {
073: return Node.TEXT_NODE;
074: }
075:
076: public String getNodeName() {
077: return "#text"; //NOI18N
078: }
079:
080: @Override
081: public String getNamespaceURI() {
082: return null;
083: }
084:
085: public String getText() {
086: StringBuilder txtBuf = new StringBuilder();
087: for (Token token : getTokens()) {
088: if (token.getType() == TokenType.TOKEN_CHARACTER_DATA)
089: txtBuf.append(token.getValue());
090: }
091: return removeEntityReference(txtBuf.toString());
092: }
093:
094: public void setText(String text) {
095: checkNotInTree();
096: List<Token> tokens = getTokensForWrite();
097: if (!tokens.isEmpty())
098: tokens.clear();
099: // no null text allowed
100: if (text == null)
101: text = "";
102: text = insertEntityReference(text);
103: tokens.add(Token.create(text, TokenType.TOKEN_CHARACTER_DATA));
104: }
105:
106: /**
107: * Returns whether this text node contains <a href='http://www.w3.org/TR/2004/REC-xml-infoset-20040204#infoitem.character'>
108: * element content whitespace</a>, often abusively called "ignorable whitespace". The text node is
109: * determined to contain whitespace in element content during the load
110: * of the document or if validation occurs while using
111: * <code>Document.normalizeDocument()</code>.
112: * @since DOM Level 3
113: */
114: public boolean isElementContentWhitespace() {
115: //TODO Implement later
116: return false;
117: }
118:
119: /**
120: * The number of 16-bit units that are available through <code>data</code>
121: * and the <code>substringData</code> method below. This may have the
122: * value zero, i.e., <code>CharacterData</code> nodes may be empty.
123: */
124: public int getLength() {
125: //TODO Implement later
126: return -1;
127: }
128:
129: /**
130: * Replaces the text of the current node and all logically-adjacent text
131: * nodes with the specified text. All logically-adjacent text nodes are
132: * removed including the current node unless it was the recipient of the
133: * replacement text.
134: * <br>This method returns the node which received the replacement text.
135: * The returned node is:
136: * <ul>
137: * <li><code>null</code>, when the replacement text is
138: * the empty string;
139: * </li>
140: * <li>the current node, except when the current node is
141: * read-only;
142: * </li>
143: * <li> a new <code>Text</code> node of the same type (
144: * <code>Text</code> or <code>CDATASection</code>) as the current node
145: * inserted at the location of the replacement.
146: * </li>
147: * </ul>
148: * <br>For instance, in the above example calling
149: * <code>replaceWholeText</code> on the <code>Text</code> node that
150: * contains "bar" with "yo" in argument results in the following:
151: * <br>Where the nodes to be removed are read-only descendants of an
152: * <code>EntityReference</code>, the <code>EntityReference</code> must
153: * be removed instead of the read-only nodes. If any
154: * <code>EntityReference</code> to be removed has descendants that are
155: * not <code>EntityReference</code>, <code>Text</code>, or
156: * <code>CDATASection</code> nodes, the <code>replaceWholeText</code>
157: * method must fail before performing any modification of the document,
158: * raising a <code>DOMException</code> with the code
159: * <code>NO_MODIFICATION_ALLOWED_ERR</code>.
160: * <br>For instance, in the example below calling
161: * <code>replaceWholeText</code> on the <code>Text</code> node that
162: * contains "bar" fails, because the <code>EntityReference</code> node
163: * "ent" contains an <code>Element</code> node which cannot be removed.
164: * @param content The content of the replacing <code>Text</code> node.
165: * @return The <code>Text</code> node created with the specified content.
166: * @exception DOMException
167: * NO_MODIFICATION_ALLOWED_ERR: Raised if one of the <code>Text</code>
168: * nodes being replaced is readonly.
169: * @since DOM Level 3
170: */
171: public org.w3c.dom.Text replaceWholeText(String content) {
172: //TODO Implement later
173: return null;
174: }
175:
176: /**
177: * Breaks this node into two nodes at the specified <code>offset</code>,
178: * keeping both in the tree as siblings. After being split, this node
179: * will contain all the content up to the <code>offset</code> point. A
180: * new node of the same type, which contains all the content at and
181: * after the <code>offset</code> point, is returned. If the original
182: * node had a parent node, the new node is inserted as the next sibling
183: * of the original node. When the <code>offset</code> is equal to the
184: * length of this node, the new node has no data.
185: * @param offset The 16-bit unit offset at which to split, starting from
186: * <code>0</code>.
187: * @return The new node, of the same type as this node.
188: * @exception DOMException
189: * INDEX_SIZE_ERR: Raised if the specified offset is negative or greater
190: * than the number of 16-bit units in <code>data</code>.
191: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
192: */
193: public org.w3c.dom.Text splitText(int offset) {
194: //TODO Implement later
195: return null;
196: }
197:
198: /**
199: * Returns all text of <code>Text</code> nodes logically-adjacent text
200: * nodes to this node, concatenated in document order.
201: * <br>For instance, in the example below <code>wholeText</code> on the
202: * <code>Text</code> node that contains "bar" returns "barfoo", while on
203: * the <code>Text</code> node that contains "foo" it returns "barfoo".
204: * @since DOM Level 3
205: */
206: public String getWholeText() {
207: //TODO Implement later
208: return null;
209: }
210:
211: /**
212: * The character data of the node that implements this interface. The DOM
213: * implementation may not put arbitrary limits on the amount of data
214: * that may be stored in a <code>CharacterData</code> node. However,
215: * implementation limits may mean that the entirety of a node's data may
216: * not fit into a single <code>DOMString</code>. In such cases, the user
217: * may call <code>substringData</code> to retrieve the data in
218: * appropriately sized pieces.
219: * @exception DOMException
220: * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
221: */
222: public void setData(String text) {
223: checkNotInTree();
224: List<Token> tokens = getTokensForWrite();
225: if (!tokens.isEmpty())
226: tokens.clear();
227: // no null text allowed
228: if (text == null)
229: text = "";
230: tokens.add(Token.create(text, TokenType.TOKEN_CHARACTER_DATA));
231: }
232:
233: /**
234: * Append the string to the end of the character data of the node. Upon
235: * success, <code>data</code> provides access to the concatenation of
236: * <code>data</code> and the <code>DOMString</code> specified.
237: * @param arg The <code>DOMString</code> to append.
238: * @exception DOMException
239: * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
240: */
241: public void appendData(String arg) {
242: //TODO Implement later
243: }
244:
245: /**
246: * Replace the characters starting at the specified 16-bit unit offset
247: * with the specified string.
248: * @param offset The offset from which to start replacing.
249: * @param count The number of 16-bit units to replace. If the sum of
250: * <code>offset</code> and <code>count</code> exceeds
251: * <code>length</code>, then all 16-bit units to the end of the data
252: * are replaced; (i.e., the effect is the same as a <code>remove</code>
253: * method call with the same range, followed by an <code>append</code>
254: * method invocation).
255: * @param arg The <code>DOMString</code> with which the range must be
256: * replaced.
257: * @exception DOMException
258: * INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
259: * negative or greater than the number of 16-bit units in
260: * <code>data</code>, or if the specified <code>count</code> is
261: * negative.
262: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
263: */
264: public void replaceData(int offset, int count, String arg) {
265: //TODO Implement later
266: }
267:
268: /**
269: * Insert a string at the specified 16-bit unit offset.
270: * @param offset The character offset at which to insert.
271: * @param arg The <code>DOMString</code> to insert.
272: * @exception DOMException
273: * INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
274: * negative or greater than the number of 16-bit units in
275: * <code>data</code>.
276: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
277: */
278: public void insertData(int offset, String arg) {
279: //TODO Implement later
280: }
281:
282: /**
283: * Extracts a range of data from the node.
284: * @param offset Start offset of substring to extract.
285: * @param count The number of 16-bit units to extract.
286: * @return The specified substring. If the sum of <code>offset</code> and
287: * <code>count</code> exceeds the <code>length</code>, then all 16-bit
288: * units to the end of the data are returned.
289: * @exception DOMException
290: * INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
291: * negative or greater than the number of 16-bit units in
292: * <code>data</code>, or if the specified <code>count</code> is
293: * negative.
294: * <br>DOMSTRING_SIZE_ERR: Raised if the specified range of text does
295: * not fit into a <code>DOMString</code>.
296: */
297: public String substringData(int offset, int count) {
298: //TODO Implement later
299: return null;
300: }
301:
302: /**
303: * The character data of the node that implements this interface. The DOM
304: * implementation may not put arbitrary limits on the amount of data
305: * that may be stored in a <code>CharacterData</code> node. However,
306: * implementation limits may mean that the entirety of a node's data may
307: * not fit into a single <code>DOMString</code>. In such cases, the user
308: * may call <code>substringData</code> to retrieve the data in
309: * appropriately sized pieces.
310: * @exception DOMException
311: * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
312: * fit in a <code>DOMString</code> variable on the implementation
313: * platform.
314: */
315: public String getData() {
316: StringBuilder txtBuf = new StringBuilder();
317: for (Token token : getTokens()) {
318: if (token.getType() == TokenType.TOKEN_CHARACTER_DATA)
319: txtBuf.append(token.getValue());
320: }
321: return txtBuf.toString();
322: }
323:
324: /**
325: * Remove a range of 16-bit units from the node. Upon success,
326: * <code>data</code> and <code>length</code> reflect the change.
327: * @param offset The offset from which to start removing.
328: * @param count The number of 16-bit units to delete. If the sum of
329: * <code>offset</code> and <code>count</code> exceeds
330: * <code>length</code> then all 16-bit units from <code>offset</code>
331: * to the end of the data are deleted.
332: * @exception DOMException
333: * INDEX_SIZE_ERR: Raised if the specified <code>offset</code> is
334: * negative or greater than the number of 16-bit units in
335: * <code>data</code>, or if the specified <code>count</code> is
336: * negative.
337: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
338: */
339: public void deleteData(int offset, int count) {
340: //TODO Implement later
341: }
342:
343: private String insertEntityReference(String text) {
344: // just make sure we replace & with & and not & with &&amp; and so on
345: String result = removeEntityReference(text);
346: result = result.replaceAll("&", "&"); //replace &
347: result = result.replaceAll("<", "<"); //replace <
348: result = result.replaceAll(">", ">"); //replace >
349: // result = result.replaceAll("'","'"); //replace '
350: // result = result.replaceAll("\"","""); //replace "
351: return result;
352: }
353:
354: private String removeEntityReference(String text) {
355: String result = text;
356: result = AMPERSAND_PATTERN.matcher(result).replaceAll("&"); //replace with &
357: result = LESS_THAN_PATTERN.matcher(result).replaceAll("<"); //replace with <
358: result = GREATER_THAN_PATTERN.matcher(result).replaceAll(">"); //replace with >
359: // result = result.replaceAll("'","'"); //replace with '
360: // result = result.replaceAll(""","\""); //replace with "
361: return result;
362: }
363:
364: private static final Pattern AMPERSAND_PATTERN = Pattern
365: .compile("&"); //NOI18N
366: private static final Pattern LESS_THAN_PATTERN = Pattern
367: .compile("<"); //NOI18N
368: private static final Pattern GREATER_THAN_PATTERN = Pattern
369: .compile(">"); //NOI18N
370: }
|