XMLPullParser checking for specific Child node - android

I have a XML like this:
<node_a>
<node_b>
<required/>
<random_node1/>
</node_b>
<node_c>
<required/>
</node_c>
<node_d>
<random_node2/>
</node_d>
</node_a>
and trying to parse it using XMLPullParser
I want to iterate through the XML and add all the node names that have the child . In this example i my result list should have node_b and node_c.
The problem i face is if i do a parser.next() then the pointer moves ahead and it is impossible for me get back and iterate through them again. There is no api to check for all child nodes.
What will be the best approach to go with.

Something like this?
XmlPullParser paser = Xml.newPullParser();
... other init that you might need ...
parser.next(); // get first token
// In general, you'll need to add error checking such as this:
if (parser.getEventType() != XmlPullParser.START_TAG)
...error...
String parentName = parser.getName(); // this will be "node_a"
parser.next(); // done with first token; fetch next
while (parser.getEventType() == XmlPullParser.START_TAG)
{
String childName = parser.getName(); // will be "node_b" first time through loop
// get nested attributes - e.g. "required"
parser.next();
while (parser.getEventType() == XmlPullParser.START_TAG)
{
String nestedAttribute = parser.getName();
... do something with nestedAttribute ...
parser.next();
}
if (parser.getEventType() != XmlPullParser.END_TAG)
...error...
parser.next(); // consume END_TAG for nested attributes
}
if (parser.getEventType() != XmlPullParser.END_TAG)
...error...
// make sure we're at end of file
parser.next(); // consume END_TAG for node_a
if (parser.getEventType() != XmlPullPaarser.END_DOCUMENT)
...error...

Related

Parsing complex XML using XmlPullParser

I'm facing the problem of parsing xml using XmlPullParser. Everithing works fine except this problmatic part:
<Device>
<Description>
Tracker, type CONNECT
<Firmware>0240</Firmware>
</Description>
<Settings>
...
</Settings>
<Variables>
...
</Variables>
</Device>
I need to parse both DESCRIPTION and FIRMWARE. But I can't read properly that description text because of such tags weird structure.
What I've tried (following this guide):
private Device parseDevice(XmlPullParser parser) throws XmlPullParserException, IOException {
Device device = new Device();
parser.require(XmlPullParser.START_TAG, ns, DEVICE);
//device.setDescription(readDeviceDescription(parser)); <---tried to parse from here
device.setName(readDeviceName(parser));
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// Starts by looking for the entry tag
switch (name) {
case DESCRIPTION:
// device.setDescription(readDeviceDescription(parser)); <---and from here
device.setFirmware(readDescription(parser, device)); //<-- and inside this method
break;
case VARIABLES:
device.setGroups(readGroups(parser));
break;
default:
skip(parser);
break;
}
}
return device;
}
readDeviceDesscription() method (maybe problem lies here):
private String readDeviceDescription(XmlPullParser parser) throws XmlPullParserException, IOException {
String result = "";
if (parser.next() == XmlPullParser.TEXT) {
result = parser.getText();
parser.next();
}
return result;
}
But any my attempt was ending with returning null either to Firmware or to Description.
Please help. Appreciate any hint.
You should do:
private String readDeviceDescription(XmlPullParser parser) throws XmlPullParserException, IOException {
String result = parser.getText();
return result;
}
Since you are already positioned at Description start_tag getText call will return the text inside Description tag.
To get the Firmware tag text you should do:
if(parser.getEventType() == XmlPullParser.START_TAG && parser.getName().compareTo("Firmware")==0)
String firmwareText = parser.getText();
Also take a look at this its a good example of a clean XmlPullParser implementation.
Hope this helps.

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?
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"));
}

android parsing xml content from String

Following is the xml content which i get after decrypting an encrypted value
<card order_no="1" id="cmpe0rhm3ym5ha8wlqp4jt7u" place="HOME">33</card>
Now i have the above content in a String called message.
Now i want parse the values such as id and place using the main tag "card" and the number
"33" also to be parsed.
Following is what i have been tried
InputStream inputStream = new ByteArrayInputStream(message.getBytes());
XmlPullParser cardParser = Xml.newPullParser();
cardParser.setInput(inputStream, null);
Map<String, String> attrs = XMLParsers.getAttributes(cardParser);
String cardTag = cardParser.getName();
if (cardTag.equalsIgnoreCase("card"))
{
CardTag card = new CardTag();
card.setId(attrs.get("id"));
card.setPlace(attrs.get("place"));
card.setCardNumericValue(cardParser.getText());
return card;
}
I have stored the string in an InputStream and again tried to parse it, but i am getting a null pointer exception
Value of String cardTag seems to be null when i printed it.
NullPointerException rises at if condition "if (cardTag.equalsIgnoreCase("card"))"
How to do this
The documentation says
For START_TAG or END_TAG events, the (local) name of the current
element is returned when namespaces are enabled. When namespace
processing is disabled, the raw name is returned. For ENTITY_REF
events, the entity name is returned. If the current event is not
START_TAG, END_TAG, or ENTITY_REF, null is returned.
So, I believe you current event is START_DOCUMENT and you need call cardParser.next() to get next start tag event. Please take a look on example
public class SimpleXmlPullApp{
public static void main (String args[])
throws XmlPullParserException, IOException
{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput( new StringReader ( "<foo>Hello World!</foo>" ) );
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_DOCUMENT) {
System.out.println("Start document");
} else if(eventType == XmlPullParser.START_TAG) {
System.out.println("Start tag "+xpp.getName());
} else if(eventType == XmlPullParser.END_TAG) {
System.out.println("End tag "+xpp.getName());
} else if(eventType == XmlPullParser.TEXT) {
System.out.println("Text "+xpp.getText());
}
eventType = xpp.next();
}
System.out.println("End document");
}
}
output
Start document
Start tag foo
Text Hello World!
End tag foo
End document

