androidxmlandroid-xmlpullparser

XmlPullParser handling multidimensional repeated elements


Im trying to get a list of the top level elements from my XML (that contains duplicated sub elements)

example XML

<feed>
   <folder name="subfolder1">
       <file name="subfile1" />
       <file name="subfile2" />
       <folder name="subsubfolder1">
            <file name="subsubfile1" />
            <file name="subsubfile2" />
        </folder>
   </folder>
   <folder name="subfolder2">
       <file name="subfile1" />
       <file name="subfile2" />
       <folder name="subsubfolder1">
            <file name="subsubfile1" />
            <file name="subsubfile2" />
        </folder>
   </folder>
   <file name="file1"/>
</feed>

I'm trying to get a list of all names of the top level elements e.g.

.subfolder1
.subfolder2

Here is my FeedReader....

private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
        List<Entry> entries = new ArrayList<Entry>();

        Log.v("ab", "reed feed started");

        parser.require(XmlPullParser.START_TAG, ns, "feed");
        while (parser.next() != XmlPullParser.END_TAG) {

            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String sectionName = parser.getName();

            if(sectionName.equals("folder")) {
                readFolder(parser);
            } 
        }

        return entries;
    }

private void readFolder (XmlPullParser parser) throws XmlPullParserException, IOException  {
        parser.require(XmlPullParser.START_TAG, ns, "folder");
        Log.v("ab", parser.getAttributeValue(null, "name"));
        parser.require(XmlPullParser.END_TAG, ns, "folder");
    }

And here is my LogCat....

09-02 13:40:22.537  31736-31753/? V/ab reed feed started
09-02 13:40:22.537  31736-31753/? V/ab﹕ subfolder1

Can anyone help with why this is stopping after finding the first instance of an folder element?


Solution

  • It looks like a problem with your last parser.require line:

    parser.require(XmlPullParser.END_TAG, ns, "folder");
    

    From the documentation, what you're doing here is checking if these conditions are met, and if not, throwing an exception. So you're currently at the 'folder' start tag that you've just read, and you're checking if you're at the 'folder' end tag. Since you're not at the 'folder' end tag, then parser.require will throw an exception.

    If you remove that line it should just let your while loop keep going until the next folder start tag.

    Edit: here's a full solution

    We need to keep going until the end of the document not just until any END_TAG so I amended your while loop to while (parser.next() != XmlPullParser.END_DOCUMENT), then added some extra code after the readFolder method call. If I understood correctly, you are only after the folders named 'subfolder' and skipping the 'subsubfolder's. So I've included a loop which should skip those. I also removed the parser.require lines as I didn't see the need personally, but this is just one way to do it.

    private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
        List<Entry> entries = new ArrayList<Entry>();
    
        Log.v("ab", "reed feed started");
    
        while (parser.next() != XmlPullParser.END_DOCUMENT) {
    
            if (parser.getEventType() != XmlPullParser.START_TAG) {
                continue;
            }
            String sectionName = parser.getName();
    
            if(sectionName.equals("folder")) {
                readFolder(parser);
    
                //these booleans will be used to help us skip the subfolders
                boolean finishedTopLevelElement = false;
                boolean unwantedSubFolderFound = false;
    
                //this will loop until we are at a "folder" tag and have 
                //confirmed we have finished with the top level folder
                while (!(("folder".equals(parser.getName())) && finishedTopLevelElement)){
                    parser.next();
    
                    //we only care about 'folder' tags, for anything else
                    //we keep looping
                    if ("folder".equals(parser.getName())){
    
                        if (parser.getEventType() == XmlPullParser.START_TAG){
    
                            //if we hit a folder start tag, we're at a sub-folder
                            unwantedSubFolderFound = true;
    
                        } else if (parser.getEventType() == XmlPullParser.END_TAG && !unwantedSubFolderFound){
    
                            //if we hit a 'folder' end tag and we've not got an unwanted subfolder then
                            //we're done, it's the end tag of the top-level folder
                            finishedTopLevelElement = true;
                            unwantedSubFolderFound = false;
    
                        } else {
    
                            //if it's a folder end tag and we HAVE previously found an unwanted sub folder start tag
                            //then we've successfully skipped that sub-folder and can keep looking
                            unwantedSubFolderFound = false;
                        }
                    }
    
    
                }
            } 
        }
    
        return entries;
    }
    
    private void readFolder (XmlPullParser parser) throws XmlPullParserException, IOException  {
        Log.v("ab", parser.getAttributeValue(null, "name"));
    }