blob: 0bd2d4fde4706190b06b18cf37017f99072cd552 [file] [log] [blame]
The Android Open Source Project0eec4642012-04-01 00:00:00 -07001/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- //------100-columns-wide------>|*/
2// for license please see accompanying LICENSE.txt file (available also at http://www.xmlpull.org/)
3
4package org.xmlpull.v1.sax2;
5
6import java.io.InputStream;
7import java.io.IOException;
8import java.io.Reader;
9
10// not J2ME classes -- remove if you want to run in MIDP devices
11import java.net.URL;
12import java.net.MalformedURLException;
13
14
15// not J2ME classes
16import java.io.FileInputStream;
17import java.io.FileNotFoundException;
18
19import org.xml.sax.Attributes;
20import org.xml.sax.DTDHandler;
21import org.xml.sax.ContentHandler;
22import org.xml.sax.EntityResolver;
23import org.xml.sax.ErrorHandler;
24import org.xml.sax.InputSource;
25import org.xml.sax.Locator;
26import org.xml.sax.SAXException;
27import org.xml.sax.SAXParseException;
28import org.xml.sax.SAXNotRecognizedException;
29import org.xml.sax.SAXNotSupportedException;
30import org.xml.sax.XMLReader;
31import org.xml.sax.helpers.DefaultHandler;
32
33import org.xmlpull.v1.XmlPullParser;
34import org.xmlpull.v1.XmlPullParserException;
35import org.xmlpull.v1.XmlPullParserFactory;
36
37/**
38 * SAX2 Driver that pulls events from XmlPullParser
39 * and comverts them into SAX2 callbacks.
40 *
41 * @author <a href="http://www.extreme.indiana.edu/~aslom/">Aleksander Slominski</a>
42 */
43
44public class Driver implements Locator, XMLReader, Attributes
45{
46
47 protected static final String DECLARATION_HANDLER_PROPERTY =
48 "http://xml.org/sax/properties/declaration-handler";
49
50 protected static final String LEXICAL_HANDLER_PROPERTY =
51 "http://xml.org/sax/properties/lexical-handler";
52
53 protected static final String NAMESPACES_FEATURE =
54 "http://xml.org/sax/features/namespaces";
55
56 protected static final String NAMESPACE_PREFIXES_FEATURE =
57 "http://xml.org/sax/features/namespace-prefixes";
58
59 protected static final String VALIDATION_FEATURE =
60 "http://xml.org/sax/features/validation";
61
62 protected static final String APACHE_SCHEMA_VALIDATION_FEATURE =
63 "http://apache.org/xml/features/validation/schema";
64
65 protected static final String APACHE_DYNAMIC_VALIDATION_FEATURE =
66 "http://apache.org/xml/features/validation/dynamic";
67
68 protected ContentHandler contentHandler = new DefaultHandler();
69 protected ErrorHandler errorHandler = new DefaultHandler();;
70
71 protected String systemId;
72
73 protected XmlPullParser pp;
74
75 //private final static boolean DEBUG = false;
76
77 /**
78 */
79 public Driver() throws XmlPullParserException {
80 final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
81 factory.setNamespaceAware(true);
82 pp = factory.newPullParser();
83 }
84
85 public Driver(XmlPullParser pp) throws XmlPullParserException {
86 this.pp = pp;
87 }
88
89 // -- Attributes interface
90
91 public int getLength() { return pp.getAttributeCount(); }
92 public String getURI(int index) { return pp.getAttributeNamespace(index); }
93 public String getLocalName(int index) { return pp.getAttributeName(index); }
94 public String getQName(int index) {
95 final String prefix = pp.getAttributePrefix(index);
96 if(prefix != null) {
97 return prefix+':'+pp.getAttributeName(index);
98 } else {
99 return pp.getAttributeName(index);
100 }
101 }
102 public String getType(int index) { return pp.getAttributeType(index); }
103 public String getValue(int index) { return pp.getAttributeValue(index); }
104
105 public int getIndex(String uri, String localName) {
106 for (int i = 0; i < pp.getAttributeCount(); i++)
107 {
108 if(pp.getAttributeNamespace(i).equals(uri)
109 && pp.getAttributeName(i).equals(localName))
110 {
111 return i;
112 }
113
114 }
115 return -1;
116 }
117
118 public int getIndex(String qName) {
119 for (int i = 0; i < pp.getAttributeCount(); i++)
120 {
121 if(pp.getAttributeName(i).equals(qName))
122 {
123 return i;
124 }
125
126 }
127 return -1;
128 }
129
130 public String getType(String uri, String localName) {
131 for (int i = 0; i < pp.getAttributeCount(); i++)
132 {
133 if(pp.getAttributeNamespace(i).equals(uri)
134 && pp.getAttributeName(i).equals(localName))
135 {
136 return pp.getAttributeType(i);
137 }
138
139 }
140 return null;
141 }
142 public String getType(String qName) {
143 for (int i = 0; i < pp.getAttributeCount(); i++)
144 {
145 if(pp.getAttributeName(i).equals(qName))
146 {
147 return pp.getAttributeType(i);
148 }
149
150 }
151 return null;
152 }
153 public String getValue(String uri, String localName) {
154 return pp.getAttributeValue(uri, localName);
155 }
156 public String getValue(String qName) {
157 return pp.getAttributeValue(null, qName);
158 }
159
160 // -- Locator interface
161
162 public String getPublicId() { return null; }
163 public String getSystemId() { return systemId; }
164 public int getLineNumber() { return pp.getLineNumber(); }
165 public int getColumnNumber() { return pp.getColumnNumber(); }
166
167 // --- XMLReader interface
168
169 public boolean getFeature(String name)
170 throws SAXNotRecognizedException, SAXNotSupportedException
171 {
172 if(NAMESPACES_FEATURE.equals(name)) {
173 return pp.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
174 } else if(NAMESPACE_PREFIXES_FEATURE.equals(name)) {
175 return pp.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES);
176 } else if(VALIDATION_FEATURE.equals(name)) {
177 return pp.getFeature(XmlPullParser.FEATURE_VALIDATION);
178 // } else if(APACHE_SCHEMA_VALIDATION_FEATURE.equals(name)) {
179 // return false; //TODO
180 // } else if(APACHE_DYNAMIC_VALIDATION_FEATURE.equals(name)) {
181 // return false; //TODO
182 } else {
183 return pp.getFeature(name);
184 //throw new SAXNotRecognizedException("unrecognized feature "+name);
185 }
186 }
187
188 public void setFeature (String name, boolean value)
189 throws SAXNotRecognizedException, SAXNotSupportedException
190 {
191 try {
192 if(NAMESPACES_FEATURE.equals(name)) {
193 pp.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, value);
194 } else if(NAMESPACE_PREFIXES_FEATURE.equals(name)) {
195 if(pp.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES) != value) {
196 pp.setFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, value);
197 }
198 } else if(VALIDATION_FEATURE.equals(name)) {
199 pp.setFeature(XmlPullParser.FEATURE_VALIDATION, value);
200 // } else if(APACHE_SCHEMA_VALIDATION_FEATURE.equals(name)) {
201 // // can ignore as validation must be false ...
202 // // if(true == value) {
203 // // throw new SAXNotSupportedException("schema validation is not supported");
204 // // }
205 // } else if(APACHE_DYNAMIC_VALIDATION_FEATURE.equals(name)) {
206 // if(true == value) {
207 // throw new SAXNotSupportedException("dynamic validation is not supported");
208 // }
209 } else {
210 pp.setFeature(name, value);
211 //throw new SAXNotRecognizedException("unrecognized feature "+name);
212 }
213 } catch(XmlPullParserException ex) {
214 // throw new SAXNotSupportedException("problem with setting feature "+name+": "+ex);
215 }
216 }
217
218 public Object getProperty (String name)
219 throws SAXNotRecognizedException, SAXNotSupportedException
220 {
221 if(DECLARATION_HANDLER_PROPERTY.equals(name)) {
222 return null;
223 } else if(LEXICAL_HANDLER_PROPERTY.equals(name)) {
224 return null;
225 } else {
226 return pp.getProperty(name);
227 //throw new SAXNotRecognizedException("not recognized get property "+name);
228 }
229 }
230
231 public void setProperty (String name, Object value)
232 throws SAXNotRecognizedException, SAXNotSupportedException
233 {
234 //
235 if(DECLARATION_HANDLER_PROPERTY.equals(name)) {
236 throw new SAXNotSupportedException("not supported setting property "+name);//+" to "+value);
237 } else if(LEXICAL_HANDLER_PROPERTY.equals(name)) {
238 throw new SAXNotSupportedException("not supported setting property "+name);//+" to "+value);
239 } else {
240 try {
241 pp.setProperty(name, value);
242 } catch(XmlPullParserException ex) {
243 throw new SAXNotSupportedException("not supported set property "+name+": "+ ex);
244 }
245 //throw new SAXNotRecognizedException("not recognized set property "+name);
246 }
247 }
248
249 public void setEntityResolver (EntityResolver resolver) {}
250
251 public EntityResolver getEntityResolver () { return null; }
252
253 public void setDTDHandler (DTDHandler handler) {}
254
255 public DTDHandler getDTDHandler () { return null; }
256
257 public void setContentHandler (ContentHandler handler)
258 {
259 this.contentHandler = handler;
260 }
261
262 public ContentHandler getContentHandler() { return contentHandler; }
263
264 public void setErrorHandler(ErrorHandler handler) {
265 this.errorHandler = handler;
266 }
267
268 public ErrorHandler getErrorHandler() { return errorHandler; }
269
270 public void parse(InputSource source) throws SAXException, IOException
271 {
272
273 systemId = source.getSystemId();
274 contentHandler.setDocumentLocator(this);
275
276 final Reader reader = source.getCharacterStream();
277 try {
278 if (reader == null) {
279 InputStream stream = source.getByteStream();
280 final String encoding = source.getEncoding();
281
282 if (stream == null) {
283 systemId = source.getSystemId();
284 if(systemId == null) {
285 SAXParseException saxException = new SAXParseException(
286 "null source systemId" , this);
287 errorHandler.fatalError(saxException);
288 return;
289 }
290 // NOTE: replace with Connection to run in J2ME environment
291 try {
292 final URL url = new URL(systemId);
293 stream = url.openStream();
294 } catch (MalformedURLException nue) {
295 try {
296 stream = new FileInputStream(systemId);
297 } catch (FileNotFoundException fnfe) {
298 final SAXParseException saxException = new SAXParseException(
299 "could not open file with systemId "+systemId, this, fnfe);
300 errorHandler.fatalError(saxException);
301 return;
302 }
303 }
304 }
305 pp.setInput(stream, encoding);
306 } else {
307 pp.setInput(reader);
308 }
309 } catch (XmlPullParserException ex) {
310 final SAXParseException saxException = new SAXParseException(
311 "parsing initialization error: "+ex, this, ex);
312 //if(DEBUG) ex.printStackTrace();
313 errorHandler.fatalError(saxException);
314 return;
315 }
316
317 // start parsing - move to first start tag
318 try {
319 contentHandler.startDocument();
320 // get first event
321 pp.next();
322 // it should be start tag...
323 if(pp.getEventType() != XmlPullParser.START_TAG) {
324 final SAXParseException saxException = new SAXParseException(
325 "expected start tag not"+pp.getPositionDescription(), this);
326 //throw saxException;
327 errorHandler.fatalError(saxException);
328 return;
329 }
330 } catch (XmlPullParserException ex) {
331 final SAXParseException saxException = new SAXParseException(
332 "parsing initialization error: "+ex, this, ex);
333 //ex.printStackTrace();
334 errorHandler.fatalError(saxException);
335 return;
336 }
337
338 // now real parsing can start!
339
340 parseSubTree(pp);
341
342 // and finished ...
343
344 contentHandler.endDocument();
345 }
346
347 public void parse(String systemId) throws SAXException, IOException {
348 parse(new InputSource(systemId));
349 }
350
351
352 public void parseSubTree(XmlPullParser pp) throws SAXException, IOException {
353 this.pp = pp;
354 final boolean namespaceAware = pp.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
355 try {
356 if(pp.getEventType() != XmlPullParser.START_TAG) {
357 throw new SAXException(
358 "start tag must be read before skiping subtree"+pp.getPositionDescription());
359 }
360 final int[] holderForStartAndLength = new int[2];
361 final StringBuffer rawName = new StringBuffer(16);
362 String prefix = null;
363 String name = null;
364 int level = pp.getDepth() - 1;
365 int type = XmlPullParser.START_TAG;
366
367 LOOP:
368 do {
369 switch(type) {
370 case XmlPullParser.START_TAG:
371 if(namespaceAware) {
372 final int depth = pp.getDepth() - 1;
373 final int countPrev =
374 (level > depth) ? pp.getNamespaceCount(depth) : 0;
375 //int countPrev = pp.getNamespaceCount(pp.getDepth() - 1);
376 final int count = pp.getNamespaceCount(depth + 1);
377 for (int i = countPrev; i < count; i++)
378 {
379 contentHandler.startPrefixMapping(
380 pp.getNamespacePrefix(i),
381 pp.getNamespaceUri(i)
382 );
383 }
384 name = pp.getName();
385 prefix = pp.getPrefix();
386 if(prefix != null) {
387 rawName.setLength(0);
388 rawName.append(prefix);
389 rawName.append(':');
390 rawName.append(name);
391 }
392 startElement(pp.getNamespace(),
393 name,
394 // TODO Fixed this. Was "not equals".
395 prefix == null ? name : rawName.toString());
396 } else {
397 startElement(pp.getNamespace(),
398 pp.getName(),
399 pp.getName());
400 }
401 //++level;
402
403 break;
404 case XmlPullParser.TEXT:
405 final char[] chars = pp.getTextCharacters(holderForStartAndLength);
406 contentHandler.characters(chars,
407 holderForStartAndLength[0], //start
408 holderForStartAndLength[1] //len
409 );
410 break;
411 case XmlPullParser.END_TAG:
412 //--level;
413 if(namespaceAware) {
414 name = pp.getName();
415 prefix = pp.getPrefix();
416 if(prefix != null) {
417 rawName.setLength(0);
418 rawName.append(prefix);
419 rawName.append(':');
420 rawName.append(name);
421 }
422 contentHandler.endElement(pp.getNamespace(),
423 name,
424 prefix != null ? name : rawName.toString()
425 );
426 // when entering show prefixes for all levels!!!!
427 final int depth = pp.getDepth();
428 final int countPrev =
429 (level > depth) ? pp.getNamespaceCount(pp.getDepth()) : 0;
430 int count = pp.getNamespaceCount(pp.getDepth() - 1);
431 // undeclare them in reverse order
432 for (int i = count - 1; i >= countPrev; i--)
433 {
434 contentHandler.endPrefixMapping(
435 pp.getNamespacePrefix(i)
436 );
437 }
438 } else {
439 contentHandler.endElement(pp.getNamespace(),
440 pp.getName(),
441 pp.getName()
442 );
443
444 }
445 break;
446 case XmlPullParser.END_DOCUMENT:
447 break LOOP;
448 }
449 type = pp.next();
450 } while(pp.getDepth() > level);
451 } catch (XmlPullParserException ex) {
452 final SAXParseException saxException = new SAXParseException("parsing error: "+ex, this, ex);
453 ex.printStackTrace();
454 errorHandler.fatalError(saxException);
455 }
456 }
457
458 /**
459 * Calls {@link ContentHandler#startElement(String, String, String, Attributes) startElement}
460 * on the <code>ContentHandler</code> with <code>this</code> driver object as the
461 * {@link Attributes} implementation. In default implementation
462 * {@link Attributes} object is valid only during this method call and may not
463 * be stored. Sub-classes can overwrite this method to cache attributes.
464 */
465 protected void startElement(String namespace, String localName, String qName) throws SAXException {
466 contentHandler.startElement(namespace, localName, qName, this);
467 }
468
469}