View Javadoc

1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
6    */
7   
8   package org.dom4j.dom;
9   
10  import java.util.List;
11  
12  import org.dom4j.Branch;
13  import org.dom4j.CharacterData;
14  import org.dom4j.Document;
15  import org.dom4j.DocumentType;
16  import org.dom4j.Element;
17  import org.dom4j.Node;
18  
19  import org.w3c.dom.DOMException;
20  import org.w3c.dom.NamedNodeMap;
21  import org.w3c.dom.NodeList;
22  
23  /***
24   * <p>
25   * <code>DOMNodeHelper</code> contains a collection of utility methods for use
26   * across Node implementations.
27   * </p>
28   * 
29   * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
30   * @version $Revision: 1.20 $
31   */
32  public class DOMNodeHelper {
33      public static final NodeList EMPTY_NODE_LIST = new EmptyNodeList();
34  
35      protected DOMNodeHelper() {
36      }
37  
38      // Node API
39      // -------------------------------------------------------------------------
40      public static boolean supports(Node node, String feature, String version) {
41          return false;
42      }
43  
44      public static String getNamespaceURI(Node node) {
45          return null;
46      }
47  
48      public static String getPrefix(Node node) {
49          return null;
50      }
51  
52      public static String getLocalName(Node node) {
53          return null;
54      }
55  
56      public static void setPrefix(Node node, String prefix) throws DOMException {
57          notSupported();
58      }
59  
60      public static String getNodeValue(Node node) throws DOMException {
61          return node.getText();
62      }
63  
64      public static void setNodeValue(Node node, String nodeValue)
65              throws DOMException {
66          node.setText(nodeValue);
67      }
68  
69      public static org.w3c.dom.Node getParentNode(Node node) {
70          return asDOMNode(node.getParent());
71      }
72  
73      public static NodeList getChildNodes(Node node) {
74          return EMPTY_NODE_LIST;
75      }
76  
77      public static org.w3c.dom.Node getFirstChild(Node node) {
78          return null;
79      }
80  
81      public static org.w3c.dom.Node getLastChild(Node node) {
82          return null;
83      }
84  
85      public static org.w3c.dom.Node getPreviousSibling(Node node) {
86          Element parent = node.getParent();
87  
88          if (parent != null) {
89              int index = parent.indexOf(node);
90  
91              if (index > 0) {
92                  Node previous = parent.node(index - 1);
93  
94                  return asDOMNode(previous);
95              }
96          }
97  
98          return null;
99      }
100 
101     public static org.w3c.dom.Node getNextSibling(Node node) {
102         Element parent = node.getParent();
103 
104         if (parent != null) {
105             int index = parent.indexOf(node);
106 
107             if (index >= 0) {
108                 if (++index < parent.nodeCount()) {
109                     Node next = parent.node(index);
110 
111                     return asDOMNode(next);
112                 }
113             }
114         }
115 
116         return null;
117     }
118 
119     public static NamedNodeMap getAttributes(Node node) {
120         return null;
121     }
122 
123     public static org.w3c.dom.Document getOwnerDocument(Node node) {
124         return asDOMDocument(node.getDocument());
125     }
126 
127     public static org.w3c.dom.Node insertBefore(Node node,
128             org.w3c.dom.Node newChild, org.w3c.dom.Node refChild)
129             throws DOMException {
130         if (node instanceof Branch) {
131             Branch branch = (Branch) node;
132             List list = branch.content();
133             int index = list.indexOf(refChild);
134 
135             if (index < 0) {
136                 branch.add((Node) newChild);
137             } else {
138                 list.add(index, newChild);
139             }
140 
141             return newChild;
142         } else {
143             throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
144                     "Children not allowed for this node: " + node);
145         }
146     }
147 
148     public static org.w3c.dom.Node replaceChild(Node node,
149             org.w3c.dom.Node newChild, org.w3c.dom.Node oldChild)
150             throws DOMException {
151         if (node instanceof Branch) {
152             Branch branch = (Branch) node;
153             List list = branch.content();
154             int index = list.indexOf(oldChild);
155 
156             if (index < 0) {
157                 throw new DOMException(DOMException.NOT_FOUND_ERR,
158                         "Tried to replace a non existing child " + "for node: "
159                                 + node);
160             }
161 
162             list.set(index, newChild);
163 
164             return oldChild;
165         } else {
166             throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
167                     "Children not allowed for this node: " + node);
168         }
169     }
170 
171     public static org.w3c.dom.Node removeChild(Node node,
172             org.w3c.dom.Node oldChild) throws DOMException {
173         if (node instanceof Branch) {
174             Branch branch = (Branch) node;
175             branch.remove((Node) oldChild);
176 
177             return oldChild;
178         }
179 
180         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
181                 "Children not allowed for this node: " + node);
182     }
183 
184     public static org.w3c.dom.Node appendChild(Node node,
185             org.w3c.dom.Node newChild) throws DOMException {
186         if (node instanceof Branch) {
187             Branch branch = (Branch) node;
188             org.w3c.dom.Node previousParent = newChild.getParentNode();
189 
190             if (previousParent != null) {
191                 previousParent.removeChild(newChild);
192             }
193 
194             branch.add((Node) newChild);
195 
196             return newChild;
197         }
198 
199         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
200                 "Children not allowed for this node: " + node);
201     }
202 
203     public static boolean hasChildNodes(Node node) {
204         return false;
205     }
206 
207     public static org.w3c.dom.Node cloneNode(Node node, boolean deep) {
208         return asDOMNode((Node) node.clone());
209     }
210 
211     public static void normalize(Node node) {
212         notSupported();
213     }
214 
215     public static boolean isSupported(Node n, String feature, String version) {
216         return false;
217     }
218 
219     public static boolean hasAttributes(Node node) {
220         if ((node != null) && node instanceof Element) {
221             return ((Element) node).attributeCount() > 0;
222         } else {
223             return false;
224         }
225     }
226 
227     // CharacterData API
228     // -------------------------------------------------------------------------
229     public static String getData(CharacterData charData) throws DOMException {
230         return charData.getText();
231     }
232 
233     public static void setData(CharacterData charData, String data)
234             throws DOMException {
235         charData.setText(data);
236     }
237 
238     public static int getLength(CharacterData charData) {
239         String text = charData.getText();
240 
241         return (text != null) ? text.length() : 0;
242     }
243 
244     public static String substringData(CharacterData charData, int offset,
245             int count) throws DOMException {
246         if (count < 0) {
247             throw new DOMException(DOMException.INDEX_SIZE_ERR,
248                     "Illegal value for count: " + count);
249         }
250 
251         String text = charData.getText();
252         int length = (text != null) ? text.length() : 0;
253 
254         if ((offset < 0) || (offset >= length)) {
255             throw new DOMException(DOMException.INDEX_SIZE_ERR,
256                     "No text at offset: " + offset);
257         }
258 
259         if ((offset + count) > length) {
260             return text.substring(offset);
261         }
262 
263         return text.substring(offset, offset + count);
264     }
265 
266     public static void appendData(CharacterData charData, String arg)
267             throws DOMException {
268         if (charData.isReadOnly()) {
269             throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
270                     "CharacterData node is read only: " + charData);
271         } else {
272             String text = charData.getText();
273 
274             if (text == null) {
275                 charData.setText(text);
276             } else {
277                 charData.setText(text + arg);
278             }
279         }
280     }
281 
282     public static void insertData(CharacterData data, int offset, String arg)
283             throws DOMException {
284         if (data.isReadOnly()) {
285             throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
286                     "CharacterData node is read only: " + data);
287         } else {
288             String text = data.getText();
289 
290             if (text == null) {
291                 data.setText(arg);
292             } else {
293                 int length = text.length();
294 
295                 if ((offset < 0) || (offset > length)) {
296                     throw new DOMException(DOMException.INDEX_SIZE_ERR,
297                             "No text at offset: " + offset);
298                 } else {
299                     StringBuffer buffer = new StringBuffer(text);
300                     buffer.insert(offset, arg);
301                     data.setText(buffer.toString());
302                 }
303             }
304         }
305     }
306 
307     public static void deleteData(CharacterData charData, int offset, int count)
308             throws DOMException {
309         if (charData.isReadOnly()) {
310             throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
311                     "CharacterData node is read only: " + charData);
312         } else {
313             if (count < 0) {
314                 throw new DOMException(DOMException.INDEX_SIZE_ERR,
315                         "Illegal value for count: " + count);
316             }
317 
318             String text = charData.getText();
319 
320             if (text != null) {
321                 int length = text.length();
322 
323                 if ((offset < 0) || (offset >= length)) {
324                     throw new DOMException(DOMException.INDEX_SIZE_ERR,
325                             "No text at offset: " + offset);
326                 } else {
327                     StringBuffer buffer = new StringBuffer(text);
328                     buffer.delete(offset, offset + count);
329                     charData.setText(buffer.toString());
330                 }
331             }
332         }
333     }
334 
335     public static void replaceData(CharacterData charData, int offset,
336             int count, String arg) throws DOMException {
337         if (charData.isReadOnly()) {
338             throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
339                     "CharacterData node is read only: " + charData);
340         } else {
341             if (count < 0) {
342                 throw new DOMException(DOMException.INDEX_SIZE_ERR,
343                         "Illegal value for count: " + count);
344             }
345 
346             String text = charData.getText();
347 
348             if (text != null) {
349                 int length = text.length();
350 
351                 if ((offset < 0) || (offset >= length)) {
352                     throw new DOMException(DOMException.INDEX_SIZE_ERR,
353                             "No text at offset: " + offset);
354                 } else {
355                     StringBuffer buffer = new StringBuffer(text);
356                     buffer.replace(offset, offset + count, arg);
357                     charData.setText(buffer.toString());
358                 }
359             }
360         }
361     }
362 
363     // Branch API
364     // -------------------------------------------------------------------------
365     public static void appendElementsByTagName(List list, Branch parent,
366             String name) {
367         final boolean isStar = "*".equals(name);
368 
369         for (int i = 0, size = parent.nodeCount(); i < size; i++) {
370             Node node = parent.node(i);
371 
372             if (node instanceof Element) {
373                 Element element = (Element) node;
374 
375                 if (isStar || name.equals(element.getName())) {
376                     list.add(element);
377                 }
378 
379                 appendElementsByTagName(list, element, name);
380             }
381         }
382     }
383 
384     public static void appendElementsByTagNameNS(List list, Branch parent,
385             String namespace, String localName) {
386         final boolean isStarNS = "*".equals(namespace);
387         final boolean isStar = "*".equals(localName);
388 
389         for (int i = 0, size = parent.nodeCount(); i < size; i++) {
390             Node node = parent.node(i);
391 
392             if (node instanceof Element) {
393                 Element element = (Element) node;
394 
395                 if ((isStarNS
396                         || (((namespace == null) 
397                                 || (namespace.length() == 0)) && ((element
398                                 .getNamespaceURI() == null) || (element
399                                 .getNamespaceURI().length() == 0))) 
400                                 || ((namespace != null) && namespace
401                         .equals(element.getNamespaceURI())))
402                         && (isStar || localName.equals(element.getName()))) {
403                     list.add(element);
404                 }
405 
406                 appendElementsByTagNameNS(list, element, namespace, localName);
407             }
408         }
409     }
410 
411     // Helper methods
412     // -------------------------------------------------------------------------
413     public static NodeList createNodeList(final List list) {
414         return new NodeList() {
415             public org.w3c.dom.Node item(int index) {
416                 if (index >= getLength()) {
417                     /*
418                      * From the NodeList specification: If index is greater than
419                      * or equal to the number of nodes in the list, this returns
420                      * null.
421                      */
422                     return null;
423                 } else {
424                     return DOMNodeHelper.asDOMNode((Node) list.get(index));
425                 }
426             }
427 
428             public int getLength() {
429                 return list.size();
430             }
431         };
432     }
433 
434     public static org.w3c.dom.Node asDOMNode(Node node) {
435         if (node == null) {
436             return null;
437         }
438 
439         if (node instanceof org.w3c.dom.Node) {
440             return (org.w3c.dom.Node) node;
441         } else {
442             // Use DOMWriter?
443             System.out.println("Cannot convert: " + node
444                     + " into a W3C DOM Node");
445             notSupported();
446 
447             return null;
448         }
449     }
450 
451     public static org.w3c.dom.Document asDOMDocument(Document document) {
452         if (document == null) {
453             return null;
454         }
455 
456         if (document instanceof org.w3c.dom.Document) {
457             return (org.w3c.dom.Document) document;
458         } else {
459             // Use DOMWriter?
460             notSupported();
461 
462             return null;
463         }
464     }
465 
466     public static org.w3c.dom.DocumentType asDOMDocumentType(DocumentType dt) {
467         if (dt == null) {
468             return null;
469         }
470 
471         if (dt instanceof org.w3c.dom.DocumentType) {
472             return (org.w3c.dom.DocumentType) dt;
473         } else {
474             // Use DOMWriter?
475             notSupported();
476 
477             return null;
478         }
479     }
480 
481     public static org.w3c.dom.Text asDOMText(CharacterData text) {
482         if (text == null) {
483             return null;
484         }
485 
486         if (text instanceof org.w3c.dom.Text) {
487             return (org.w3c.dom.Text) text;
488         } else {
489             // Use DOMWriter?
490             notSupported();
491 
492             return null;
493         }
494     }
495 
496     public static org.w3c.dom.Element asDOMElement(Node element) {
497         if (element == null) {
498             return null;
499         }
500 
501         if (element instanceof org.w3c.dom.Element) {
502             return (org.w3c.dom.Element) element;
503         } else {
504             // Use DOMWriter?
505             notSupported();
506 
507             return null;
508         }
509     }
510 
511     public static org.w3c.dom.Attr asDOMAttr(Node attribute) {
512         if (attribute == null) {
513             return null;
514         }
515 
516         if (attribute instanceof org.w3c.dom.Attr) {
517             return (org.w3c.dom.Attr) attribute;
518         } else {
519             // Use DOMWriter?
520             notSupported();
521 
522             return null;
523         }
524     }
525 
526     /***
527      * Called when a method has not been implemented yet
528      * 
529      * @throws DOMException
530      *             DOCUMENT ME!
531      */
532     public static void notSupported() {
533         throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
534                 "Not supported yet");
535     }
536 
537     public static class EmptyNodeList implements NodeList {
538         public org.w3c.dom.Node item(int index) {
539             return null;
540         }
541 
542         public int getLength() {
543             return 0;
544         }
545     }
546 }
547 
548 /*
549  * Redistribution and use of this software and associated documentation
550  * ("Software"), with or without modification, are permitted provided that the
551  * following conditions are met:
552  * 
553  * 1. Redistributions of source code must retain copyright statements and
554  * notices. Redistributions must also contain a copy of this document.
555  * 
556  * 2. Redistributions in binary form must reproduce the above copyright notice,
557  * this list of conditions and the following disclaimer in the documentation
558  * and/or other materials provided with the distribution.
559  * 
560  * 3. The name "DOM4J" must not be used to endorse or promote products derived
561  * from this Software without prior written permission of MetaStuff, Ltd. For
562  * written permission, please contact dom4j-info@metastuff.com.
563  * 
564  * 4. Products derived from this Software may not be called "DOM4J" nor may
565  * "DOM4J" appear in their names without prior written permission of MetaStuff,
566  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
567  * 
568  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
569  * 
570  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
571  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
572  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
573  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
574  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
575  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
576  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
577  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
578  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
579  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
580  * POSSIBILITY OF SUCH DAMAGE.
581  * 
582  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
583  */