Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.util;
     18 
     19 
     20 import org.xmlpull.v1.XmlPullParser;
     21 import org.xmlpull.v1.XmlPullParserException;
     22 import org.xmlpull.v1.XmlSerializer;
     23 
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 import java.io.OutputStream;
     27 import java.util.ArrayList;
     28 import java.util.HashMap;
     29 import java.util.Iterator;
     30 import java.util.List;
     31 import java.util.Map;
     32 import java.util.Set;
     33 
     34 import android.util.Xml;
     35 
     36 /** {@hide} */
     37 public class XmlUtils
     38 {
     39 
     40     public static void skipCurrentTag(XmlPullParser parser)
     41             throws XmlPullParserException, IOException {
     42         int outerDepth = parser.getDepth();
     43         int type;
     44         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
     45                && (type != XmlPullParser.END_TAG
     46                        || parser.getDepth() > outerDepth)) {
     47         }
     48     }
     49 
     50     public static final int
     51     convertValueToList(CharSequence value, String[] options, int defaultValue)
     52     {
     53         if (null != value) {
     54             for (int i = 0; i < options.length; i++) {
     55                 if (value.equals(options[i]))
     56                     return i;
     57             }
     58         }
     59 
     60         return defaultValue;
     61     }
     62 
     63     public static final boolean
     64     convertValueToBoolean(CharSequence value, boolean defaultValue)
     65     {
     66         boolean result = false;
     67 
     68         if (null == value)
     69             return defaultValue;
     70 
     71         if (value.equals("1")
     72         ||  value.equals("true")
     73         ||  value.equals("TRUE"))
     74             result = true;
     75 
     76         return result;
     77     }
     78 
     79     public static final int
     80     convertValueToInt(CharSequence charSeq, int defaultValue)
     81     {
     82         if (null == charSeq)
     83             return defaultValue;
     84 
     85         String nm = charSeq.toString();
     86 
     87         // XXX This code is copied from Integer.decode() so we don't
     88         // have to instantiate an Integer!
     89 
     90         int value;
     91         int sign = 1;
     92         int index = 0;
     93         int len = nm.length();
     94         int base = 10;
     95 
     96         if ('-' == nm.charAt(0)) {
     97             sign = -1;
     98             index++;
     99         }
    100 
    101         if ('0' == nm.charAt(index)) {
    102             //  Quick check for a zero by itself
    103             if (index == (len - 1))
    104                 return 0;
    105 
    106             char    c = nm.charAt(index + 1);
    107 
    108             if ('x' == c || 'X' == c) {
    109                 index += 2;
    110                 base = 16;
    111             } else {
    112                 index++;
    113                 base = 8;
    114             }
    115         }
    116         else if ('#' == nm.charAt(index))
    117         {
    118             index++;
    119             base = 16;
    120         }
    121 
    122         return Integer.parseInt(nm.substring(index), base) * sign;
    123     }
    124 
    125     public static final int
    126     convertValueToUnsignedInt(String value, int defaultValue)
    127     {
    128         if (null == value)
    129             return defaultValue;
    130 
    131         return parseUnsignedIntAttribute(value);
    132     }
    133 
    134     public static final int
    135     parseUnsignedIntAttribute(CharSequence charSeq)
    136     {
    137         String  value = charSeq.toString();
    138 
    139         long    bits;
    140         int     index = 0;
    141         int     len = value.length();
    142         int     base = 10;
    143 
    144         if ('0' == value.charAt(index)) {
    145             //  Quick check for zero by itself
    146             if (index == (len - 1))
    147                 return 0;
    148 
    149             char    c = value.charAt(index + 1);
    150 
    151             if ('x' == c || 'X' == c) {     //  check for hex
    152                 index += 2;
    153                 base = 16;
    154             } else {                        //  check for octal
    155                 index++;
    156                 base = 8;
    157             }
    158         } else if ('#' == value.charAt(index)) {
    159             index++;
    160             base = 16;
    161         }
    162 
    163         return (int) Long.parseLong(value.substring(index), base);
    164     }
    165 
    166     /**
    167      * Flatten a Map into an output stream as XML.  The map can later be
    168      * read back with readMapXml().
    169      *
    170      * @param val The map to be flattened.
    171      * @param out Where to write the XML data.
    172      *
    173      * @see #writeMapXml(Map, String, XmlSerializer)
    174      * @see #writeListXml
    175      * @see #writeValueXml
    176      * @see #readMapXml
    177      */
    178     public static final void writeMapXml(Map val, OutputStream out)
    179             throws XmlPullParserException, java.io.IOException {
    180         XmlSerializer serializer = new FastXmlSerializer();
    181         serializer.setOutput(out, "utf-8");
    182         serializer.startDocument(null, true);
    183         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
    184         writeMapXml(val, null, serializer);
    185         serializer.endDocument();
    186     }
    187 
    188     /**
    189      * Flatten a List into an output stream as XML.  The list can later be
    190      * read back with readListXml().
    191      *
    192      * @param val The list to be flattened.
    193      * @param out Where to write the XML data.
    194      *
    195      * @see #writeListXml(List, String, XmlSerializer)
    196      * @see #writeMapXml
    197      * @see #writeValueXml
    198      * @see #readListXml
    199      */
    200     public static final void writeListXml(List val, OutputStream out)
    201     throws XmlPullParserException, java.io.IOException
    202     {
    203         XmlSerializer serializer = Xml.newSerializer();
    204         serializer.setOutput(out, "utf-8");
    205         serializer.startDocument(null, true);
    206         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
    207         writeListXml(val, null, serializer);
    208         serializer.endDocument();
    209     }
    210 
    211     /**
    212      * Flatten a Map into an XmlSerializer.  The map can later be read back
    213      * with readThisMapXml().
    214      *
    215      * @param val The map to be flattened.
    216      * @param name Name attribute to include with this list's tag, or null for
    217      *             none.
    218      * @param out XmlSerializer to write the map into.
    219      *
    220      * @see #writeMapXml(Map, OutputStream)
    221      * @see #writeListXml
    222      * @see #writeValueXml
    223      * @see #readMapXml
    224      */
    225     public static final void writeMapXml(Map val, String name, XmlSerializer out)
    226     throws XmlPullParserException, java.io.IOException
    227     {
    228         if (val == null) {
    229             out.startTag(null, "null");
    230             out.endTag(null, "null");
    231             return;
    232         }
    233 
    234         Set s = val.entrySet();
    235         Iterator i = s.iterator();
    236 
    237         out.startTag(null, "map");
    238         if (name != null) {
    239             out.attribute(null, "name", name);
    240         }
    241 
    242         while (i.hasNext()) {
    243             Map.Entry e = (Map.Entry)i.next();
    244             writeValueXml(e.getValue(), (String)e.getKey(), out);
    245         }
    246 
    247         out.endTag(null, "map");
    248     }
    249 
    250     /**
    251      * Flatten a List into an XmlSerializer.  The list can later be read back
    252      * with readThisListXml().
    253      *
    254      * @param val The list to be flattened.
    255      * @param name Name attribute to include with this list's tag, or null for
    256      *             none.
    257      * @param out XmlSerializer to write the list into.
    258      *
    259      * @see #writeListXml(List, OutputStream)
    260      * @see #writeMapXml
    261      * @see #writeValueXml
    262      * @see #readListXml
    263      */
    264     public static final void writeListXml(List val, String name, XmlSerializer out)
    265     throws XmlPullParserException, java.io.IOException
    266     {
    267         if (val == null) {
    268             out.startTag(null, "null");
    269             out.endTag(null, "null");
    270             return;
    271         }
    272 
    273         out.startTag(null, "list");
    274         if (name != null) {
    275             out.attribute(null, "name", name);
    276         }
    277 
    278         int N = val.size();
    279         int i=0;
    280         while (i < N) {
    281             writeValueXml(val.get(i), null, out);
    282             i++;
    283         }
    284 
    285         out.endTag(null, "list");
    286     }
    287 
    288     /**
    289      * Flatten a byte[] into an XmlSerializer.  The list can later be read back
    290      * with readThisByteArrayXml().
    291      *
    292      * @param val The byte array to be flattened.
    293      * @param name Name attribute to include with this array's tag, or null for
    294      *             none.
    295      * @param out XmlSerializer to write the array into.
    296      *
    297      * @see #writeMapXml
    298      * @see #writeValueXml
    299      */
    300     public static final void writeByteArrayXml(byte[] val, String name,
    301             XmlSerializer out)
    302             throws XmlPullParserException, java.io.IOException {
    303 
    304         if (val == null) {
    305             out.startTag(null, "null");
    306             out.endTag(null, "null");
    307             return;
    308         }
    309 
    310         out.startTag(null, "byte-array");
    311         if (name != null) {
    312             out.attribute(null, "name", name);
    313         }
    314 
    315         final int N = val.length;
    316         out.attribute(null, "num", Integer.toString(N));
    317 
    318         StringBuilder sb = new StringBuilder(val.length*2);
    319         for (int i=0; i<N; i++) {
    320             int b = val[i];
    321             int h = b>>4;
    322             sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
    323             h = b&0xff;
    324             sb.append(h >= 10 ? ('a'+h-10) : ('0'+h));
    325         }
    326 
    327         out.text(sb.toString());
    328 
    329         out.endTag(null, "byte-array");
    330     }
    331 
    332     /**
    333      * Flatten an int[] into an XmlSerializer.  The list can later be read back
    334      * with readThisIntArrayXml().
    335      *
    336      * @param val The int array to be flattened.
    337      * @param name Name attribute to include with this array's tag, or null for
    338      *             none.
    339      * @param out XmlSerializer to write the array into.
    340      *
    341      * @see #writeMapXml
    342      * @see #writeValueXml
    343      * @see #readThisIntArrayXml
    344      */
    345     public static final void writeIntArrayXml(int[] val, String name,
    346             XmlSerializer out)
    347             throws XmlPullParserException, java.io.IOException {
    348 
    349         if (val == null) {
    350             out.startTag(null, "null");
    351             out.endTag(null, "null");
    352             return;
    353         }
    354 
    355         out.startTag(null, "int-array");
    356         if (name != null) {
    357             out.attribute(null, "name", name);
    358         }
    359 
    360         final int N = val.length;
    361         out.attribute(null, "num", Integer.toString(N));
    362 
    363         for (int i=0; i<N; i++) {
    364             out.startTag(null, "item");
    365             out.attribute(null, "value", Integer.toString(val[i]));
    366             out.endTag(null, "item");
    367         }
    368 
    369         out.endTag(null, "int-array");
    370     }
    371 
    372     /**
    373      * Flatten an object's value into an XmlSerializer.  The value can later
    374      * be read back with readThisValueXml().
    375      *
    376      * Currently supported value types are: null, String, Integer, Long,
    377      * Float, Double Boolean, Map, List.
    378      *
    379      * @param v The object to be flattened.
    380      * @param name Name attribute to include with this value's tag, or null
    381      *             for none.
    382      * @param out XmlSerializer to write the object into.
    383      *
    384      * @see #writeMapXml
    385      * @see #writeListXml
    386      * @see #readValueXml
    387      */
    388     public static final void writeValueXml(Object v, String name, XmlSerializer out)
    389     throws XmlPullParserException, java.io.IOException
    390     {
    391         String typeStr;
    392         if (v == null) {
    393             out.startTag(null, "null");
    394             if (name != null) {
    395                 out.attribute(null, "name", name);
    396             }
    397             out.endTag(null, "null");
    398             return;
    399         } else if (v instanceof String) {
    400             out.startTag(null, "string");
    401             if (name != null) {
    402                 out.attribute(null, "name", name);
    403             }
    404             out.text(v.toString());
    405             out.endTag(null, "string");
    406             return;
    407         } else if (v instanceof Integer) {
    408             typeStr = "int";
    409         } else if (v instanceof Long) {
    410             typeStr = "long";
    411         } else if (v instanceof Float) {
    412             typeStr = "float";
    413         } else if (v instanceof Double) {
    414             typeStr = "double";
    415         } else if (v instanceof Boolean) {
    416             typeStr = "boolean";
    417         } else if (v instanceof byte[]) {
    418             writeByteArrayXml((byte[])v, name, out);
    419             return;
    420         } else if (v instanceof int[]) {
    421             writeIntArrayXml((int[])v, name, out);
    422             return;
    423         } else if (v instanceof Map) {
    424             writeMapXml((Map)v, name, out);
    425             return;
    426         } else if (v instanceof List) {
    427             writeListXml((List)v, name, out);
    428             return;
    429         } else if (v instanceof CharSequence) {
    430             // XXX This is to allow us to at least write something if
    431             // we encounter styled text...  but it means we will drop all
    432             // of the styling information. :(
    433             out.startTag(null, "string");
    434             if (name != null) {
    435                 out.attribute(null, "name", name);
    436             }
    437             out.text(v.toString());
    438             out.endTag(null, "string");
    439             return;
    440         } else {
    441             throw new RuntimeException("writeValueXml: unable to write value " + v);
    442         }
    443 
    444         out.startTag(null, typeStr);
    445         if (name != null) {
    446             out.attribute(null, "name", name);
    447         }
    448         out.attribute(null, "value", v.toString());
    449         out.endTag(null, typeStr);
    450     }
    451 
    452     /**
    453      * Read a HashMap from an InputStream containing XML.  The stream can
    454      * previously have been written by writeMapXml().
    455      *
    456      * @param in The InputStream from which to read.
    457      *
    458      * @return HashMap The resulting map.
    459      *
    460      * @see #readListXml
    461      * @see #readValueXml
    462      * @see #readThisMapXml
    463      * #see #writeMapXml
    464      */
    465     public static final HashMap readMapXml(InputStream in)
    466     throws XmlPullParserException, java.io.IOException
    467     {
    468         XmlPullParser   parser = Xml.newPullParser();
    469         parser.setInput(in, null);
    470         return (HashMap)readValueXml(parser, new String[1]);
    471     }
    472 
    473     /**
    474      * Read an ArrayList from an InputStream containing XML.  The stream can
    475      * previously have been written by writeListXml().
    476      *
    477      * @param in The InputStream from which to read.
    478      *
    479      * @return HashMap The resulting list.
    480      *
    481      * @see #readMapXml
    482      * @see #readValueXml
    483      * @see #readThisListXml
    484      * @see #writeListXml
    485      */
    486     public static final ArrayList readListXml(InputStream in)
    487     throws XmlPullParserException, java.io.IOException
    488     {
    489         XmlPullParser   parser = Xml.newPullParser();
    490         parser.setInput(in, null);
    491         return (ArrayList)readValueXml(parser, new String[1]);
    492     }
    493 
    494     /**
    495      * Read a HashMap object from an XmlPullParser.  The XML data could
    496      * previously have been generated by writeMapXml().  The XmlPullParser
    497      * must be positioned <em>after</em> the tag that begins the map.
    498      *
    499      * @param parser The XmlPullParser from which to read the map data.
    500      * @param endTag Name of the tag that will end the map, usually "map".
    501      * @param name An array of one string, used to return the name attribute
    502      *             of the map's tag.
    503      *
    504      * @return HashMap The newly generated map.
    505      *
    506      * @see #readMapXml
    507      */
    508     public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name)
    509     throws XmlPullParserException, java.io.IOException
    510     {
    511         HashMap map = new HashMap();
    512 
    513         int eventType = parser.getEventType();
    514         do {
    515             if (eventType == parser.START_TAG) {
    516                 Object val = readThisValueXml(parser, name);
    517                 if (name[0] != null) {
    518                     //System.out.println("Adding to map: " + name + " -> " + val);
    519                     map.put(name[0], val);
    520                 } else {
    521                     throw new XmlPullParserException(
    522                         "Map value without name attribute: " + parser.getName());
    523                 }
    524             } else if (eventType == parser.END_TAG) {
    525                 if (parser.getName().equals(endTag)) {
    526                     return map;
    527                 }
    528                 throw new XmlPullParserException(
    529                     "Expected " + endTag + " end tag at: " + parser.getName());
    530             }
    531             eventType = parser.next();
    532         } while (eventType != parser.END_DOCUMENT);
    533 
    534         throw new XmlPullParserException(
    535             "Document ended before " + endTag + " end tag");
    536     }
    537 
    538     /**
    539      * Read an ArrayList object from an XmlPullParser.  The XML data could
    540      * previously have been generated by writeListXml().  The XmlPullParser
    541      * must be positioned <em>after</em> the tag that begins the list.
    542      *
    543      * @param parser The XmlPullParser from which to read the list data.
    544      * @param endTag Name of the tag that will end the list, usually "list".
    545      * @param name An array of one string, used to return the name attribute
    546      *             of the list's tag.
    547      *
    548      * @return HashMap The newly generated list.
    549      *
    550      * @see #readListXml
    551      */
    552     public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name)
    553     throws XmlPullParserException, java.io.IOException
    554     {
    555         ArrayList list = new ArrayList();
    556 
    557         int eventType = parser.getEventType();
    558         do {
    559             if (eventType == parser.START_TAG) {
    560                 Object val = readThisValueXml(parser, name);
    561                 list.add(val);
    562                 //System.out.println("Adding to list: " + val);
    563             } else if (eventType == parser.END_TAG) {
    564                 if (parser.getName().equals(endTag)) {
    565                     return list;
    566                 }
    567                 throw new XmlPullParserException(
    568                     "Expected " + endTag + " end tag at: " + parser.getName());
    569             }
    570             eventType = parser.next();
    571         } while (eventType != parser.END_DOCUMENT);
    572 
    573         throw new XmlPullParserException(
    574             "Document ended before " + endTag + " end tag");
    575     }
    576 
    577     /**
    578      * Read an int[] object from an XmlPullParser.  The XML data could
    579      * previously have been generated by writeIntArrayXml().  The XmlPullParser
    580      * must be positioned <em>after</em> the tag that begins the list.
    581      *
    582      * @param parser The XmlPullParser from which to read the list data.
    583      * @param endTag Name of the tag that will end the list, usually "list".
    584      * @param name An array of one string, used to return the name attribute
    585      *             of the list's tag.
    586      *
    587      * @return Returns a newly generated int[].
    588      *
    589      * @see #readListXml
    590      */
    591     public static final int[] readThisIntArrayXml(XmlPullParser parser,
    592             String endTag, String[] name)
    593             throws XmlPullParserException, java.io.IOException {
    594 
    595         int num;
    596         try {
    597             num = Integer.parseInt(parser.getAttributeValue(null, "num"));
    598         } catch (NullPointerException e) {
    599             throw new XmlPullParserException(
    600                     "Need num attribute in byte-array");
    601         } catch (NumberFormatException e) {
    602             throw new XmlPullParserException(
    603                     "Not a number in num attribute in byte-array");
    604         }
    605 
    606         int[] array = new int[num];
    607         int i = 0;
    608 
    609         int eventType = parser.getEventType();
    610         do {
    611             if (eventType == parser.START_TAG) {
    612                 if (parser.getName().equals("item")) {
    613                     try {
    614                         array[i] = Integer.parseInt(
    615                                 parser.getAttributeValue(null, "value"));
    616                     } catch (NullPointerException e) {
    617                         throw new XmlPullParserException(
    618                                 "Need value attribute in item");
    619                     } catch (NumberFormatException e) {
    620                         throw new XmlPullParserException(
    621                                 "Not a number in value attribute in item");
    622                     }
    623                 } else {
    624                     throw new XmlPullParserException(
    625                             "Expected item tag at: " + parser.getName());
    626                 }
    627             } else if (eventType == parser.END_TAG) {
    628                 if (parser.getName().equals(endTag)) {
    629                     return array;
    630                 } else if (parser.getName().equals("item")) {
    631                     i++;
    632                 } else {
    633                     throw new XmlPullParserException(
    634                         "Expected " + endTag + " end tag at: "
    635                         + parser.getName());
    636                 }
    637             }
    638             eventType = parser.next();
    639         } while (eventType != parser.END_DOCUMENT);
    640 
    641         throw new XmlPullParserException(
    642             "Document ended before " + endTag + " end tag");
    643     }
    644 
    645     /**
    646      * Read a flattened object from an XmlPullParser.  The XML data could
    647      * previously have been written with writeMapXml(), writeListXml(), or
    648      * writeValueXml().  The XmlPullParser must be positioned <em>at</em> the
    649      * tag that defines the value.
    650      *
    651      * @param parser The XmlPullParser from which to read the object.
    652      * @param name An array of one string, used to return the name attribute
    653      *             of the value's tag.
    654      *
    655      * @return Object The newly generated value object.
    656      *
    657      * @see #readMapXml
    658      * @see #readListXml
    659      * @see #writeValueXml
    660      */
    661     public static final Object readValueXml(XmlPullParser parser, String[] name)
    662     throws XmlPullParserException, java.io.IOException
    663     {
    664         int eventType = parser.getEventType();
    665         do {
    666             if (eventType == parser.START_TAG) {
    667                 return readThisValueXml(parser, name);
    668             } else if (eventType == parser.END_TAG) {
    669                 throw new XmlPullParserException(
    670                     "Unexpected end tag at: " + parser.getName());
    671             } else if (eventType == parser.TEXT) {
    672                 throw new XmlPullParserException(
    673                     "Unexpected text: " + parser.getText());
    674             }
    675             eventType = parser.next();
    676         } while (eventType != parser.END_DOCUMENT);
    677 
    678         throw new XmlPullParserException(
    679             "Unexpected end of document");
    680     }
    681 
    682     private static final Object readThisValueXml(XmlPullParser parser, String[] name)
    683     throws XmlPullParserException, java.io.IOException
    684     {
    685         final String valueName = parser.getAttributeValue(null, "name");
    686         final String tagName = parser.getName();
    687 
    688         //System.out.println("Reading this value tag: " + tagName + ", name=" + valueName);
    689 
    690         Object res;
    691 
    692         if (tagName.equals("null")) {
    693             res = null;
    694         } else if (tagName.equals("string")) {
    695             String value = "";
    696             int eventType;
    697             while ((eventType = parser.next()) != parser.END_DOCUMENT) {
    698                 if (eventType == parser.END_TAG) {
    699                     if (parser.getName().equals("string")) {
    700                         name[0] = valueName;
    701                         //System.out.println("Returning value for " + valueName + ": " + value);
    702                         return value;
    703                     }
    704                     throw new XmlPullParserException(
    705                         "Unexpected end tag in <string>: " + parser.getName());
    706                 } else if (eventType == parser.TEXT) {
    707                     value += parser.getText();
    708                 } else if (eventType == parser.START_TAG) {
    709                     throw new XmlPullParserException(
    710                         "Unexpected start tag in <string>: " + parser.getName());
    711                 }
    712             }
    713             throw new XmlPullParserException(
    714                 "Unexpected end of document in <string>");
    715         } else if (tagName.equals("int")) {
    716             res = Integer.parseInt(parser.getAttributeValue(null, "value"));
    717         } else if (tagName.equals("long")) {
    718             res = Long.valueOf(parser.getAttributeValue(null, "value"));
    719         } else if (tagName.equals("float")) {
    720             res = new Float(parser.getAttributeValue(null, "value"));
    721         } else if (tagName.equals("double")) {
    722             res = new Double(parser.getAttributeValue(null, "value"));
    723         } else if (tagName.equals("boolean")) {
    724             res = Boolean.valueOf(parser.getAttributeValue(null, "value"));
    725         } else if (tagName.equals("int-array")) {
    726             parser.next();
    727             res = readThisIntArrayXml(parser, "int-array", name);
    728             name[0] = valueName;
    729             //System.out.println("Returning value for " + valueName + ": " + res);
    730             return res;
    731         } else if (tagName.equals("map")) {
    732             parser.next();
    733             res = readThisMapXml(parser, "map", name);
    734             name[0] = valueName;
    735             //System.out.println("Returning value for " + valueName + ": " + res);
    736             return res;
    737         } else if (tagName.equals("list")) {
    738             parser.next();
    739             res = readThisListXml(parser, "list", name);
    740             name[0] = valueName;
    741             //System.out.println("Returning value for " + valueName + ": " + res);
    742             return res;
    743         } else {
    744             throw new XmlPullParserException(
    745                 "Unknown tag: " + tagName);
    746         }
    747 
    748         // Skip through to end tag.
    749         int eventType;
    750         while ((eventType = parser.next()) != parser.END_DOCUMENT) {
    751             if (eventType == parser.END_TAG) {
    752                 if (parser.getName().equals(tagName)) {
    753                     name[0] = valueName;
    754                     //System.out.println("Returning value for " + valueName + ": " + res);
    755                     return res;
    756                 }
    757                 throw new XmlPullParserException(
    758                     "Unexpected end tag in <" + tagName + ">: " + parser.getName());
    759             } else if (eventType == parser.TEXT) {
    760                 throw new XmlPullParserException(
    761                 "Unexpected text in <" + tagName + ">: " + parser.getName());
    762             } else if (eventType == parser.START_TAG) {
    763                 throw new XmlPullParserException(
    764                     "Unexpected start tag in <" + tagName + ">: " + parser.getName());
    765             }
    766         }
    767         throw new XmlPullParserException(
    768             "Unexpected end of document in <" + tagName + ">");
    769     }
    770 
    771     public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException
    772     {
    773         int type;
    774         while ((type=parser.next()) != parser.START_TAG
    775                    && type != parser.END_DOCUMENT) {
    776             ;
    777         }
    778 
    779         if (type != parser.START_TAG) {
    780             throw new XmlPullParserException("No start tag found");
    781         }
    782 
    783         if (!parser.getName().equals(firstElementName)) {
    784             throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
    785                     ", expected " + firstElementName);
    786         }
    787     }
    788 
    789     public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException
    790     {
    791         int type;
    792         while ((type=parser.next()) != parser.START_TAG
    793                    && type != parser.END_DOCUMENT) {
    794             ;
    795         }
    796     }
    797 }
    798