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