• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
addChild(int index, int type, Object child)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 
addChild(int type, Object child)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 
createElement(String namespace, String name)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 
getChild(int index)97     public Object getChild(int index) {
98         return children.elementAt(index);
99     }
100 
101     /** Returns the number of child objects */
102 
getChildCount()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 
getElement(int index)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 
getElement(String namespace, String name)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 
getText(int index)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 
getType(int index)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 
indexOf(String namespace, String name, int startIndex)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 
isText(int i)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 
parse(XmlPullParser parser)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 
removeChild(int idx)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 
write(XmlSerializer writer)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 
writeChildren(XmlSerializer writer)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