1/*
2 * Copyright (C) 2007 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
17package android.util;
18
19import java.io.IOException;
20import java.io.InputStream;
21import java.io.Reader;
22import java.io.StringReader;
23import java.io.UnsupportedEncodingException;
24import org.apache.harmony.xml.ExpatReader;
25import org.kxml2.io.KXmlParser;
26import org.xml.sax.ContentHandler;
27import org.xml.sax.InputSource;
28import org.xml.sax.SAXException;
29import org.xml.sax.XMLReader;
30import org.xmlpull.v1.XmlPullParser;
31import org.xmlpull.v1.XmlPullParserException;
32import org.xmlpull.v1.XmlPullParserFactory;
33import org.xmlpull.v1.XmlSerializer;
34
35/**
36 * XML utility methods.
37 */
38public class Xml {
39    /** @hide */ public Xml() {}
40
41    /**
42     * {@link org.xmlpull.v1.XmlPullParser} "relaxed" feature name.
43     *
44     * @see <a href="http://xmlpull.org/v1/doc/features.html#relaxed">
45     *  specification</a>
46     */
47    public static String FEATURE_RELAXED = "http://xmlpull.org/v1/doc/features.html#relaxed";
48
49    /**
50     * Parses the given xml string and fires events on the given SAX handler.
51     */
52    public static void parse(String xml, ContentHandler contentHandler)
53            throws SAXException {
54        try {
55            XMLReader reader = new ExpatReader();
56            reader.setContentHandler(contentHandler);
57            reader.parse(new InputSource(new StringReader(xml)));
58        } catch (IOException e) {
59            throw new AssertionError(e);
60        }
61    }
62
63    /**
64     * Parses xml from the given reader and fires events on the given SAX
65     * handler.
66     */
67    public static void parse(Reader in, ContentHandler contentHandler)
68            throws IOException, SAXException {
69        XMLReader reader = new ExpatReader();
70        reader.setContentHandler(contentHandler);
71        reader.parse(new InputSource(in));
72    }
73
74    /**
75     * Parses xml from the given input stream and fires events on the given SAX
76     * handler.
77     */
78    public static void parse(InputStream in, Encoding encoding,
79            ContentHandler contentHandler) throws IOException, SAXException {
80        XMLReader reader = new ExpatReader();
81        reader.setContentHandler(contentHandler);
82        InputSource source = new InputSource(in);
83        source.setEncoding(encoding.expatName);
84        reader.parse(source);
85    }
86
87    /**
88     * Returns a new pull parser with namespace support.
89     */
90    public static XmlPullParser newPullParser() {
91        try {
92            KXmlParser parser = new KXmlParser();
93            parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
94            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
95            return parser;
96        } catch (XmlPullParserException e) {
97            throw new AssertionError();
98        }
99    }
100
101    /**
102     * Creates a new xml serializer.
103     */
104    public static XmlSerializer newSerializer() {
105        try {
106            return XmlSerializerFactory.instance.newSerializer();
107        } catch (XmlPullParserException e) {
108            throw new AssertionError(e);
109        }
110    }
111
112    /** Factory for xml serializers. Initialized on demand. */
113    static class XmlSerializerFactory {
114        static final String TYPE
115                = "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer";
116        static final XmlPullParserFactory instance;
117        static {
118            try {
119                instance = XmlPullParserFactory.newInstance(TYPE, null);
120            } catch (XmlPullParserException e) {
121                throw new AssertionError(e);
122            }
123        }
124    }
125
126    /**
127     * Supported character encodings.
128     */
129    public enum Encoding {
130
131        US_ASCII("US-ASCII"),
132        UTF_8("UTF-8"),
133        UTF_16("UTF-16"),
134        ISO_8859_1("ISO-8859-1");
135
136        final String expatName;
137
138        Encoding(String expatName) {
139            this.expatName = expatName;
140        }
141    }
142
143    /**
144     * Finds an encoding by name. Returns UTF-8 if you pass {@code null}.
145     */
146    public static Encoding findEncodingByName(String encodingName)
147            throws UnsupportedEncodingException {
148        if (encodingName == null) {
149            return Encoding.UTF_8;
150        }
151
152        for (Encoding encoding : Encoding.values()) {
153            if (encoding.expatName.equalsIgnoreCase(encodingName))
154                return encoding;
155        }
156        throw new UnsupportedEncodingException(encodingName);
157    }
158
159    /**
160     * Return an AttributeSet interface for use with the given XmlPullParser.
161     * If the given parser itself implements AttributeSet, that implementation
162     * is simply returned.  Otherwise a wrapper class is
163     * instantiated on top of the XmlPullParser, as a proxy for retrieving its
164     * attributes, and returned to you.
165     *
166     * @param parser The existing parser for which you would like an
167     *               AttributeSet.
168     *
169     * @return An AttributeSet you can use to retrieve the
170     *         attribute values at each of the tags as the parser moves
171     *         through its XML document.
172     *
173     * @see AttributeSet
174     */
175    public static AttributeSet asAttributeSet(XmlPullParser parser) {
176        return (parser instanceof AttributeSet)
177                ? (AttributeSet) parser
178                : new XmlPullAttributes(parser);
179    }
180}
181