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"));
}
Related
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.
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();
}
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...
im currently trying to read and XML from a web server in my Android App, but im not sure how to search for the TAGS, and all the examples i see are not unlike mine:
<document>
<producer/>
<metadata></metadata>
<recorddata count="111">
<row>
<field name="numint" value="MTAwMQ=="/>
<field name="Grupo" value="NQ=="/>
<field name="Link" value="Q29ycmllbnRlcw=="/>
<field name="Nombre" value="Q29ycmllbnRlcw=="/>
<field name="Valor" value="MzQwMC4wMA=="/>
</row>
</recorddata>
</document>
I need to read the ROWS inside RECORDATA, but im not sure how to address this problem, this is my code:
private void parseXML(XmlPullParser parser) throws XmlPullParserException,IOException
{
ArrayList<Record> Records = null;
int eventType = parser.getEventType();
Record currentRecord = null;
while (eventType != XmlPullParser.END_DOCUMENT){
String name = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
Records = new ArrayList();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name == "row"){
currentRecord = new Record();
} else if (currentRecord != null){
if (name == "numint"){
currentRecord.numint = parser.getText();
} else if (name == "Grupo"){
currentRecord.group = parser.getText();
} else if (name == "Link"){
currentRecord.link= parser.getText();
}else if (name == "Nombre") {
currentRecord.name= parser.getText();
}else if (name == "Valor") {
currentRecord.value= parser.getText();
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase("row") && currentRecord != null){
Records.add(currentRecord);
}
}
eventType = parser.next();
}
printProducts(Records);
}
BUT, the Records List IS EMPTY at the end of the process, and i can tell is doing something, because there are a lot of records and it takes like 2 minutes till the process is over.
Im not sure if im using the getName() correctly, should i be checking for field??? and if so, how do i know in which field im on. Should i be using nextToken() instead???
I Solved the problem by rewriting my code as follows:
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equals("row")){
currentRecord = new Record();
} else if (currentRecord != null) {
if(parser.getName().equals("field")) {
if(parser.getAttributeValue(null, "name").equalsIgnoreCase("numint")) {
currentRecord.numint = parser.getAttributeValue(null, "value");
}else if (parser.getAttributeValue(null, "name").equalsIgnoreCase("Grupo")) {
currentRecord.group = parser.getAttributeValue(null, "value");
}else if (parser.getAttributeValue(null, "name").equalsIgnoreCase("Link")) {
currentRecord.link = parser.getAttributeValue(null, "value");
}else if (parser.getAttributeValue(null, "name").equalsIgnoreCase("Nombre")) {
currentRecord.name = parser.getAttributeValue(null, "value");
}else if (parser.getAttributeValue(null, "name").equalsIgnoreCase("Valor")) {
currentRecord.value = parser.getAttributeValue(null, "value");
}
}
}
break;
Taking something the answer by Andreaoid, and a little tweaking, i could the read de xml file without issue
To get an attribute you can use the method:
parser.getAttributeValue(null, "value");
Definition:
public abstract String getAttributeValue (String namespace, String name)
Taken from help:
*Added in API level 1. Returns the attributes value identified by namespace URI and namespace localName. If namespaces are disabled namespace must be null. If current event type is not START_TAG then IndexOutOfBoundsException will be thrown.*
Pay attention: Replace all the String comparisons!
name == "row"
With:
name.equals("row")
Hope it helps.
I've the following xml file inside the /mnt/sdcard. I want to get the version of the item type=provider from the following file. The file is big(1500 lines) which has other types also. This is simplified file. In the file I'm interested in this node:
<Item Type="Provider" Version="19.0.0.0"Checksum="EShHVeNtW1xTfEvLvATwqA==" FileSize="2746200" />
From this node I want to get the version i.e. 19.0.0.0.
Here is my xml file:
<Manifest guid="FD29E1EF-A5C4-4D19-ACC8-8C98C7E91B02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" PackageType="Full" Scope="APPROVED">
<Items>
<Item id="fcxm-8ikj-olk-ffgcxh3" Checksum="EShHVeNtW1xTfEvLvATwqA==" value="f425921f-b6ef-4e58-8a14-fcbd0d7e50e9" />
<Item Type="question" Version="19.0.0.0"Checksum="EShHVeNtW1xTfEvLvATwqA==" FileSize="2746200" />
<Item Type="Provider" Version="19.0.0.0"Checksum="EShHVeNtW1xTfEvLvATwqA==" FileSize="2746200" />
</Items>
</Manifest>
I searched on the internet, I got this which is iterating to all the nodes of item type. I dont want want to iterate.
How can I do this in Android using XmlPullParser?
Hi you can try this,
private void parseContent(XmlPullParser parser)
throws XmlPullParserException,IOException,Exception {
int eventType;
while((eventType=parser.next()) != XmlPullParser.END_TAG) {
if (eventType == XmlPullParser.START_TAG) {
Log.d(MY_DEBUG_TAG,"Parsing Attributes for ["+parser.getName()+"]");
Map<String,String> attributes = getAttributes(parser);
}
else if(eventType==...);
else {
throw new Exception("Invalid tag at content parse");
}
}
}
private Map<String,String> getAttributes(XmlPullParser parser) throws Exception {
Map<String,String> attrs=null;
int acount=parser.getAttributeCount();
if(acount != -1) {
Log.d(MY_DEBUG_TAG,"Attributes for ["+parser.getName()+"]");
attrs = new HashMap<String,String>(acount);
for(int x=0;x<acount;x++) {
Log.d(MY_DEBUG_TAG,"\t["+parser.getAttributeName(x)+"]=" +
"["+parser.getAttributeValue(x)+"]");
attrs.put(parser.getAttributeName(x), parser.getAttributeValue(x));
}
}
else {
throw new Exception("Required entity attributes missing");
}
return attrs;
}