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  */