Home | History | Annotate | Download | only in kdom
      1 /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to deal
      5  * in the Software without restriction, including without limitation the rights
      6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The  above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE. */
     20 
     21 package org.ksoap2.kdom;
     22 
     23 import java.util.*;
     24 import java.io.*;
     25 import org.xmlpull.v1.*;
     26 
     27 /** A common base class for Document and Element, also used for
     28     storing XML fragments. */
     29 
     30 public class Node { //implements XmlIO{
     31 
     32     public static final int DOCUMENT = 0;
     33     public static final int ELEMENT = 2;
     34     public static final int TEXT = 4;
     35     public static final int CDSECT = 5;
     36     public static final int ENTITY_REF = 6;
     37     public static final int IGNORABLE_WHITESPACE = 7;
     38     public static final int PROCESSING_INSTRUCTION = 8;
     39     public static final int COMMENT = 9;
     40     public static final int DOCDECL = 10;
     41 
     42     protected Vector children;
     43     protected StringBuffer types;
     44 
     45     /** inserts the given child object of the given type at the
     46     given index. */
     47 
     48     public void addChild(int index, int type, Object child) {
     49 
     50         if (child == null)
     51             throw new NullPointerException();
     52 
     53         if (children == null) {
     54             children = new Vector();
     55             types = new StringBuffer();
     56         }
     57 
     58         if (type == ELEMENT) {
     59             if (!(child instanceof Element))
     60                 throw new RuntimeException("Element obj expected)");
     61 
     62             ((Element) child).setParent(this);
     63         }
     64         else if (!(child instanceof String))
     65             throw new RuntimeException("String expected");
     66 
     67         children.insertElementAt(child, index);
     68         types.insert(index, (char) type);
     69     }
     70 
     71     /** convenience method for addChild (getChildCount (), child) */
     72 
     73     public void addChild(int type, Object child) {
     74         addChild(getChildCount(), type, child);
     75     }
     76 
     77     /** Builds a default element with the given properties. Elements
     78     should always be created using this method instead of the
     79     constructor in order to enable construction of specialized
     80     subclasses by deriving custom Document classes. Please note:
     81     For no namespace, please use Xml.NO_NAMESPACE, null is not a
     82     legal value. Currently, null is converted to Xml.NO_NAMESPACE,
     83     but future versions may throw an exception. */
     84 
     85     public Element createElement(String namespace, String name) {
     86 
     87         Element e = new Element();
     88         e.namespace = namespace == null ? "" : namespace;
     89         e.name = name;
     90         return e;
     91     }
     92 
     93     /** Returns the child object at the given index.  For child
     94         elements, an Element object is returned. For all other child
     95         types, a String is returned. */
     96 
     97     public Object getChild(int index) {
     98         return children.elementAt(index);
     99     }
    100 
    101     /** Returns the number of child objects */
    102 
    103     public int getChildCount() {
    104         return children == null ? 0 : children.size();
    105     }
    106 
    107     /** returns the element at the given index. If the node at the
    108     given index is a text node, null is returned */
    109 
    110     public Element getElement(int index) {
    111         Object child = getChild(index);
    112         return (child instanceof Element) ? (Element) child : null;
    113     }
    114 
    115     /** Returns the element with the given namespace and name. If the
    116         element is not found, or more than one matching elements are
    117         found, an exception is thrown. */
    118 
    119     public Element getElement(String namespace, String name) {
    120 
    121         int i = indexOf(namespace, name, 0);
    122         int j = indexOf(namespace, name, i + 1);
    123 
    124         if (i == -1 || j != -1)
    125             throw new RuntimeException(
    126                     "Element {"
    127                             + namespace
    128                             + "}"
    129                             + name
    130                             + (i == -1 ? " not found in " : " more than once in ")
    131                             + this);
    132 
    133         return getElement(i);
    134     }
    135 
    136     /* returns "#document-fragment". For elements, the element name is returned
    137 
    138     public String getName() {
    139         return "#document-fragment";
    140     }
    141 
    142     /** Returns the namespace of the current element. For Node
    143         and Document, Xml.NO_NAMESPACE is returned.
    144 
    145     public String getNamespace() {
    146         return "";
    147     }
    148 
    149     public int getNamespaceCount () {
    150         return 0;
    151     }
    152 
    153     /** returns the text content if the element has text-only
    154     content. Throws an exception for mixed content
    155 
    156     public String getText() {
    157 
    158         StringBuffer buf = new StringBuffer();
    159         int len = getChildCount();
    160 
    161         for (int i = 0; i < len; i++) {
    162             if (isText(i))
    163                 buf.append(getText(i));
    164             else if (getType(i) == ELEMENT)
    165                 throw new RuntimeException("not text-only content!");
    166         }
    167 
    168         return buf.toString();
    169     }
    170     */
    171 
    172     /** Returns the text node with the given index or null if the node
    173         with the given index is not a text node. */
    174 
    175     public String getText(int index) {
    176         return (isText(index)) ? (String) getChild(index) : null;
    177     }
    178 
    179     /** Returns the type of the child at the given index. Possible
    180     types are ELEMENT, TEXT, COMMENT, and PROCESSING_INSTRUCTION */
    181 
    182     public int getType(int index) {
    183         return types.charAt(index);
    184     }
    185 
    186     /** Convenience method for indexOf (getNamespace (), name,
    187         startIndex).
    188 
    189     public int indexOf(String name, int startIndex) {
    190         return indexOf(getNamespace(), name, startIndex);
    191     }
    192     */
    193 
    194     /** Performs search for an element with the given namespace and
    195     name, starting at the given start index. A null namespace
    196     matches any namespace, please use Xml.NO_NAMESPACE for no
    197     namespace).  returns -1 if no matching element was found. */
    198 
    199     public int indexOf(String namespace, String name, int startIndex) {
    200 
    201         int len = getChildCount();
    202 
    203         for (int i = startIndex; i < len; i++) {
    204 
    205             Element child = getElement(i);
    206 
    207             if (child != null
    208                     && name.equals(child.getName())
    209                     && (namespace == null || namespace.equals(child.getNamespace())))
    210                 return i;
    211         }
    212         return -1;
    213     }
    214 
    215     public boolean isText(int i) {
    216         int t = getType(i);
    217         return t == TEXT || t == IGNORABLE_WHITESPACE || t == CDSECT;
    218     }
    219 
    220     /** Recursively builds the child elements from the given parser
    221     until an end tag or end document is found.
    222         The end tag is not consumed. */
    223 
    224     public void parse(XmlPullParser parser)
    225             throws IOException, XmlPullParserException {
    226 
    227         boolean leave = false;
    228 
    229         do {
    230             int type = parser.getEventType();
    231 
    232             //         System.out.println(parser.getPositionDescription());
    233 
    234             switch (type) {
    235 
    236                 case XmlPullParser.START_TAG: {
    237                     Element child =
    238                             createElement(
    239                                     parser.getNamespace(),
    240                                     parser.getName());
    241                     //    child.setAttributes (event.getAttributes ());
    242                     addChild(ELEMENT, child);
    243 
    244                     // order is important here since
    245                     // setparent may perform some init code!
    246 
    247                     child.parse(parser);
    248                     break;
    249                 }
    250 
    251                 case XmlPullParser.END_DOCUMENT:
    252                 case XmlPullParser.END_TAG:
    253                     leave = true;
    254                     break;
    255 
    256                 default:
    257                     if (parser.getText() != null)
    258                         addChild(
    259                                 type == XmlPullParser.ENTITY_REF ? TEXT : type,
    260                                 parser.getText());
    261                     else if (type == XmlPullParser.ENTITY_REF
    262                             && parser.getName() != null) {
    263                         addChild(ENTITY_REF, parser.getName());
    264                     }
    265                     parser.nextToken();
    266             }
    267         } while (!leave);
    268     }
    269 
    270     /** Removes the child object at the given index */
    271 
    272     public void removeChild(int idx) {
    273         children.removeElementAt(idx);
    274 
    275         /***  Modification by HHS - start ***/
    276         //      types.deleteCharAt (index);
    277         /***/
    278         int n = types.length() - 1;
    279 
    280         for (int i = idx; i < n; i++)
    281             types.setCharAt(i, types.charAt(i + 1));
    282 
    283         types.setLength(n);
    284 
    285         /***  Modification by HHS - end   ***/
    286     }
    287 
    288     /* returns a valid XML representation of this Element including
    289         attributes and children.
    290     public String toString() {
    291         try {
    292             ByteArrayOutputStream bos =
    293                 new ByteArrayOutputStream();
    294             XmlWriter xw =
    295                 new XmlWriter(new OutputStreamWriter(bos));
    296             write(xw);
    297             xw.close();
    298             return new String(bos.toByteArray());
    299         }
    300         catch (IOException e) {
    301             throw new RuntimeException(e.toString());
    302         }
    303     }
    304     */
    305 
    306     /** Writes this node to the given XmlWriter. For node and document,
    307         this method is identical to writeChildren, except that the
    308         stream is flushed automatically. */
    309 
    310     public void write(XmlSerializer writer) throws IOException {
    311         writeChildren(writer);
    312         writer.flush();
    313     }
    314 
    315     /** Writes the children of this node to the given XmlWriter. */
    316 
    317     public void writeChildren(XmlSerializer writer) throws IOException {
    318         if (children == null)
    319             return;
    320 
    321         int len = children.size();
    322 
    323         for (int i = 0; i < len; i++) {
    324             int type = getType(i);
    325             Object child = children.elementAt(i);
    326             switch (type) {
    327                 case ELEMENT:
    328                     ((Element) child).write(writer);
    329                     break;
    330 
    331                 case TEXT:
    332                     writer.text((String) child);
    333                     break;
    334 
    335                 case IGNORABLE_WHITESPACE:
    336                     writer.ignorableWhitespace((String) child);
    337                     break;
    338 
    339                 case CDSECT:
    340                     writer.cdsect((String) child);
    341                     break;
    342 
    343                 case COMMENT:
    344                     writer.comment((String) child);
    345                     break;
    346 
    347                 case ENTITY_REF:
    348                     writer.entityRef((String) child);
    349                     break;
    350 
    351                 case PROCESSING_INSTRUCTION:
    352                     writer.processingInstruction((String) child);
    353                     break;
    354 
    355                 case DOCDECL:
    356                     writer.docdecl((String) child);
    357                     break;
    358 
    359                 default:
    360                     throw new RuntimeException("Illegal type: " + type);
    361             }
    362         }
    363     }
    364 }
    365