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 
17 package android.util;
18 
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.Reader;
22 import java.io.StringReader;
23 import java.io.UnsupportedEncodingException;
24 import org.apache.harmony.xml.ExpatReader;
25 import org.kxml2.io.KXmlParser;
26 import org.xml.sax.ContentHandler;
27 import org.xml.sax.InputSource;
28 import org.xml.sax.SAXException;
29 import org.xml.sax.XMLReader;
30 import org.xmlpull.v1.XmlPullParser;
31 import org.xmlpull.v1.XmlPullParserException;
32 import org.xmlpull.v1.XmlPullParserFactory;
33 import org.xmlpull.v1.XmlSerializer;
34 
35 /**
36  * XML utility methods.
37  */
38 public class Xml {
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      */
parse(String xml, ContentHandler contentHandler)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      */
parse(Reader in, ContentHandler contentHandler)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      */
parse(InputStream in, Encoding encoding, ContentHandler contentHandler)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      */
newPullParser()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      */
newSerializer()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 
Encoding(String expatName)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      */
findEncodingByName(String encodingName)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      */
asAttributeSet(XmlPullParser parser)175     public static AttributeSet asAttributeSet(XmlPullParser parser) {
176         return (parser instanceof AttributeSet)
177                 ? (AttributeSet) parser
178                 : new XmlPullAttributes(parser);
179     }
180 }
181