001/*
002 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
003 * 
004 * This software is open source. 
005 * See the bottom of this file for the licence.
006 * 
007 * $Id: DOMNodeHelper.java,v 1.6 2001/04/10 23:43:44 jstrachan Exp $
008 */
009
010package org.dom4j.dom;
011
012import java.util.List;
013
014import org.dom4j.Branch;
015import org.dom4j.CharacterData;
016import org.dom4j.Document;
017import org.dom4j.DocumentType;
018import org.dom4j.Node;
019import org.dom4j.Element;
020import org.dom4j.QName;
021import org.dom4j.Namespace;
022import org.dom4j.Text;
023
024import org.w3c.dom.DOMException;
025import org.w3c.dom.NamedNodeMap;
026import org.w3c.dom.NodeList;
027
028/** <p><code>DOMNodeHelper</code> contains a collection of utility methods
029  * for use across Node implementations.</p>
030  *
031  * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
032  * @version $Revision: 1.6 $
033  */
034public class DOMNodeHelper {
035
036    public static final NodeList EMPTY_NODE_LIST = new EmptyNodeList();
037    
038    public static class EmptyNodeList implements NodeList {
039        public org.w3c.dom.Node item(int index) {
040            return null;
041        }
042        public int getLength() {
043            return 0;
044        }
045    }
046    
047    
048    // Node API
049    //-------------------------------------------------------------------------        
050
051    public static String getNamespaceURI(Node node) {
052        return null;
053    }
054
055    public static String getPrefix(Node node) {
056        return null;
057    }
058    
059    public static String getLocalName(Node node) {
060        return null;
061    }
062    
063    public static void setPrefix(Node node, String prefix) throws DOMException {
064        notSupported();
065    }
066    
067    public static String getNodeValue(Node node) throws DOMException {
068        return node.getText();
069    }
070    
071    public static void setNodeValue(Node node, String nodeValue) throws DOMException {
072        node.setText(nodeValue);
073    }
074
075    public static org.w3c.dom.Node getParentNode(Node node) {
076        return asDOMNode( node.getParent() );
077    }
078
079    public static NodeList getChildNodes(Node node) {
080        return EMPTY_NODE_LIST;
081    }
082
083    public static org.w3c.dom.Node getFirstChild(Node node) {
084        return null;
085    }
086
087    public static org.w3c.dom.Node getLastChild(Node node) {
088        return null;
089    }
090
091    public static org.w3c.dom.Node getPreviousSibling(Node node) {
092        Element parent = node.getParent();
093        if ( parent != null ) {
094            int index = parent.indexOf( node );
095            if ( index > 0 ) {
096                Node previous = parent.node(index - 1);
097                return asDOMNode( previous );
098            }
099        }
100        return null;
101    }
102
103    public static org.w3c.dom.Node getNextSibling(Node node) {
104        Element parent = node.getParent();
105        if ( parent != null ) {
106            int index = parent.indexOf( node );
107            if ( index >= 0 ) {
108                if ( ++index < parent.nodeCount() ) {
109                    Node next = parent.node(index);
110                    return asDOMNode( next );
111                }
112            }
113        }
114        return null;
115    }
116
117    public static NamedNodeMap getAttributes(Node node) {
118        return null;
119    }
120
121    public static org.w3c.dom.Document getOwnerDocument(Node node) {
122        return asDOMDocument( node.getDocument() );
123    }
124
125    public static org.w3c.dom.Node insertBefore(
126        Node node, 
127        org.w3c.dom.Node newChild, 
128        org.w3c.dom.Node refChild
129    ) throws DOMException {
130        throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Children not allowed for this node: " + node );
131    }
132
133    public static org.w3c.dom.Node replaceChild(
134        Node node, 
135        org.w3c.dom.Node newChild, 
136        org.w3c.dom.Node oldChild
137    ) throws DOMException {
138        throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Children not allowed for this node: " + node );
139    }
140
141    public static org.w3c.dom.Node removeChild(
142        Node node, 
143        org.w3c.dom.Node oldChild
144    ) throws DOMException {
145        throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Children not allowed for this node: " + node );
146    }
147
148    public static org.w3c.dom.Node appendChild(
149        Node node, 
150        org.w3c.dom.Node newChild
151    ) throws DOMException {
152        throw new DOMException( DOMException.HIERARCHY_REQUEST_ERR, "Children not allowed for this node: " + node );
153    }
154
155    public static boolean hasChildNodes(Node node) {
156        return false;
157    }
158
159    public static org.w3c.dom.Node cloneNode(Node node, boolean deep) {
160        return asDOMNode( (Node) node.clone() );
161    }
162
163    public static void normalize(Node node) {
164        notSupported();
165    }
166
167    public static boolean isSupported(Node node, String feature, String version) {
168        return false;
169    }
170
171    public static boolean hasAttributes(Node node) {
172        return false;
173    }
174
175
176    // CharacterData API
177    //-------------------------------------------------------------------------        
178    
179    public static String getData(CharacterData charData) throws DOMException {
180        return charData.getText();
181    }
182    
183    public static void setData(CharacterData charData, String data) throws DOMException {
184        charData.setText(data);
185    }
186
187    public static int getLength(CharacterData charData) {
188        String text = charData.getText();
189        return ( text != null ) ? text.length() : 0;
190    }
191
192    public static String substringData(
193        CharacterData charData, int offset, int count
194    ) throws DOMException {
195        String text = charData.getText();
196        int length = ( text != null ) ? text.length() : 0;
197        if ( offset < 0 || offset >= length ) {
198            throw new DOMException( 
199                DOMException.INDEX_SIZE_ERR, 
200                "No text at offset: " + offset
201            );
202        }
203        return text.substring( offset, offset + count );
204    }
205
206    public static void appendData(
207        CharacterData charData, String arg
208    ) throws DOMException {
209        if ( charData.isReadOnly() ) {
210            throw new DOMException( 
211                DOMException.NO_MODIFICATION_ALLOWED_ERR,
212                "CharacterData node is read only: " + charData 
213            );
214        }
215        else {
216            String text = charData.getText();
217            if ( text == null ) {
218                charData.setText( text );
219            }
220            else {
221                charData.setText( text + arg );
222            }
223        }
224    }
225
226    public static void insertData(CharacterData charData, int offset, String arg) throws DOMException {
227        if ( charData.isReadOnly() ) {
228            throw new DOMException( 
229                DOMException.NO_MODIFICATION_ALLOWED_ERR,
230                "CharacterData node is read only: " + charData 
231            );
232        }
233        else {
234            String text = charData.getText();
235            if ( text == null ) {
236                charData.setText( arg );
237            }
238            else {
239                int length = text.length();
240                if ( offset < 0 || offset >= length ) {
241                    throw new DOMException( 
242                        DOMException.INDEX_SIZE_ERR, 
243                        "No text at offset: " + offset
244                    );
245                }
246                else {
247                    StringBuffer buffer = new StringBuffer( text );
248                    buffer.insert( offset, arg );
249                    charData.setText( buffer.toString() );
250                }
251            }
252        }
253    }
254
255    public static void deleteData(CharacterData charData, int offset, int count) throws DOMException {
256        if ( charData.isReadOnly() ) {
257            throw new DOMException( 
258                DOMException.NO_MODIFICATION_ALLOWED_ERR,
259                "CharacterData node is read only: " + charData 
260            );
261        }
262        else {
263            String text = charData.getText();
264            if ( text != null ) {
265                int length = text.length();
266                if ( offset < 0 || offset >= length ) {
267                    throw new DOMException( 
268                        DOMException.INDEX_SIZE_ERR, 
269                        "No text at offset: " + offset
270                    );
271                }
272                else {
273                    StringBuffer buffer = new StringBuffer( text );
274                    buffer.delete( offset, offset + count );
275                    charData.setText( buffer.toString() );
276                }
277            }
278        }
279    }
280
281    public static void replaceData(
282        CharacterData charData, int offset, int count, String arg
283    ) throws DOMException {
284        if ( charData.isReadOnly() ) {
285            throw new DOMException( 
286                DOMException.NO_MODIFICATION_ALLOWED_ERR,
287                "CharacterData node is read only: " + charData 
288            );
289        }
290        else {
291            String text = charData.getText();
292            if ( text != null ) {
293                int length = text.length();
294                if ( offset < 0 || offset >= length ) {
295                    throw new DOMException( 
296                        DOMException.INDEX_SIZE_ERR, 
297                        "No text at offset: " + offset
298                    );
299                }
300                else {
301                    StringBuffer buffer = new StringBuffer( text );
302                    buffer.replace( offset, offset + count, arg );
303                    charData.setText( buffer.toString() );
304                }
305            }
306        }
307    }
308
309
310    // Branch API
311    //-------------------------------------------------------------------------        
312    
313    public static void appendElementsByTagName(
314        List list, Branch parent, String name
315    ) {
316        for ( int i = 0, size = parent.nodeCount(); i < size; i++ ) {
317            Node node = parent.node(i);
318            if ( node instanceof Element ) {
319                Element element = (Element) node;
320                if ( name.equals( element.getName() ) ) {
321                    list.add( element );
322                }
323                appendElementsByTagName(list, element, name);
324            }
325        }
326    }
327
328    public static void appendElementsByTagNameNS(
329        List list, Branch parent, String namespaceURI, String localName
330    ) {
331        for ( int i = 0, size = parent.nodeCount(); i < size; i++ ) {
332            Node node = parent.node(i);
333            if ( node instanceof Element ) {
334                Element element = (Element) node;
335                if ( namespaceURI.equals( element.getNamespaceURI() ) 
336                        && localName.equals( element.getName() ) ) {
337                    list.add( element );
338                }
339                appendElementsByTagNameNS(list, element, namespaceURI, localName);
340            }
341        }
342    }
343
344    
345    // Helper methods
346    //-------------------------------------------------------------------------        
347    
348    public static NodeList createNodeList( final List list ) {
349        return new NodeList() {
350            public org.w3c.dom.Node item(int index) {
351                return DOMNodeHelper.asDOMNode( (Node) list.get( index ) );
352            }
353            public int getLength() {
354                return list.size();
355            }
356        };
357    }
358
359    public static org.w3c.dom.Node asDOMNode(Node node) {
360        if ( node instanceof org.w3c.dom.Node ) {
361            return (org.w3c.dom.Node) node;
362        }
363        else {
364            // Use DOMWriter?
365            System.out.println( "Cannot convert: " + node + " into a W3C DOM Node");
366            notSupported();
367            return null;
368        }
369    }
370    
371    public static org.w3c.dom.Document asDOMDocument(Document document) {
372        if ( document instanceof org.w3c.dom.Document ) {
373            return (org.w3c.dom.Document) document;
374        }
375        else {
376            // Use DOMWriter?
377            notSupported();
378            return null;
379        }
380    }
381    
382    public static org.w3c.dom.DocumentType asDOMDocumentType(DocumentType documentType) {
383        if ( documentType instanceof org.w3c.dom.DocumentType ) {
384            return (org.w3c.dom.DocumentType) documentType;
385        }
386        else {
387            // Use DOMWriter?
388            notSupported();
389            return null;
390        }
391    }
392
393    public static org.w3c.dom.Text asDOMText(CharacterData text) {
394        if ( text instanceof org.w3c.dom.Text ) {
395            return (org.w3c.dom.Text) text;
396        }
397        else {
398            // Use DOMWriter?
399            notSupported();
400            return null;
401        }
402    }
403
404    public static org.w3c.dom.Element asDOMElement(Node element) {
405        if ( element instanceof org.w3c.dom.Element ) {
406            return (org.w3c.dom.Element) element;
407        }
408        else {
409            // Use DOMWriter?
410            notSupported();
411            return null;
412        }
413    }
414
415    public static org.w3c.dom.Attr asDOMAttr(Node attribute) {
416        if ( attribute instanceof org.w3c.dom.Attr ) {
417            return (org.w3c.dom.Attr) attribute;
418        }
419        else {
420            // Use DOMWriter?
421            notSupported();
422            return null;
423        }
424    }
425
426    /** Called when a method has not been implemented yet 
427      */
428    public static void notSupported() {
429        throw new DOMException( DOMException.NOT_SUPPORTED_ERR, "Not supported yet");
430    }
431    
432}
433
434
435
436
437/*
438 * Redistribution and use of this software and associated documentation
439 * ("Software"), with or without modification, are permitted provided
440 * that the following conditions are met:
441 *
442 * 1. Redistributions of source code must retain copyright
443 *    statements and notices.  Redistributions must also contain a
444 *    copy of this document.
445 *
446 * 2. Redistributions in binary form must reproduce the
447 *    above copyright notice, this list of conditions and the
448 *    following disclaimer in the documentation and/or other
449 *    materials provided with the distribution.
450 *
451 * 3. The name "DOM4J" must not be used to endorse or promote
452 *    products derived from this Software without prior written
453 *    permission of MetaStuff, Ltd.  For written permission,
454 *    please contact dom4j-info@metastuff.com.
455 *
456 * 4. Products derived from this Software may not be called "DOM4J"
457 *    nor may "DOM4J" appear in their names without prior written
458 *    permission of MetaStuff, Ltd. DOM4J is a registered
459 *    trademark of MetaStuff, Ltd.
460 *
461 * 5. Due credit should be given to the DOM4J Project
462 *    (http://dom4j.org/).
463 *
464 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
465 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
466 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
467 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
468 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
469 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
470 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
471 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
472 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
473 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
474 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
475 * OF THE POSSIBILITY OF SUCH DAMAGE.
476 *
477 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
478 *
479 * $Id: DOMNodeHelper.java,v 1.6 2001/04/10 23:43:44 jstrachan Exp $
480 */