View Javadoc

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