Parsing a read-only XML file with XmlPullParser
Video: Parsing a read-only XML file with XmlPullParserI've previously described how to create and read files in both internal and external storage. You can also package read-only files as a part of your application as a resource, in the same ways you might package up a layout or a binary file. I'll describe how to do that and also how to parse XML using a class called the XML Pull Parser that's included with the Android SDK. In this version of the application, I've changed my layout so that it contains a ListView control.
- Retrieving and displaying data
- Filtering and sorting data
Viewers: in countries Watching now:
Take your Android programming skills to the next level with the Android built-in framework that enables local data management in text files and SQLite-based relational databases. This course shows you how to create datacentric apps for Android devices, using SQLite, Java, and the built-in android.database packages. Author David Gassner describes how to define shared preferences, work with JSON and XML files in internal and external data stores, and create new local SQLite databases.
- Exploring local data storage options
- Creating an Android virtual device
- Starting a new project
- Defining preferences with Java and activities
- Creating and reading JSON and XML data files
- Creating a new SQLite database
- Inserting and retrieving data in the database
Parsing a read-only XML file with XmlPullParser
I've previously described how to create and read files in both internal and external storage. You can also package read-only files as a part of your application as a resource, in the same ways you might package up a layout or a binary file. I'll describe how to do that and also how to parse XML using a class called the XML Pull Parser that's included with the Android SDK. In this version of the application, I've changed my layout so that it contains a ListView control.
A list view is designed to display a list of data, and I'm going to be retrieving the data from an XML file that's packaged with the application and displaying its data in this list. The layout also has a TextView control that I'll be able to use to display any type of information I want to the user. The MainActivity class has been changed so that it extends the ListActivity, and I'll be able to use this class and the layout to easily display a list of data. First, I'm going to describe how to package up an XML file as part of your application as an application resource.
I'll work with an XML file that's delivered in the exercise files. I'll move Eclipse over to the right and go to my exercise files, to the Assets folder, and from there to Data. You can open this tours.xml file in any text editor. I'm going to copy it into my project first and then show you its contents. I'll copy it to the clipboard. Then I'll go back to Eclipse and I'll go to my Resources folder. You can place this XML file anywhere you want.
I'm going to follow a common standard and place it in a subfolder called raw. I'll create a new folder in the res folder and I'll name it raw. I'll paste the file into place. Then I'll open up the raw folder, and I'll open the XML file using the text editor. I'll right-click and choose Open With > Text Editor. Here's the structure of the XML file. It has a root element named tours and child elements named tour.
Within each tour element, there's a tourID, a tourTitle, a packageTitle, and so on. I won't be using all of the data elements, but I will be using the tourTitle, the description, the price, and the image. There are a couple of different ways of parsing XML. I'm going to start with something called the XML Pull Parser, a class that's packaged with the Android SDK. It's not the easiest parser to code with, but it's very high performance and you don't have to go get any other parsers to use it.
The code is a little bit complex, so I've already created a class that we can use. Once again, I'll move Eclipse over and I'll go back to my exercise files. I'll go back to the Assets folder, and this time I'll go to the Code folder. I'm going to be using two of these classes. First, I'm going to use the Tour class. The Tour class is a Java bin class with a little bit of extra code. It's designed to represent a single instance of the tour entity. I'll select and copy the Tour class into the clipboard, then return to Eclipse.
I'll go to my source folder, and I'll go to this new empty package com.exploreca.tourfinder.model, and I'll paste the file into place. The Tour class has private fields for each of the values I want to store: the tour ID, the title, the description, the price, and the image. There are three strings and two numeric values. Then there are public getters and setters for each of the fields, and down at the bottom, very importantly, there's a toString method.
The toString method uses a number format object. That's a class that's a part of the standard Java Development Kit, and it returns the title and the formatted price as a single string. I'll be using this toString method to display the data in the list. I'll go back to my exercise files and I'll take this file, ToursPullParser. I'll copy that to the clipboard and go back to Eclipse, and I'll paste this into my MainPackage, the tour finder package.
Here's the code that I'm going to be using to parse the XML file. First, I've created five constants, each matching a data element that's a part of the XML file. I'll use these constants to identify what I'm looking for. Then there's a little bit of code that's declaring an ArrayList where each item in the ArrayList is an instance of that new tour class. There's a method named parseXML. The parseXML method first creates an instance of the pullParser object.
That code is right here. The name of the parser is xpp. There are a few other bits of code above it, but the important part is that we're creating an instance of the parser and then we'll be using it to read the contents of the XML file. Then there's something called an InputStream. The important part here is the call to the openRawResource method. It's opening the tours.xml file as an application resource, using R.raw--remember, that's the name of the folder where we placed the XML file--and then the beginning of the tours.xml file name.
You don't include the file extension; the .xml is assumed. The nature of the pull parser is that it's a streaming parser. A streaming parser streams through the contents of the XML file and then fires events whenever it reaches certain markers. The XML Pull Parser knows to look for five different events. It dispatches an event when it gets to the beginning of the document and to the end of the document, whenever it hits a start tag and whenever it hits an end tag, and whenever it hits a text note.
Each time an event occurs, it's up to you as the developer to find out what the event was and do something with it. So in this code, I'm starting by calling the first event, by calling a method called getEventType. That triggers the first read of the file. The first event that happens is the start document event, and I don't care about that. But I do care about getting to the end of the document. So my while loop is going to continue processing until I get to that event. So I'm saying, while (eventType != XmlPullParser.END DOCUMENT) due to following.
Then there's a little bit of processing, and at the end of the loop, I'm calling xpp.next. That means keep reading the XML file until you get to the next event. Streaming parsers like XML Pull Parser are very high performance. They're very fast, but they do cause a little bit of fragmented programming, because it's up to you as the developer to remember where you are and figure out what you need to do. Here's the logic that I've used. I've said that if I've just gotten to a START TAG then call a method called handleStartTag and pass in the tag name.
That method is down here. Within handleStartTag, I say, if the name is tour, then create a new instance of the Tour class and save it to this variable, which is declared as a field of the class. Then add that to our variable to the tours package. If the start tag isn't tour, then instead, save the current tag. I'll get to that later. Going back to the parse XML method. If I hit an END_TAG, then I set currentTag to null, meaning I'm not reading a tag right now.
Finally, and this is the critical part, if I get a text event then I want to handle that text, and I'll go to this method, handleText. I have conditional code that's looking for the TOUR_ID, the TOUR_TITLE, the TOUR_DESC, and so on. For the numeric values, I'm parsing them using parseInt and parseDouble. For the string values, I'm just taking the value. And I'm adding the text to the appropriate property of the currentTour object. So this method will be called five times for each tour.
Going back again, if I hit some text that's not part of a tag I care about, the currentTag will be null and I'll ignore it. By the time this loop is finished, I will have read through the entire XML file and I'll have an ArrayList containing tour objects, and the return statement returns those object as a list. So now, in order to use this class, I'll go back to my MainActivity. I'll go the onCreate method. This is where I'll parse the data and display it to the user.
I'll click into the onCreate method. Within this method, I'll create an instance of my ToursPullParser class. I'll declare that as the data type and I'll name it parser, and I'll instantiate it using the constructor method. Next, I'll create a list. I'll make sure to include the import statement. I'll say that the data type is Tour. I'll name this variable tours. I'll get its value by calling parser.parseXML.
I'll pass in the context, which will be this. The context will be used in the parser to identify the resource that points to the XML file. Now I have some data and I'm ready to display it. I'll use an ArrayAdapter. The ArrayAdapter class takes a collection and binds it to a list. The data type will be Tour, my Tour class. I'll name this adapter, and I'll instantiate it using its constructor method, with new ArrayAdapter.
For the context, I'll pass in this. For the resource which points to the layout I'll be using for each item in the list, I'll use android.R.layout.simple_list_item_1. This is a built-in renderer for a single list item. It knows how to display simple text, and I'll describe in a moment where the text will come from. Finally, I'll pass in the tours object. So I'm using a version of the ArrayAdapter constructor which receives the context, the resource identifier for the list item renderer, and the data which should be displayed.
Then, after all that, I'll call setListAdapter and I'll pass in the adapter object. So I've retrieved the XML content and I'm ready to display it on the screen. When the data is displayed, it's going to use that toString method of the tour class that I described. If you want to change the way the tour is displayed and decide you want to display other fields, this is the method you should modify. I'll run the application in the emulator. As the application comes to the screen, its onCreate method is executed.
It opens the XML file and parses it and displays the contents. You can scroll up and down the list and see all the data that was in the XML file displayed here. I'll show you in a later video a way to improve the display of this data using a richer presentation. So, that's the XML Pull Parser, a parser that's included with the Android SDK and is very fast, and while it takes a little bit of fragmented programming, once you've mastered it, you should be able to work with any XML file that makes sense for your application.
There are currently no FAQs about Android SDK: Local Data Storage.