XmlPullParserException "ожидается: START_DOCUMENT {пустые} статьи (позиция:START_TAG"

Я столкнулся с этой ошибкой, когда пытался реализовать простой синтаксический анализатор xml, созданный на учебной странице Android " Разбор XML-данных". Поскольку я являюсь новым разработчиком Android - и чрезвычайно любительским программистом - исключение, которое выдается при попытке реализовать собственную модифицированную версию, не помогает мне направить меня к проблеме.

Вот точное исключение XmlPullParserException:

04-06 19:10:42.772  19279-19279/com.example.reader.app E/Main-Activity﹕ expected: START_DOCUMENT {null}articles (position:START_TAG <articles>@2:11 in java.io.InputStreamReader@41ec5dd8)

Вот мой тестовый XML-файл:

<?xml version="1.0" encoding="utf-8"?>
<articles>
    <article>
        <title>Test Article Number 1</title>
        <description>This is a short description of the article.</description>
        <text>This is some text.</text>
    </article>
    <article>
        <title>Test Article Number 2</title>
        <description>This is a short description of the article.</description>
        <text>This is some text.</text>
    </article>
</articles>

Вот метод onCreate моего файла MainActivity.java, который открывает inputStream и создает экземпляр моего класса ArticleListParser.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));

    // try to access the data in the xml file
    Log.d(TAG, "Starting to execute your code...");
    try {
        InputStream minputStream = getResources().openRawResource(R.raw.test);
        ArticleListParser marticleParser = new ArticleListParser();
        List mlistOfArticles = marticleParser.parse(minputStream);
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
    }
}

А вот и мой класс ArticleListParser.java. Экземпляр этого класса, созданный объектом MainActivity, не проходит мимо метода parse() (т. Е. Не выполняет никаких других методов, которые могут быть вызваны return readArticles(parser); строка в разборе ())...

package com.example.reader.app;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by jasondblack on 4/5/14.
 */

public class ArticleListParser {
    // We don't use namespaces
    private static final String ns = null;

    // log tag
    private static final String TAG = "ArticleListParser";

    public List parse(InputStream in) throws XmlPullParserException, IOException {
        try {
            // get a new xml pull parser
            XmlPullParser parser = Xml.newPullParser();

            // indicate that this xml does not have namespaces
            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);

            // set the input stream of the pull parser
            parser.setInput(in, null);

            // go to the first element
            parser.nextTag();

            // start reading the xml
            return readArticles(parser);
        } finally {
            // no matter what, close the input stream
            in.close();
        }
    }

    private List readArticles(XmlPullParser parser) throws XmlPullParserException, IOException {
        // create List that will be returned
        List articles = new ArrayList();

        parser.require(XmlPullParser.START_DOCUMENT, ns, "articles");
        while(parser.next() != XmlPullParser.END_TAG) {
            if(parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String thisName = parser.getName();

            if(thisName.equals("article")) {
                articles.add(readArticle(parser));
            }
            else {
                skip(parser);
            }
        }
        return articles;
    }

    public static class Article {
        public final String title;
        public final String description;
        public final String text;

        private Article (String thisTitle, String thisDescription, String thisText) {
            this.title = thisTitle;
            this.description = thisDescription;
            this.text = thisText;
        }
    }

    private Article readArticle(XmlPullParser parser) throws XmlPullParserException, IOException {
        // make sure the xml parser is at the beginning of a tag
        parser.require(XmlPullParser.START_TAG, ns, "article");
        String title = null;
        String description = null;
        String text = null;

        // step through xml file until you reach the end tag
        while(parser.getEventType() != XmlPullParser.END_TAG) {
            // if it is the start tag, continue onto next element in parser
            // ??? weird because we have already required a start tag in the first line of this method
            if(parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }

            // get the name of the element in the angled brackets
            String name = parser.getName();

            // check to see if it is one of the titles we want ... if so extract the contents
            if(name.equals("title")) {
                title = readTitle(parser);
            } else if (name.equals("description")) {
                description = readDescription(parser);
            } else if (name.equals("text")) {
                text = readText(parser);
            } else {
                skip(parser);
            }
        }
        // return an Article object
        return new Article (title, description, text);
    }

    // TODO: stopped here don't be confused by duplicate methods implement your own readTitle(), readDescription(), readText(), and extractText() [their "readTExt()" method]

    // Processes title tags in the feed
    private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "title");
        String thisTitle = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, "title");
        return thisTitle;
    }

    // Processes description tags in the feed.
    private String readDescription(XmlPullParser parser) throws IOException, XmlPullParserException {
        parser.require(XmlPullParser.START_TAG, ns, "description");
        String thisDescription = readText(parser);
        parser.require(XmlPullParser.END_TAG, ns, "description");
        return thisDescription;
    }

    // For the tags title and summary, extracts their text values.
    private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
        String result = "";
        // TODO: possible that this will snag on my xml because I don't have type="text" in my xml elements
        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;
            }
        }
    }
}

1 ответ

Решение

Если вы добавите следующее перед вашей строкой parser.require() вызывать readArticles()вы можете видеть, что вы на самом деле не участвуете в мероприятии START_DOCUMENT.

int eventType = parser.getEventType();
Log.i("TAG", "The event type is: " + eventType);

while (eventType != XmlPullParser.START_DOCUMENT) {
    eventType = parser.next();            
    Log.i("TAG", "The event type is: " + eventType);
}

После комментирования parser.nextTag(); линия в parse()эта запись показывает, что вы сейчас находитесь на START_DOCUMENT. Но тогда require() Вызов не выполняется с исключением, упомянутым в вашем вопросе. Похоже, что с помощью ns, который является нулевым, поскольку аргумент пространства имен недопустим. Установка для пространства имен и аргументов имени значения NULL позволяет require() чтобы добиться успеха, но, возможно, не то, что вы хотите.

Другие вопросы по тегам