I'm having trouble parsing an xml file from internal storage. I have a xml file that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<entries>
<entry>
<name>Name 1</name>
<submenu>Submenu 1</submenu>
<color>Color 1</color>
</entry>
<entry>
<name>Name 2</name>
<submenu>Submenu 2</submenu>
<color>Color 2</color>
</entry>
<entry>
<name>Name 3</name>
<submenu>Submenu 3</submenu>
<color>Color 3</color>
</entry>
</entries>
I have a copy of this xml file in my assets folder called test.xml and I have a copy on my webserver called test.xml. When I try to parse the file from my assets folder, everything works great. When I download the file from the internet and try to parse it from internal storage, it doesn't work. Here is my activity code which has all the functionality in it:
package com.example.testdl;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
ProgressDialog mProgressDialog;
Button button;
int x = 0;
String URL = "http://www.classicknightstudio.com/marthasvillans/test.xml";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Test1");
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.myButton);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (x == 0) {
// Execute DownloadFile AsyncTask
new DownloadFile().execute(URL);
x = x + 1;
} else {
logNames();
}
}
});
}
// DownloadFile AsyncTask
private class DownloadFile extends AsyncTask<String, Integer, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setTitle("Downloads");
mProgressDialog.setMessage("Downloading, Please Wait!");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.show();
}
@Override
protected String doInBackground(String... sUrl) {
try {
URL url = new URL(sUrl[0]);
URLConnection connection = url.openConnection();
connection.connect();
// Detect the file length
int fileLength = connection.getContentLength();
// Download the file
InputStream input = new BufferedInputStream(url.openStream());
FileOutputStream output = openFileOutput("test.xml",
Context.MODE_PRIVATE);
output.write("test.xml".getBytes());
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// Publish the progress
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
// Close connection
output.flush();
output.close();
input.close();
} catch (Exception e) {
// Error Log
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
mProgressDialog.setProgress(progress[0]);
}
}
private class XmlParser {
private final String ns = null;
public List parse(InputStream in) throws XmlPullParserException,
IOException {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES,
false);
parser.setInput(in, null);
parser.nextTag();
return readFeed(parser);
} finally {
in.close();
}
}
private List<Entry> readFeed(XmlPullParser parser)
throws XmlPullParserException, IOException {
List<Entry> entries = new ArrayList<Entry>();
parser.require(XmlPullParser.START_TAG, ns, "entries");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (name.equals("entry")) {
entries.add(readEntry(parser));
} else {
skip(parser);
}
}
return entries;
}
private Entry readEntry(XmlPullParser parser)
throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, "entry");
String titleName = null;
String submenu = null;
String color = null;
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (name.equals("name")) {
titleName = readTitleName(parser);
} else if (name.equals("submenu")) {
submenu = readSubmenu(parser);
} else if (name.equals("color")) {
color = readColor(parser);
} else {
skip(parser);
}
}
return new Entry(titleName, submenu, color);
}
private String readTitleName(XmlPullParser parser) throws IOException,
XmlPullParserException {
parser.require(XmlPullParser.START_TAG, ns, "name");
String titleName = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "name");
return titleName;
}
private String readSubmenu(XmlPullParser parser) throws IOException,
XmlPullParserException {
parser.require(XmlPullParser.START_TAG, ns, "submenu");
String submenu = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "submenu");
return submenu;
}
private String readColor(XmlPullParser parser) throws IOException,
XmlPullParserException {
parser.require(XmlPullParser.START_TAG, ns, "color");
String color = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "color");
return color;
}
private String readText(XmlPullParser parser) throws IOException,
XmlPullParserException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.nextTag();
}
return result;
}
private void skip(XmlPullParser parser) throws XmlPullParserException,
IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
}
public static class Entry {
public final String titleName;
public final String submenu;
public final String color;
public Entry(String titleName, String submenu, String color) {
this.titleName = titleName;
this.submenu = submenu;
this.color = color;
}
public String getTitleName() {
return titleName;
}
public String getSubmenu() {
return submenu;
}
public String getColor() {
return color;
}
}
protected void logNames() {
File file = getBaseContext().getFileStreamPath("test.xml");
if (file.exists()) {
Log.d("TEST1", "file exists");
try {
// InputStream in = getApplicationContext().getAssets().open("test.xml");
FileInputStream in = openFileInput("test.xml");
XmlParser myParse = new XmlParser();
try {
@SuppressWarnings("unchecked")
ArrayList<Entry> TheParse = (ArrayList<Entry>) myParse
.parse(in);
for (int i = 0; i < TheParse.size(); i = i + 1) {
Log.d("TEST1", "" + TheParse.get(i).getTitleName());
}
} catch (XmlPullParserException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
The activity is set up that when you press the button the first time, it downloads the file from the web. Then when you press the button a second time, it logs the name of each entry in the logcat.
In the logNames method, the code that i posted is using the FileInputStream in = openFileInput("test.xml");
Commented out above it is a stream that gets the file from the assets folder. I understand that to read the file from the assets folder, I don't need all the downloading stuff. So, if i comment out the:
FileInputStream in = openFileInput("test.xml");
in the logNames method and uncomment the:
InputStream in = getApplicationContext().getAssets().open("test.xml");
Then everything works fine and the names are displayed in the log cat. However, if i use the code as shown (attempting to download the xml from the web, save it to external storage, and then parse it), I get the following error:
08-12 04:38:56.899: W/System.err(17622): org.xmlpull.v1.XmlPullParserException: Unexpected token (position:TEXT test.xml@1:9 in java.io.InputStreamReader@4278f850)
08-12 04:38:56.909: W/System.err(17622): at org.kxml2.io.KXmlParser.next(KXmlParser.java:426)
08-12 04:38:56.909: W/System.err(17622): at org.kxml2.io.KXmlParser.next(KXmlParser.java:310)
08-12 04:38:56.909: W/System.err(17622): at org.kxml2.io.KXmlParser.nextTag(KXmlParser.java:2029)
08-12 04:38:56.909: W/System.err(17622): at com.example.testdl.MainActivity$XmlParser.parse(MainActivity.java:143)
08-12 04:38:56.909: W/System.err(17622): at com.example.testdl.MainActivity.logNames(MainActivity.java:292)
08-12 04:38:56.909: W/System.err(17622): at com.example.testdl.MainActivity$1.onClick(MainActivity.java:59)
08-12 04:38:56.909: W/System.err(17622): at android.view.View.performClick(View.java:4203)
08-12 04:38:56.909: W/System.err(17622): at android.view.View$PerformClick.run(View.java:17189)
08-12 04:38:56.909: W/System.err(17622): at android.os.Handler.handleCallback(Handler.java:615)
08-12 04:38:56.909: W/System.err(17622): at android.os.Handler.dispatchMessage(Handler.java:92)
08-12 04:38:56.909: W/System.err(17622): at android.os.Looper.loop(Looper.java:137)
08-12 04:38:56.909: W/System.err(17622): at android.app.ActivityThread.main(ActivityThread.java:4950)
08-12 04:38:56.909: W/System.err(17622): at java.lang.reflect.Method.invokeNative(Native Method)
08-12 04:38:56.909: W/System.err(17622): at java.lang.reflect.Method.invoke(Method.java:511)
08-12 04:38:56.909: W/System.err(17622): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
08-12 04:38:56.909: W/System.err(17622): at c com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
08-12 04:38:56.919: W/System.err(17622): at dalvik.system.NativeStart.main(Native Method)
08-12 04:38:58.210: D/TEST1(17622): file exists
08-12 04:38:58.210: W/System.err(17622): org.xmlpull.v1.XmlPullParserException: Unexpected token (position:TEXT test.xml@1:9 in java.io.InputStreamReader@4279b7c8)
08-12 04:38:58.210: W/System.err(17622): at org.kxml2.io.KXmlParser.next(KXmlParser.java:426)
08-12 04:38:58.210: W/System.err(17622): at org.kxml2.io.KXmlParser.next(KXmlParser.java:310)
08-12 04:38:58.210: W/System.err(17622): at org.kxml2.io.KXmlParser.nextTag(KXmlParser.java:2029)
08-12 04:38:58.210: W/System.err(17622): at com.example.testdl.MainActivity$XmlParser.parse(MainActivity.java:143)
08-12 04:38:58.220: W/System.err(17622): at com.example.testdl.MainActivity.logNames(MainActivity.java:292)
08-12 04:38:58.220: W/System.err(17622): at com.example.testdl.MainActivity$1.onClick(MainActivity.java:59)
08-12 04:38:58.220: W/System.err(17622): at android.view.View.performClick(View.java:4203)
08-12 04:38:58.220: W/System.err(17622): at and android.view.View$PerformClick.run(View.java:17189)
08-12 04:38:58.220: W/System.err(17622): at android.os.Handler.handleCallback(Handler.java:615)
08-12 04:38:58.220: W/System.err(17622): at android.os.Handler.dispatchMessage(Handler.java:92)
08-12 04:38:58.220: W/System.err(17622): at android.os.Looper.loop(Looper.java:137)
08-12 04:38:58.220: W/System.err(17622): at android.app.ActivityThread.main(ActivityThread.java:4950)
08-12 04:38:58.220: W/System.err(17622): at java.lang.reflect.Method.invokeNative(Native Method)
08-12 04:38:58.220: W/System.err(17622): at java.lang.reflect.Method.invoke(Method.java:511)
08-12 04:38:58.220: W/System.err(17622): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
08-12 04:38:58.220: W/System.err(17622): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
08-12 04:38:58.220: W/System.err(17622): at dalvik.system.NativeStart.main(Native Method)
the check for if the file exists in the logNames method passes and it looks like the file is indeed saved to internal storage. Any help is appreciated.
solved. It must have been something wrong in my downloader class. After rewriting it, I have it working, ... for multiple files too ! Here's the new downloader:
To invoke it in the activity, I use:
URL3 is a string I set. You could add however many strings you wanted there into that array. logNames() is a method to be called after finishing downloaded. Could be any method there. Hope this helps someone :)