Parse 2 Levels of XML android

Please correct the table if it is wrong, ,I'm not entirely sure what to title this.
I am trying to parse my XML in android and i have code that should work, but the problem is there are multiple levels of tags i need to get into.
Here is an example of my XML:
<dsxout>
<uselessTag>unnecasary info</uselessTag>
<results>
<listing>
<title>I'm a Title</title>
<description>very amusing description</description>
</listing>
<listing>
...
</listing>
</results>
</dsxout>
Here is where my parsing gets stuck:
private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
List entries = new ArrayList();
Toast.makeText(getBaseContext(), "readFeed", Toast.LENGTH_SHORT).show();
parser.require(XmlPullParser.START_TAG, ns, "dsxout");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
The line below just spits out the tag uselessTag and results
Toast.makeText(getBaseContext(), name, Toast.LENGTH_SHORT).show();
// Starts by looking for the entry tag
if (name.equals("listing")) {
entries.add(readEntry(parser));
} else {
skip(parser);
}
}
return entries;
}
The problem is it only reads to the second level of tags and not inside the results tag so it cannot find listing.
How do I go another level in while reading?
Adding this statement seems to have fixed the problem
if (name.equals("results")) {
String nextTokedn = "Next Level " + parser.nextTag();
}

XML object storage

I've created an XML pull-parser which pulls details of an xml out:
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new InputStreamReader(response3.getEntity().getContent()));
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_DOCUMENT) {
System.out.println("Start document");
} else if(eventType == XmlPullParser.START_TAG) {
System.out.println("Start tag "+xpp.getName());
} else if(eventType == XmlPullParser.END_TAG) {
System.out.println("End tag "+xpp.getName());
} else if(eventType == XmlPullParser.TEXT) {
System.out.println("Text "+xpp.getText());
}
eventType = xpp.next();
}
This searches through the XML correctly pulling out different tags etc.
My problem is now that I wish to store these. The basic structure is that it stores a series of cards, each with an attribute list. The outer tag would be something like <card> and inside there would be many attributes such as <resourceid>, <price> etc.
I wish to store each card in an easy to retrieve manner. I was thinking of using SQlite but have very little experience with it.Is it possible to do this as the parser steps through?
Added my class here
public class SecondActivity {
String resourceid;
String startprice;
String currentbid;
String buynowprice;
String expires;
public String getResourceId(){
return this.resourceid;
}
public String getStartPrice(){
return this.startprice;
}
public String getCurrentBid(){
return this.currentbid;
}
public String getBuyNowPrice(){
return this.buynowprice;
}
public String getExpires(){
return this.expires;
}
public void setResourceId(String resourceidin){
this.resourceid = resourceidin;
}
public void setStartPrice(String startpricein){
this.startprice = startpricein;
}
public void setCurrentBid(String currentbidin){
this.currentbid = currentbidin;
}
public void setBuyNowPrice(String buynowpricein){
this.buynowprice = buynowpricein;
}
public void setExpires(String expiresin){
this.expires = expiresin;
}
}
I now just call each statement i.e. the set inside where the parser finds the tag values, I then call a store, passing it this object? How do I then clear all values inside object?
Thanks for all the help, most appreciated.
Trying to find the start of the card as defined by
added this to my code:
else if(eventType == XmlPullParser.START_TAG) {
if (xpp.getName() == "auctionInfo"){
this.setMyflag(1);
System.out.println("IN THE IF FLAG IS SET TO 1");
}
System.out.println("Start tag "+xpp.getName());
Unfortunately it never enters the if, and I am stumped as to why!
Sure you can. For some input about how to use SQLite in Android, see here.
You could (for example) create a class which holds the informations for one of your <card>-tags (to build something like a data-package for one card) and then perform the Database-Inserts in another method which takes an Object of this class and processes it.
Your <card>-element will have multiple child-elements or attributes. Those are the fields you for your new class. When the parser finds one of those Child-Elements/Attributes, you set the corresponding field in your class.
When the parser finds the next <card>-element, you first call your storeCardInDB()-method (or whatever you call it) and pass it the filled out Object.
The method will take the fields from your Object, bind them to a PreparedStatement (for example) and send it to the Database.
This is done for every <card>-element in your XML-File.
Okay, there is a difference in comparing two ints and two Strings. If you want to know if the content of a String matches the content of another String, you'll need to use the equals()-method:
if ( xpp.getName().equals("auctionInfo") ) {[...]}
Here is a nice article which should clear the background of this behavior.

Categories

Resources