Android, XMLParser - Reading XML - android

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.

Related

how to get inner image url including XML tags Android Studio?

i can't access the inner tag to get the image "url"
here my tag name is "enclosure" and it contain another one called "url" and this is what i want to get...
here the a whole class i created
**public class ParseApplications {
private static final String TAG = "ParseApplications";
private ArrayList<NewsFeeds> application;
public ParseApplications() {
this.application = new ArrayList<>();
}
public ArrayList<NewsFeeds> getApplication() {
return application;
}
public boolean Parse(String xmlData) {
boolean status = true;
NewsFeeds currentNews = null;
boolean InEntry = false;
String textValue = "";
boolean gotImage = false;
try {
// XmlPullParserFactory This class is used to create implementations of XML Pull Parser defined in XMPULL
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//coming line mean that the xml parse i will handle it by my code
/*
Specifies that the parser produced by this factory will provide support for XML namespaces.
By default the value of this is set to false.
Parameters
awareness
boolean: true if the parser produced by this code will provide support for XML namespaces; false otherwise.
*/
factory.setNamespaceAware(true);
//XML Pull Parser is an interface that defines parsing functionality provided in XMLPULL V1 API
//newPullParser is Creates a new instance of a XML Pull Parser using the currently configured factory features.
XmlPullParser xxp = factory.newPullParser();
xxp.setInput(new StringReader(xmlData));
//getEventType Returns the type of the current event (START_TAG, END_TAG, TEXT, etc.). return int
int eventType = xxp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagName = xxp.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
Log.d(TAG, "Parse: Starting tag for " + tagName);
if ("item".equalsIgnoreCase(tagName)) {
InEntry = true;
currentNews = new NewsFeeds();
}
break;
case XmlPullParser.TEXT:
textValue = xxp.getText();
break;
case XmlPullParser.END_TAG:
if (InEntry) {
if ("item".equalsIgnoreCase(tagName)) {
application.add(currentNews);
} else if ("title".equalsIgnoreCase(tagName)) {
currentNews.setName(textValue);
} else if ("pubdate".equalsIgnoreCase(tagName)) {
currentNews.setTheDate(textValue);
} else if ("description".equalsIgnoreCase(tagName)) {
currentNews.setSummry(textValue);
} else if ("link".equalsIgnoreCase(tagName)) {
currentNews.setTitle(textValue);
} else if ("enclosure".equalsIgnoreCase(tagName)) {
currentNews.setImageUrl(textValue);
}
}
break;
default:
//nothing to do
}
eventType = xxp.next();
}
for (NewsFeeds app : application) {
Log.d(TAG, "*********************");
Log.d(TAG, app.toString());
}
} catch (Exception e) {
status = false;
}
return status;
}
}**
i can't access the inner tag to get the image "url" here my tag name is "enclosure" and it contain another one called "url" and this is what i want to get... here the a whole class i created
I suggest printing the raw data and see the hierarchy of the tags. just do a Log without parsing the data and read it yourself. It might be missing or you need to access a parent tag before you get it.
also this might seem basic but are you sure you typed it correctly ? (capital letters, spaces etc)
How about the other tags ? I guess you are getting them correctly .
SOLVED
JUST TWO LINES
else if ("enclosure".equalsIgnoreCase(tagName)) {
String url = xxp.getAttributeValue(0);
currentNews.setImageUrl(url);
}

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.

How to parse Nested tag with same name using XMLpullparser in android

