문제

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:

  private class GetXMLTask extends AsyncTask<String, Integer, Boolean> {

    private static final int DOWNLOAD_BUFFER_SIZE = 4096;
    int dlCount = 1;

    private Context context;

    int noOfURLs;

    public GetXMLTask(Context context) {
        this.context = context;
    }

    @Override
    protected Boolean doInBackground(String... urls) {
        noOfURLs = urls.length;


        for (String url : urls) {
            downloadFile(url);

        }

        return true;
    }

    private Boolean downloadFile(String urlString) {


        int count = 0;
        String basePath = "http://www.mysite.com/myFolder/";

        URL url;
        InputStream inputStream = null;
        BufferedOutputStream outputStream = null;

        File outFile;
        FileOutputStream fileStream;

        try {
            url = new URL(basePath + urlString);
            URLConnection connection = url.openConnection();
            int lenghtOfFile = connection.getContentLength();

            inputStream = new BufferedInputStream(url.openStream());


            outFile = new File(context.getFilesDir() + "/" + urlString);
            fileStream = new FileOutputStream(outFile);

            outputStream = new BufferedOutputStream(fileStream, DOWNLOAD_BUFFER_SIZE);

            byte data[] = new byte[1024];
            long total = 0;

            while ((count = inputStream.read(data)) != -1) {
                total += count;
                /*publishing progress update on UI thread.
                Invokes onProgressUpdate()*/
                publishProgress((int)((total*100)/lenghtOfFile));

                // writing data to byte array stream
                outputStream.write(data, 0, count);
            }
            outputStream.flush();



        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            FileUtils.close(inputStream);
            FileUtils.close(outputStream);
        }
        dlCount++;
        return true;
    }

    protected void onProgressUpdate(Integer... progress) {
        progressDialog.setProgress(progress[0]);

            progressDialog.setMessage("Downloading File " + dlCount + "/" + noOfURLs);

   }

   @Override
protected void onPostExecute(Boolean result) {

    super.onPostExecute(result);

    logNames();
    progressDialog.dismiss();
}   

}

To invoke it in the activity, I use:

/*Creating and executing background task*/
    GetXMLTask task = new GetXMLTask(getApplicationContext());
    task.execute(new String[] { URL3 });

    progressDialog = new ProgressDialog(this);
    progressDialog.setTitle(PROTOCOL_NAME);
    progressDialog.setMessage("Loading...");
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.setIndeterminate(false);
    progressDialog.setMax(100);
    progressDialog.setCancelable(true);
    progressDialog.show();

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 :)

다른 팁

  1. If you have already InputStream on this line InputStream input = new BufferedInputStream(url.openStream()); then why are you convet into file and get back InputStream from file??
  2. Your file path is wrong, it should be full path like this. FileInputStream in = openFileInput("/mnt/sdcard/../test.xml");
  3. Check your file is sucessfully write or not?

Solution:

  1. No need to save file, you can directly use InputStream for parsing.
  2. Correct you file path..
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top