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.io.*;
24 import java.util.*;
25 
26 import org.xmlpull.v1.*;
27 
28 /**
29  * In order to create an element, please use the createElement method
30  * instead of invoking the constructor directly. The right place to
31  * add user defined initialization code is the init method. */
32 
33 public class Element extends Node {
34 
35     protected String namespace;
36     protected String name;
37     protected Vector attributes;
38     protected Node parent;
39     protected Vector prefixes;
40 
Element()41     public Element() {
42     }
43 
44     /**
45      * called when all properties are set, but before children
46      * are parsed. Please do not use setParent for initialization
47      * code any longer. */
48 
init()49     public void init() {
50     }
51 
52     /**
53      * removes all children and attributes */
54 
clear()55     public void clear() {
56         attributes = null;
57         children = null;
58     }
59 
60     /**
61      * Forwards creation request to parent if any, otherwise
62      * calls super.createElement. */
63 
createElement( String namespace, String name)64     public Element createElement(
65             String namespace,
66             String name) {
67 
68         return (this.parent == null)
69                 ? super.createElement(namespace, name)
70                 : this.parent.createElement(namespace, name);
71     }
72 
73     /**
74      * Returns the number of attributes of this element. */
75 
getAttributeCount()76     public int getAttributeCount() {
77         return attributes == null ? 0 : attributes.size();
78     }
79 
getAttributeNamespace(int index)80     public String getAttributeNamespace(int index) {
81         return ((String[]) attributes.elementAt(index))[0];
82     }
83 
84     /*    public String getAttributePrefix (int index) {
85             return ((String []) attributes.elementAt (index)) [1];
86         }*/
87 
getAttributeName(int index)88     public String getAttributeName(int index) {
89         return ((String[]) attributes.elementAt(index))[1];
90     }
91 
getAttributeValue(int index)92     public String getAttributeValue(int index) {
93         return ((String[]) attributes.elementAt(index))[2];
94     }
95 
getAttributeValue(String namespace, String name)96     public String getAttributeValue(String namespace, String name) {
97         for (int i = 0; i < getAttributeCount(); i++) {
98             if (name.equals(getAttributeName(i))
99                     && (namespace == null || namespace.equals(getAttributeNamespace(i)))) {
100                 return getAttributeValue(i);
101             }
102         }
103         return null;
104     }
105 
106     /**
107      * Returns the root node, determined by ascending to the
108      * all parents un of the root element. */
109 
getRoot()110     public Node getRoot() {
111 
112         Element current = this;
113 
114         while (current.parent != null) {
115             if (!(current.parent instanceof Element))
116                 return current.parent;
117             current = (Element) current.parent;
118         }
119 
120         return current;
121     }
122 
123     /**
124      * returns the (local) name of the element */
125 
getName()126     public String getName() {
127         return name;
128     }
129 
130     /**
131      * returns the namespace of the element */
132 
getNamespace()133     public String getNamespace() {
134         return namespace;
135     }
136 
137     /**
138      * returns the namespace for the given prefix */
139 
getNamespaceUri(String prefix)140     public String getNamespaceUri(String prefix) {
141         int cnt = getNamespaceCount();
142         for (int i = 0; i < cnt; i++) {
143             if (prefix == getNamespacePrefix(i) ||
144                     (prefix != null && prefix.equals(getNamespacePrefix(i))))
145                 return getNamespaceUri(i);
146         }
147         return parent instanceof Element ? ((Element) parent).getNamespaceUri(prefix) : null;
148     }
149 
150     /**
151      * returns the number of declared namespaces, NOT including
152      * parent elements */
153 
getNamespaceCount()154     public int getNamespaceCount() {
155         return (prefixes == null ? 0 : prefixes.size());
156     }
157 
getNamespacePrefix(int i)158     public String getNamespacePrefix(int i) {
159         return ((String[]) prefixes.elementAt(i))[0];
160     }
161 
getNamespaceUri(int i)162     public String getNamespaceUri(int i) {
163         return ((String[]) prefixes.elementAt(i))[1];
164     }
165 
166     /**
167      * Returns the parent node of this element */
168 
getParent()169     public Node getParent() {
170         return parent;
171     }
172 
173     /*
174      * Returns the parent element if available, null otherwise
175 
176     public Element getParentElement() {
177         return (parent instanceof Element)
178             ? ((Element) parent)
179             : null;
180     }
181     */
182 
183     /**
184      * Builds the child elements from the given Parser. By overwriting
185      * parse, an element can take complete control over parsing its
186      * subtree. */
187 
parse(XmlPullParser parser)188     public void parse(XmlPullParser parser)
189             throws IOException, XmlPullParserException {
190 
191         for (int i = parser.getNamespaceCount(parser.getDepth() - 1); i < parser
192                 .getNamespaceCount(parser.getDepth()); i++) {
193             setPrefix(parser.getNamespacePrefix(i), parser.getNamespaceUri(i));
194         }
195 
196         for (int i = 0; i < parser.getAttributeCount(); i++)
197             setAttribute(parser.getAttributeNamespace(i),
198                     //                          parser.getAttributePrefix (i),
199                     parser.getAttributeName(i),
200                     parser.getAttributeValue(i));
201 
202         //        if (prefixMap == null) throw new RuntimeException ("!!");
203 
204         init();
205 
206         if (parser.isEmptyElementTag())
207             parser.nextToken();
208         else {
209             parser.nextToken();
210             super.parse(parser);
211 
212             if (getChildCount() == 0)
213                 addChild(IGNORABLE_WHITESPACE, "");
214         }
215 
216         parser.require(
217                 XmlPullParser.END_TAG,
218                 getNamespace(),
219                 getName());
220 
221         parser.nextToken();
222     }
223 
224     /**
225      * Sets the given attribute; a value of null removes the attribute */
226 
setAttribute(String namespace, String name, String value)227     public void setAttribute(String namespace, String name, String value) {
228         if (attributes == null)
229             attributes = new Vector();
230 
231         if (namespace == null)
232             namespace = "";
233 
234         for (int i = attributes.size() - 1; i >= 0; i--) {
235             String[] attribut = (String[]) attributes.elementAt(i);
236             if (attribut[0].equals(namespace) &&
237                     attribut[1].equals(name)) {
238 
239                 if (value == null) {
240                     attributes.removeElementAt(i);
241                 }
242                 else {
243                     attribut[2] = value;
244                 }
245                 return;
246             }
247         }
248 
249         attributes.addElement
250                 (new String[] {
251                         namespace, name, value
252                 });
253     }
254 
255     /**
256      * Sets the given prefix; a namespace value of null removess the
257      * prefix */
258 
setPrefix(String prefix, String namespace)259     public void setPrefix(String prefix, String namespace) {
260         if (prefixes == null)
261             prefixes = new Vector();
262         prefixes.addElement(new String[] {
263                 prefix, namespace
264         });
265     }
266 
267     /**
268      * sets the name of the element */
269 
setName(String name)270     public void setName(String name) {
271         this.name = name;
272     }
273 
274     /**
275      * sets the namespace of the element. Please note: For no
276      * namespace, please use Xml.NO_NAMESPACE, null is not a legal
277      * value. Currently, null is converted to Xml.NO_NAMESPACE, but
278      * future versions may throw an exception. */
279 
setNamespace(String namespace)280     public void setNamespace(String namespace) {
281         if (namespace == null)
282             throw new NullPointerException("Use \"\" for empty namespace");
283         this.namespace = namespace;
284     }
285 
286     /**
287      * Sets the Parent of this element. Automatically called from the
288      * add method.  Please use with care, you can simply
289      * create inconsitencies in the document tree structure using
290      * this method!  */
291 
setParent(Node parent)292     protected void setParent(Node parent) {
293         this.parent = parent;
294     }
295 
296     /**
297      * Writes this element and all children to the given XmlWriter. */
298 
write(XmlSerializer writer)299     public void write(XmlSerializer writer)
300             throws IOException {
301 
302         if (prefixes != null) {
303             for (int i = 0; i < prefixes.size(); i++) {
304                 writer.setPrefix(getNamespacePrefix(i), getNamespaceUri(i));
305             }
306         }
307 
308         writer.startTag(
309                 getNamespace(),
310                 getName());
311 
312         int len = getAttributeCount();
313 
314         for (int i = 0; i < len; i++) {
315             writer.attribute(
316                     getAttributeNamespace(i),
317                     getAttributeName(i),
318                     getAttributeValue(i));
319         }
320 
321         writeChildren(writer);
322 
323         writer.endTag(getNamespace(), getName());
324     }
325 }
326