I want to parse title and link tag only in item section with XMLpullparser. how do i parse it with ignoring previous title and link tag?
<channel>
<title>AAA</title>
<link>linkone</link>
<item>
<title>BBB</title>
<link>link2</link>
</item>
</channel>
The parser which i am using currently is following. How do ignore starting title and link tag?
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
FileInputStream fis = ctx.openFileInput("StackSites.xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
xpp.setInput(reader);
int eventtype = xpp.getEventType();
while (eventtype != XmlPullParser.END_DOCUMENT){
String tagname = xpp.getName();
switch (eventtype){
case XmlPullParser.START_TAG:
if(tagname.equalsIgnoreCase("item")){
curStackSite = new StackSite();
}
break;
case XmlPullParser.TEXT:
curText = xpp.getText();
break;
case XmlPullParser.END_TAG:
if(tagname.equalsIgnoreCase("item")){
stackSites.add(curStackSite);
}
if(tagname.equalsIgnoreCase("title")){
curStackSite.setName(curText);
}
if(tagname.equalsIgnoreCase("link")){
curStackSite.setLink(curText);
}
break;
default:
break;
}
eventtype = xpp.next();
}
I dont know wheather its right way to do it, but what i did is inside case XmlPullParser.START_TAG: if it found item tag , ive set counter is equal to 1. and in case XmlPullParser.END_TAG: if counter != 0, then only it adds value to object .this method works. if anybody knows more accurate way please post. Thanks.
There is one library available to parse xml response to POJO class.
https://github.com/stanfy/gson-xml
By using this library, you do not need to do manual parsing. You need to create POJO class according to your xml.
For given xml, you need to create two POJO classes
Channel.java
public class Channel {
Item item;
}
Item.java
public class Item {
String title;
String link;
}
Now you can parse your xml like below
public void parseXml(Strng xml){
XmlParserCreator parserCreator = new XmlParserCreator() {
#Override
public XmlPullParser createParser() {
try {
return XmlPullParserFactory.newInstance().newPullParser();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
GsonXml gsonXml = new GsonXmlBuilder().setXmlParserCreator(parserCreator).create();
Channel channel = gsonXml.fromXml(xml, Channel.class);
Log.v("temp", "Title : " + channel.item.title);
}

Parsing XML XmlPullParser android

i'm using xmlpullparser in android to parse an xml document that looks like :
<top>
<category>
<name></name>
<desc></desc>
<songs>
<song>
<clip></clip>
<thumb></thumb>
</song>
<song>
<clip></clip>
<thumb></thumb>
</song>
</songs>
</category>
</top>
I tried this :
while (eventType != XmlPullParser.END_DOCUMENT && !done){
String name = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
categoriesSong = new ArrayList<TopMousika>();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(CATEGORY)){
currentCategory = new TopMousika();
currentCategory.setId(parser.getAttributeValue(0));
currentCategory.setId(parser.getAttributeValue(1));
} else if (currentCategory != null){
if (name.equalsIgnoreCase(NAME)){
currentCategory.setName(parser.nextText());
} else if (name.equalsIgnoreCase(DESCRIPTION)){
currentCategory.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(THUMBNAIL)){
currentCategory.setThumbnail(parser.nextText());
} else if (name.equalsIgnoreCase(SONGS)){
songs = new ArrayList<SongMousika>();
if(name.equalsIgnoreCase(SONG)){
currentSong = new SongMousika();
currentSong.setId(parser.getAttributeValue(0));
Log.d("TEST", "OK");
songs.add(currentSong);
} else if (name.equalsIgnoreCase(TITLE)){
Log.d("TEST", "OK2");
currentSong.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(SINGER)){
currentSong.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(THUMBNAIL)){
currentSong.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(PUBLICATION_DATE)){
currentSong.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(CLIP)){
currentSong.setTitle(parser.nextText());
}
currentCategory.setSongs(songs);
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(CATEGORY) &&
currentCategory != null){
currentCategory.setSongs(songs);
categoriesSong.add(currentCategory);
} else if (name.equalsIgnoreCase(TOP)){
done = true;
}
break;
}
eventType = parser.next();
}
but I can not retrieve my Songs List.
can any one help me please ?
You seem to be expecting name to change magically between checks:
if (name.equalsIgnoreCase(SONGS)) {
songs = new ArrayList<SongMousika>();
if(name.equalsIgnoreCase(SONG)) {
How is it going to be SONG and SONGS? You need to keep pulling XML and react to each element name differently in the loop. So you'll probably have a bunch of if/else if statements without any nesting when reacting to a START_TAG event. (It's very likely to be worth pulling the handling of that into a separate method, by the way.)
EDIT: Okay, so you need to make each iteration of the loop just react to one tag. So your handling for a start tag would be something like:
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(CATEGORY)){
currentCategory = new TopMousika();
currentCategory.setId(parser.getAttributeValue(0));
currentCategory.setId(parser.getAttributeValue(1));
} else if (currentCategory != null) {
if (name.equalsIgnoreCase(NAME)){
currentCategory.setName(parser.nextText());
} else if (name.equalsIgnoreCase(DESCRIPTION)){
currentCategory.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(THUMBNAIL)){
currentCategory.setThumbnail(parser.nextText());
} else if (name.equalsIgnoreCase(SONGS)){
songs = new ArrayList<SongMousika>();
} else if (songs != null) {
if(name.equalsIgnoreCase(SONG)) {
currentSong = new SongMousika();
currentSong.setId(parser.getAttributeValue(0));
Log.d("TEST", "OK");
songs.add(currentSong);
} else if (currentSong != null) {
else if (name.equalsIgnoreCase(TITLE)) {
Log.d("TEST", "OK2");
currentSong.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(SINGER)){
currentSong.setSinger(parser.nextText());
} else if (name.equalsIgnoreCase(THUMBNAIL))
// etc
}
}
}
Note how in any path through there we never check for name having multiple values - we say:
Are we starting a new category?
If so, create it and remember it - then continue with the next iteration.
If not (and if we've got a category), are we starting a new song list?
If so, create it and remember it - then continue with the next iteration.
If not (and if we've got a song list), are we starting a new song?
If so, create it and remember it - then continue with the next iteration.
If not (and if we've got a song)...
Are we reading the title? If so, read the text and set it, then continue.
Are we reading the singer? If so, read the text and set it, then continue.
Are we reading the thumbnail? If so, read the text and set it, then continue.
etc

XMLPullParser Out of Memory (Android)

I'm stuck in trying to handle an out of memory error in Android while trying to parse a response from a HTTPTransfer using SOAP. Overall the transport is fine until I ask for a large image. The image is about 901KB is size, but for some reason it causes Android to run out of memory while parsing it. Here is the code:
public void parseWithPullParser(InputStream is) {
try {
XmlPullParser parser = GenericHandler.createParser(this.parserTypeName); // new
// org.xmlpull.mxp1.MXParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(is, null);
Log.d(TAG, "Name of class being parsed: " + resultClassName);
for (int eventType = parser.getEventType(); eventType != XmlPullParser.END_DOCUMENT; eventType = parser
.next()) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT: {
break;
}
case XmlPullParser.START_TAG: {
String name = parser.getName();
String prefix = null;
if ("Envelope".equals(name) || "Header".equals(name) || "Body".equals(name)
|| "return".equals(name)) {
prefix = "env:"; // TODO: Hack-Hack-Hack... :)
}
name = prefix == null ? name : prefix + ":" + name;
this.startElement(name);
break;
}
case XmlPullParser.TEXT: {
String text = parser.getText();
if (text != null) {
if (resultClassName.contains("ImageSingle")) {
Log.d(TAG, "Text passage: " + text);
}
if (content == null) {
content = new String();
}
content = text; // Original system used a string builder
// but only for a single section, for
// large images this was a problem, but
// a single string object appears to
// have the same affect
// char[] ch = text.toCharArray(); //original
// this.characters(ch, 0, ch.length); //original
}
break;
}
case XmlPullParser.END_TAG: {
String name = parser.getName();
String prefix = null;
if ("Envelope".equals(name) || "Header".equals(name) || "Body".equals(name)
|| "return".equals(name)) {
prefix = "env:"; // TODO: Hack-Hack-Hack... :)
}
name = prefix == null ? name : prefix + ":" + name;
this.endElement(name);
break;
}
default: {
break;
}
}
}
} catch (Exception except) {
Log.e(this.getClass().getSimpleName(), except.toString(), except);
}
}
I found the library here. The issue (I believe) is when it does parser.next() because it reads in the image data (which is sent to me in a Base64 encoded string) and then tries to do parser.getText(). If I am understanding everything properly the way it outputs the string is by repetitive calls to the internal stringbuilder that will keep repeating .toString() to itself until it generates the parsed string. The image in question is about 1.2 million characters and as each character is 2 bytes, that implies 2.4 MB (the image though is 901 KB originally..but I guess there's extra data that gets parsed?) if I understand this correctly. But the heap expands to over 16 MB which causes the app to crash on stock VM settings when this method is called.
I doubt this is a unique situation and as such would love to hear how others have handled this problem. I've thought about maybe just throwing the string to a file on the SD card to keep it out of memory but it seems that for me to get the string I need parser.getText...which therein lies the problem.
Pursuant to Stephan Branczyk's comment here is my comment extracted and marked as the answer to my question.
For anyone that comes across this, I eventually ended up using a sax parser, I got the idea from here : helloandroid.com/tutorials/newsdroid-rss-reader

Categories

Resources