Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I need to parse xml data in android. I have seen this project: here from github which teaches how to parse xml data in listbox. However, I want to get xml data to different strings. Although, I have used pretty much the same code as in the github project but I only get error and the app stops responding.
Code:
public class Main extends Fragment {
android.view.View myview;
EditText number;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
myview = inflater.inflate(R.layout.fragment_screen, container, false);
number = (EditText) myview.findViewById(R.id.number);
XmlParser par = new XmlParser();
number.setText(par.getStackSitesFromFile(getActivity().getBaseContext())
.get(0).getLink()); **Error here**
return myview;
}
}
XmlParser.java
public class XmlParser {
static final String KEY_SITE = "rate";
static final String KEY_NAME = "Name";
static final String KEY_LINK = "Rate";
static final String KEY_ABOUT = "Date";
static final String KEY_IMAGE_URL = "Time";
public static List<HandleXML> getStackSitesFromFile(Context ctx) {
// List of StackSites that we will return
List<HandleXML> stackSites;
stackSites = new ArrayList<HandleXML>();
// temp holder for current StackSite while parsing
HandleXML curStackSite = null;
// temp holder for current text value while parsing
String curText = "";
try {
// Get our factory and PullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
// Open up InputStream and Reader of our file.
FileInputStream fis = ctx.openFileInput("/sdcard/rates.xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
// point the parser to our file.
xpp.setInput(reader);
// get initial eventType
int eventType = xpp.getEventType();
// Loop through pull events until we reach END_DOCUMENT
while (eventType != XmlPullParser.END_DOCUMENT) {
// Get the current tag
String tagname = xpp.getName();
// React to different event types appropriately
switch (eventType) {
case XmlPullParser.START_TAG:
if (tagname.equals("test")) {
curStackSite = new HandleXML();
}
break;
case XmlPullParser.TEXT:
//grab the current text so we can use it in END_TAG event
curText = xpp.getText();
break;
case XmlPullParser.END_TAG:
if (tagname.equalsIgnoreCase("test")) {
stackSites.add(curStackSite);
} else if (tagname.equalsIgnoreCase(KEY_NAME)) {
curStackSite.setName(curText);
} else if (tagname.equals("Rate")) {
curStackSite.setLink(curText);
} else if (tagname.equalsIgnoreCase(KEY_ABOUT)) {
curStackSite.setAbout(curText);
} else if (tagname.equalsIgnoreCase(KEY_IMAGE_URL)) {
curStackSite.setImgUrl(curText);
}
break;
default:
break;
}
eventType = xpp.next();
}
} catch (Exception e) {
e.printStackTrace();
}
// return the populated list.
return stackSites;
}
}
And finally, HandleXml.java
public class HandleXML {
private String name;
private String rate;
private String date;
private String time;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return rate;
}
public void setLink(String rate) {
this.rate = rate;
}
public String getAbout() {
return date;
}
public void setAbout(String date) {
this.date = date;
}
public String getImgUrl() {
return time;
}
public void setImgUrl(String time) {
this.time = time;
}
#Override
public String toString() {
return name + rate;
}
}
Xml File:
<?xml version="1.0" encoding="UTF-8"?>
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="1" yahoo:created="2016-09-07T05:50:08Z" yahoo:lang="en-US">
<results>
<test>
<Name>EUR/USD</Name>
<Rate>1.1251</Rate>
<Date>9/7/2016</Date>
<Time>0:56am</Time>
</test>
<test>
<Name>EUR/USD</Name>
<Rate>1.1253</Rate>
<Date>9/7/2016</Date>
<Time>0:56am</Time>
</test>
</results>
</query>
The error is in the first fragment of code in: number.setText(par.getStackSitesFromFile(getActivity().getBaseContext()).get(0).getLink());
The arraylist returns empty because FileInputStream fis is set to open a file which contains path separator (/) , and it causes
java.lang.IllegalArgumentException: File /sdcard/rates.xml contains a path separator
. You have to use
FileInputStream fis = new FileInputStream (new File("/sdcard/rates.xml")); instead. Do not forget to close fis by fis.close();
Final code for XmlParser will be:
public class XmlParser {
static final String KEY_SITE = "rate";
static final String KEY_NAME = "Name";
static final String KEY_LINK = "Rate";
static final String KEY_ABOUT = "Date";
static final String KEY_IMAGE_URL = "Time";
FileInputStream fis;
public static List<HandleXML> getStackSitesFromFile() {
// List of StackSites that we will return
List<HandleXML> stackSites;
stackSites = new ArrayList<HandleXML>();
// temp holder for current StackSite while parsing
HandleXML curStackSite = null;
// temp holder for current text value while parsing
String curText = "";
try {
// Get our factory and PullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
// Open up InputStream and Reader of our file.
fis = new FileInputStream(new File("/sdcard/rates.xml"));
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
// point the parser to our file.
xpp.setInput(reader);
// get initial eventType
int eventType = xpp.getEventType();
// Loop through pull events until we reach END_DOCUMENT
while (eventType != XmlPullParser.END_DOCUMENT) {
// Get the current tag
String tagname = xpp.getName();
// React to different event types appropriately
switch (eventType) {
case XmlPullParser.START_TAG:
if (tagname.equals("test")) {
curStackSite = new HandleXML();
}
break;
case XmlPullParser.TEXT:
//grab the current text so we can use it in END_TAG event
curText = xpp.getText();
break;
case XmlPullParser.END_TAG:
if (tagname.equalsIgnoreCase("test")) {
stackSites.add(curStackSite);
} else if (tagname.equalsIgnoreCase(KEY_NAME)) {
curStackSite.setName(curText);
} else if (tagname.equals("Rate")) {
curStackSite.setLink(curText);
} else if (tagname.equalsIgnoreCase(KEY_ABOUT)) {
curStackSite.setAbout(curText);
} else if (tagname.equalsIgnoreCase(KEY_IMAGE_URL)) {
curStackSite.setImgUrl(curText);
}
break;
default:
break;
}
eventType = xpp.next();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
fis.close();
}catch(Exception e){
Log.i("Problem closing", "Closing fis");
}
// return the populated list.
return stackSites;
}
}
And then set number.setText() like that: number.setText(par.getStackSitesFromFile().get(0).getLink());
Related
I created XML parsing RSS reader,but it is only reading the last 3 nodes (which is title,link and description ).i want to know which lines of code making this trick(i mean reading the last nodes).if i want to read the first three nodes from this rss site,what i should i actually do ?
i am a nuwbie . can anyone post the answer as code?
public class HandleXML {
private String title = "title";
private String link = "link";
private String description = "description";
private String title1 = "title";
private String link1 = "link";
private String description1 = "description";
private String urlString = null;
private XmlPullParserFactory xmlFactoryObject;
public volatile boolean parsingComplete = true;
public HandleXML(String url){
this.urlString = url;
}
public String getTitle(){
return title;
}
public String getLink(){
return link;
}
public String getDescription(){
return description;
}
public void parseXMLAndStoreIt(XmlPullParser myParser) {
int event;
String text=null;
try {
event = myParser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String name=myParser.getName();
switch (event){
case XmlPullParser.START_TAG:
break;
case XmlPullParser.TEXT:
text = myParser.getText();
break;
case XmlPullParser.END_TAG:
if(name.equals("title")){
title = text;
}
else if(name.equals("link")){
link = text;
}
else if(name.equals("description")){
description = text;
}
else{
}
break;
}
event = myParser.next();
}
parsingComplete = false;
}
catch (Exception e) {
e.printStackTrace();
}
}
public void fetchXML(){
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
InputStream stream = conn.getInputStream();
xmlFactoryObject = XmlPullParserFactory.newInstance();
XmlPullParser myparser = xmlFactoryObject.newPullParser();
myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
myparser.setInput(stream, null);
parseXMLAndStoreIt(myparser);
stream.close();
}
catch (Exception e) {
}
}
});
thread.start();
}
}
It is this part of the code that is responsible to read the elements you mentioned above .
if(name.equals("title")){
title = text;
}
else if(name.equals("link")){
link = text;
}
else if(name.equals("description")){
description = text;
}
else{
// Write similar conditions for the other tags that you want to parse.
}
You are using a while loop in order to process the document.
Within that loop your code reads all the title, link and description nodes.
The problem is that it overrides the variables every time, hence what you get is the last title, link and description.
If you would like to read only the firs title, link and description you could do something like:
Initialise variables like this:
private String title;
private String link;
private String description;
Than:
if(name.equals("title") && title != null){
title = text;
}
else if(name.equals("link") && link != null){
link = text;
}
else if(name.equals("description") && description != null){
description = text;
}
EDIT (try this, warning: I haven't tested it)
public class HandleXML {
public volatile boolean parsingComplete = true;
private String title;
private String link;
private String description;
private String urlString = null;
private XmlPullParserFactory xmlFactoryObject;
public HandleXML(String url) {
this.urlString = url;
}
public String getTitle() {
return title;
}
public String getLink() {
return link;
}
public String getDescription() {
return description;
}
public void parseXMLAndStoreIt(XmlPullParser myParser) {
int event;
String text = null;
try {
event = myParser.getEventType();
while (event != XmlPullParser.END_DOCUMENT) {
String name = myParser.getName();
switch (event) {
case XmlPullParser.START_TAG:
break;
case XmlPullParser.TEXT:
text = myParser.getText();
break;
case XmlPullParser.END_TAG:
if (name.equals("title") && title != null) {
title = text;
}
else if (name.equals("link") && link != null) {
link = text;
}
else if (name.equals("description") && description != null) {
description = text;
}
break;
}
event = myParser.next();
}
parsingComplete = false;
}
catch (Exception e) {
e.printStackTrace();
}
}
public void fetchXML() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
InputStream stream = conn.getInputStream();
xmlFactoryObject = XmlPullParserFactory.newInstance();
XmlPullParser myparser = xmlFactoryObject.newPullParser();
myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
myparser.setInput(stream, null);
parseXMLAndStoreIt(myparser);
stream.close();
}
catch (Exception e) {
// TODO: 27/07/2017 handle exception
}
}
});
thread.start();
}
}
I am trying change my RSS Reader code. I have something like this:
public class RSSFeedParser {
static final String TITLE = "title";
static final String DESCRIPTION = "description";
static final String CHANNEL = "channel";
static final String LANGUAGE = "language";
static final String COPYRIGHT = "copyright";
static final String LINK = "link";
static final String AUTHOR = "author";
static final String ITEM = "item";
static final String PUB_DATE = "pubDate";
static final String GUID = "guid";
public InputStream in = read();
private XMLInputFactory inputFactory = XMLInputFactory.newInstance();
private XMLEventReader eventReader;
final URL url;
public RSSFeedParser(String feedUrl) {
try {
url = new URL(feedUrl);
eventReader = inputFactory.createXMLEventReader(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Feed readFeed() {
Feed feed = null;
try {
boolean isFeedHeader = true;
String description = "";
String title = "";
String link = "";
String language = "";
String copyright = "";
String author = "";
String pubDate = "";
String guid = "";
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
String localPart = event.asStartElement().getName().getLocalPart();
switch (localPart) {
case ITEM:
if (isFeedHeader) {
isFeedHeader = false;
feed = new Feed(title, link, description, language, copyright, pubDate);
}
event = eventReader.nextEvent();
break;
case TITLE:
title = getCharacterData(event, eventReader);
break;
case DESCRIPTION:
description = getCharacterData(event, eventReader);
break;
case LINK:
link = getCharacterData(event, eventReader);
break;
case GUID:
guid = getCharacterData(event, eventReader);
break;
case LANGUAGE:
language = getCharacterData(event, eventReader);
break;
case AUTHOR:
author = getCharacterData(event, eventReader);
break;
case PUB_DATE:
pubDate = getCharacterData(event, eventReader);
break;
case COPYRIGHT:
copyright = getCharacterData(event, eventReader);
break;
}
}
else if(event.isEndElement()) {
if (event.asEndElement().getName().getLocalPart() == (ITEM)) {
FeedMessage message = new FeedMessage();
message.setAuthor(author);
message.setDescription(description);
message.setGuid(guid);
message.setLink(link);
message.setTitle(title);
feed.getMessages().add(message);
}
}
}
} catch (XMLStreamException e) {
throw new RuntimeException(e);
}
return feed;
}
private InputStream read(){
try{
return url.openStream();
}catch (IOException e){
throw new RuntimeException(e);
}
}
private String getCharacterData(XMLEvent event, XMLEventReader eventReader) throws XMLStreamException {
String results="";
event = eventReader.nextEvent();
if(event instanceof Characters){
results = event.asCharacters().getData();
}
return results;
}
And main:
public static void main(String[] args) {
RSSFeedParser parser = new RSSFeedParser("http://newsrss.bbc.co.uk/rss/sportonline_uk_edition/other_sports/rss.xml");
Feed feed = parser.readFeed();
System.out.println(feed);
for (FeedMessage message : feed.getMessages()) {
System.out.println(message);
RSSFeedWriter writer = new RSSFeedWriter(feed, "articles.rss");
try {
writer.write();
} catch (Exception e) {
e.printStackTrace();
}
}
}
I get NullPointerException in
public InputStream in = read();
return url.openStream();
RSSFeedParser parser = new RSSFeedParser("http://newsrss.bbc.co.uk/rss/sportonline_uk_edition/other_sports/rss.xml");
What's wrong with this code? Everything was working when the InputStream, XMLEventReader and XMLInputFactory was in separate class.
You are calling the read() method before the URL object is initialized. Try something like this:
public InputStream in;
public RSSFeedParser(String feedUrl) {
try {
url = new URL(feedUrl);
in = read();
eventReader = inputFactory.createXMLEventReader(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Also, It is good practice to close resources after use (streams & readers).
I am making an android app that downloads an xml file and creates a list view where the downloaded data are shown. The app was working fine. Suddenly the screen appears empty. I did not make any change. I have a variable that shows the length of the arrayadapter and it appears to be 0. The logcat shows a NullPointerException in the file below:
package com.makemyandroidapp.example.stacksites;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import android.content.Context;
public class SitesXmlPullParser {
/*static final String KEY_SITE = "site";
static final String KEY_NAME = "name";
static final String KEY_LINK = "link";
static final String KEY_ABOUT = "about"; */
static final String KEY_SITE = "pozicioni";
static final String KEY_KOMPANIA = "kompania";
static final String KEY_POZICIONI = "pozicioni";
static final String KEY_KATEGORIA = "kategoria";
static final String KEY_QYTETI = "qyteti";
static final String KEY_IMAGE_URL = "image";
public static List<StackSite> getStackSitesFromFile(Context ctx) {
// List of StackSites that we will return
List<StackSite> stackSites;
stackSites = new ArrayList<StackSite>();
// temp holder for current StackSite while parsing
StackSite curStackSite = null;
// temp holder for current text value while parsing
String curText = "";
try {
// Get our factory and PullParser
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
// Open up InputStream and Reader of our file.
FileInputStream fis = ctx.openFileInput("StackSites.xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
// point the parser to our file.
xpp.setInput(reader);
// get initial eventType
int eventType = xpp.getEventType();
boolean done = false;
int count=0;
// Loop through pull events until we reach END_DOCUMENT
while (eventType != XmlPullParser.END_DOCUMENT) {
// Get the current tag
String tagname = xpp.getName();
// React to different event types appropriately
switch (eventType) {
case XmlPullParser.START_TAG:
if (tagname.equalsIgnoreCase(KEY_SITE)&&count==0) {
// If we are starting a new <site> block we need
//a new StackSite object to represent it
curStackSite = new StackSite();
count=1;
System.out.println(count);
}
break;
case XmlPullParser.TEXT:
{String s="";
String href="";
s=xpp.getText(); //in case of cdsect this is null otherwise you get the text right here already
if (s==null) { //what would happen if it encounters in fact a cdsect
int event=xpp.nextToken(); //this is the main technical important line
if (event==XmlPullParser.CDSECT) {
s=xpp.getText();
}
}
curText=s;
break;}
case XmlPullParser.END_TAG:
if (tagname.equalsIgnoreCase(KEY_SITE)&&count==1) {
// if </site> then we are done with current Site
// add it to the list.
count=0;
System.out.println(curText);
curStackSite.setPozicioni(curText);
}
else if (tagname.equalsIgnoreCase(KEY_SITE)&&count==0){
stackSites.add(curStackSite);
} else if (tagname.equalsIgnoreCase(KEY_KOMPANIA)) {
// if </name> use setName() on curSite
//curStackSite.setKompania(curText);
System.out.println(curText+"kooooooooooooooooooooooooooooooooooooooot");
curStackSite.setKompania(curText);
System.out.println(curText+"kooooooooooooooooooooooooooooooooooooooot");
} else if (tagname.equalsIgnoreCase(KEY_KATEGORIA)) {
// if </about> use setAbout() on curSite
curStackSite.setKategoria(curText);
} else if (tagname.equalsIgnoreCase(KEY_QYTETI)){
curStackSite.setQyteti(curText);
}
break;
default:
break;
}
//move on to next iteration
eventType = xpp.next();
}
}
catch (Exception e) {
e.printStackTrace();
}
// return the populated list.
return stackSites;
}
}
NullPointerException occurs in this line:
curStackSite.setKompania(curText);
Please help me! Thanks in advance!
I'd say either to try and instancing an object and then "nulling it", before your try statement or making sure that
curStackSite = new StackSite();
Is reachable
You have it within a case within switch, so it may not always come to it. Which means the reference may fail if the object wasn't instanced.
I am trying to pull some XHTML out of an RSS feed so I can place it in a WebView. The RSS feed in question has a tag called <content> and the characters inside the content are XHTML. (The site I'm paring is a blogger feed)
What is the best way to try to pull this content? The < characters are confusing my parser. I have tried both DOM and SAX but neither can handle this very well.
Here is a sample of the XML as requested. In this case, I want basically XHTML inside the content tag to be a string. <content> XHTML </content>
Edit: based on ignyhere's suggestion I have tried XPath, but I am still having the same issue. Here is a pastebin sample of my tests.
It's not pretty, but this is (the essence of) what I use to parse an ATOM feed from Blogger using XmlPullParser. The code is pretty icky, but it is from a real app. You can probably get the general flavor of it, anyway.
final String TAG_FEED = "feed";
public int parseXml(Reader reader) {
XmlPullParserFactory factory = null;
StringBuilder out = new StringBuilder();
int entries = 0;
try {
factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(reader);
while (true) {
int eventType = xpp.next();
if (eventType == XmlPullParser.END_DOCUMENT) {
break;
} else if (eventType == XmlPullParser.START_DOCUMENT) {
out.append("Start document\n");
} else if (eventType == XmlPullParser.START_TAG) {
String tag = xpp.getName();
// out.append("Start tag " + tag + "\n");
if (TAG_FEED.equalsIgnoreCase(tag)) {
entries = parseFeed(xpp);
}
} else if (eventType == XmlPullParser.END_TAG) {
// out.append("End tag " + xpp.getName() + "\n");
} else if (eventType == XmlPullParser.TEXT) {
// out.append("Text " + xpp.getText() + "\n");
}
}
out.append("End document\n");
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// return out.toString();
return entries;
}
private int parseFeed(XmlPullParser xpp) throws XmlPullParserException, IOException {
int depth = xpp.getDepth();
assert (depth == 1);
int eventType;
int entries = 0;
xpp.require(XmlPullParser.START_TAG, null, TAG_FEED);
while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) && (xpp.getDepth() > depth)) {
// loop invariant: At this point, the parser is not sitting on
// end-of-document, and is at a level deeper than where it started.
if (eventType == XmlPullParser.START_TAG) {
String tag = xpp.getName();
// Log.d("parseFeed", "Start tag: " + tag); // Uncomment to debug
if (FeedEntry.TAG_ENTRY.equalsIgnoreCase(tag)) {
FeedEntry feedEntry = new FeedEntry(xpp);
feedEntry.persist(this);
entries++;
// Log.d("FeedEntry", feedEntry.title); // Uncomment to debug
// xpp.require(XmlPullParser.END_TAG, null, tag);
}
}
}
assert (depth == 1);
return entries;
}
class FeedEntry {
String id;
String published;
String updated;
// Timestamp lastRead;
String title;
String subtitle;
String authorName;
int contentType;
String content;
String preview;
String origLink;
String thumbnailUri;
// Media media;
static final String TAG_ENTRY = "entry";
static final String TAG_ENTRY_ID = "id";
static final String TAG_TITLE = "title";
static final String TAG_SUBTITLE = "subtitle";
static final String TAG_UPDATED = "updated";
static final String TAG_PUBLISHED = "published";
static final String TAG_AUTHOR = "author";
static final String TAG_CONTENT = "content";
static final String TAG_TYPE = "type";
static final String TAG_ORIG_LINK = "origLink";
static final String TAG_THUMBNAIL = "thumbnail";
static final String ATTRIBUTE_URL = "url";
/**
* Create a FeedEntry by pulling its bits out of an XML Pull Parser. Side effect: Advances
* XmlPullParser.
*
* #param xpp
*/
public FeedEntry(XmlPullParser xpp) {
int eventType;
int depth = xpp.getDepth();
assert (depth == 2);
try {
xpp.require(XmlPullParser.START_TAG, null, TAG_ENTRY);
while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT)
&& (xpp.getDepth() > depth)) {
if (eventType == XmlPullParser.START_TAG) {
String tag = xpp.getName();
if (TAG_ENTRY_ID.equalsIgnoreCase(tag)) {
id = Util.XmlPullTag(xpp, TAG_ENTRY_ID);
} else if (TAG_TITLE.equalsIgnoreCase(tag)) {
title = Util.XmlPullTag(xpp, TAG_TITLE);
} else if (TAG_SUBTITLE.equalsIgnoreCase(tag)) {
subtitle = Util.XmlPullTag(xpp, TAG_SUBTITLE);
} else if (TAG_UPDATED.equalsIgnoreCase(tag)) {
updated = Util.XmlPullTag(xpp, TAG_UPDATED);
} else if (TAG_PUBLISHED.equalsIgnoreCase(tag)) {
published = Util.XmlPullTag(xpp, TAG_PUBLISHED);
} else if (TAG_CONTENT.equalsIgnoreCase(tag)) {
int attributeCount = xpp.getAttributeCount();
for (int i = 0; i < attributeCount; i++) {
String attributeName = xpp.getAttributeName(i);
if (attributeName.equalsIgnoreCase(TAG_TYPE)) {
String attributeValue = xpp.getAttributeValue(i);
if (attributeValue
.equalsIgnoreCase(FeedReaderContract.FeedEntry.ATTRIBUTE_NAME_HTML)) {
contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_HTML;
} else if (attributeValue
.equalsIgnoreCase(FeedReaderContract.FeedEntry.ATTRIBUTE_NAME_XHTML)) {
contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_XHTML;
} else {
contentType = FeedReaderContract.FeedEntry.CONTENT_TYPE_TEXT;
}
break;
}
}
content = Util.XmlPullTag(xpp, TAG_CONTENT);
extractPreview();
} else if (TAG_AUTHOR.equalsIgnoreCase(tag)) {
// Skip author for now -- it is complicated
int authorDepth = xpp.getDepth();
assert (authorDepth == 3);
xpp.require(XmlPullParser.START_TAG, null, TAG_AUTHOR);
while (((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT)
&& (xpp.getDepth() > authorDepth)) {
}
assert (xpp.getDepth() == 3);
xpp.require(XmlPullParser.END_TAG, null, TAG_AUTHOR);
} else if (TAG_ORIG_LINK.equalsIgnoreCase(tag)) {
origLink = Util.XmlPullTag(xpp, TAG_ORIG_LINK);
} else if (TAG_THUMBNAIL.equalsIgnoreCase(tag)) {
thumbnailUri = Util.XmlPullAttribute(xpp, tag, null, ATTRIBUTE_URL);
} else {
#SuppressWarnings("unused")
String throwAway = Util.XmlPullTag(xpp, tag);
}
}
} // while
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
assert (xpp.getDepth() == 2);
}
}
public static String XmlPullTag(XmlPullParser xpp, String tag)
throws XmlPullParserException, IOException {
xpp.require(XmlPullParser.START_TAG, null, tag);
String itemText = xpp.nextText();
if (xpp.getEventType() != XmlPullParser.END_TAG) {
xpp.nextTag();
}
xpp.require(XmlPullParser.END_TAG, null, tag);
return itemText;
}
public static String XmlPullAttribute(XmlPullParser xpp,
String tag, String namespace, String name)
throws XmlPullParserException, IOException {
assert (!TextUtils.isEmpty(tag));
assert (!TextUtils.isEmpty(name));
xpp.require(XmlPullParser.START_TAG, null, tag);
String itemText = xpp.getAttributeValue(namespace, name);
if (xpp.getEventType() != XmlPullParser.END_TAG) {
xpp.nextTag();
}
xpp.require(XmlPullParser.END_TAG, null, tag);
return itemText;
}
I'll give you a hint: None of the return values matter. The data is saved into a database by a method (not shown) called at this line:
feedEntry.persist(this);
I would attempt to attack it with XPath. Would something like this work?
public static String parseAtom (InputStream atomIS)
throws Exception {
// Below should yield the second content block
String xpathString = "(//*[starts-with(name(),"content")])[2]";
// or, String xpathString = "//*[name() = 'content'][2]";
// remove the '[2]' to get all content tags or get the count,
// if needed, and then target specific blocks
//String xpathString = "count(//*[starts-with(name(),"content")])";
// note the evaluate expression below returns a glob and not a node set
XPathFactory xpf = XPathFactory.newInstance ();
XPath xpath = xpf.newXPath ();
XPathExpression xpathCompiled = xpath.compile (xpathString);
// use the first to recast and evaluate as NodeList
//Object atomOut = xpathCompiled.evaluate (
// new InputSource (atomIS), XPathConstants.NODESET);
String atomOut = xpathCompiled.evaluate (
new InputSource (atomIS), XPathConstants.STRING);
System.out.println (atomOut);
return atomOut;
}
I can see your problem here, the reason why these parsers are not producing the correct result is because contents of your <content> tag are not wrapped into <![CDATA[ ]]>, what I would do until I find more adequate solution I'd use quick and dirty trick :
private void parseFile(String fileName) throws IOException {
String line;
BufferedReader br = new BufferedReader(new FileReader(new File(fileName)));
StringBuilder sb = new StringBuilder();
boolean match = false;
while ((line = br.readLine()) != null) {
if(line.contains("<content")){
sb.append(line);
sb.append("\n");
match = true;
continue;
}
if(match){
sb.append(line);
sb.append("\n");
match = false;
}
if(line.contains("</content")){
sb.append(line);
sb.append("\n");
}
}
System.out.println(sb.toString());
}
This will give you all content in String. You can optionaly seperate them by slightly modyfiying this method or if you don't need actual <content> you can filter that out as well.
I'm using the Apache Commons Digester and trying to locate a particular tag in the structure to include in the object.
<parent>
<image size="small">some url</image>
<image size="medium">some url</image>
<image size="large">some url</image>
<image size="huge">some url</image>
</parent>
I really only want the medium image to be included in my partent object but I'm not sure how I would do that.
Right now I'm using digester.addBeanPropertySetter(PathToParent+"/image","image"); but this gets updated for every image tag (as it should).
Ideally I would like something like digester.addBeanPropertySetter(PathToParent+"/image/medium","image"); but you can't do that.
I omitted generic getters/setters.
public class Parent {
private Image image;
public void setImage(Image image) {
if ("medium".equals(image.getSize())) {
this.image = image;
}
}
}
public class Image {
private String size;
private String url;
}
public static void main(String[] args) throws IOException, SAXException {
String s = "<parent>"
+ "<image size='small'>some url1</image>"
+ "<image size='medium'>some url2</image>"
+ "<image size='large'>some url3</image>"
+ "<image size='huge'>some url4</image>"
+ "</parent>";
Digester digester = new Digester();
digester.addObjectCreate("parent", Parent.class);
digester.addFactoryCreate("parent/image", new ImageCreationFactory());
digester.addBeanPropertySetter("parent/image", "url");
digester.addSetNext("parent/image", "setImage");
Parent p = (Parent) digester.parse(new StringReader(s));
}
public class ImageCreationFactory implements ObjectCreationFactory {
public Object createObject(Attributes attributes) throws Exception {
Image i = new Image();
i.setSize(attributes.getValue("size"));
return i;
}
}
I actually figured this out using the xmlpullparser - here is the code to get the image attribute "large" only and ignore the rest - it's the last "if" in the case statement.
public class XmlPullFeedParser extends BaseFeedParser {
public XmlPullFeedParser(String feedUrl) {
super(feedUrl);
}
public ArrayList<Message> parse() {
ArrayList<Message> messages = null;
XmlPullParser parser = Xml.newPullParser();
try {
// auto-detect the encoding from the stream
parser.setInput(this.getInputStream(), null);
int eventType = parser.getEventType();
Message currentMessage = null;
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done){
String name = null;
String attrib = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
messages = new ArrayList<Message>();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
attrib = parser.getAttributeValue(0);
if (name.equalsIgnoreCase(EVENT)){
currentMessage = new Message();
} else if (currentMessage != null){
if (name.equalsIgnoreCase(WEBSITE)){
currentMessage.setWebsite(parser.nextText());
} else if (name.equalsIgnoreCase(DESCRIPTION)){
currentMessage.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(START_DATE)){
currentMessage.setDate(parser.nextText());
} else if (name.equalsIgnoreCase(TITLE)){
currentMessage.setTitle(parser.nextText());
} else if (name.equalsIgnoreCase(HEADLINER)){
currentMessage.setHeadliner(parser.nextText());
} else if ((name.equalsIgnoreCase(IMAGE)) && (attrib.equalsIgnoreCase("large"))) {
currentMessage.setImage(parser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(EVENT) && currentMessage != null){
messages.add(currentMessage);
} else if (name.equalsIgnoreCase(EVENTS)){
done = true;
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
Log.e("AndroidNews::PullFeedParser", e.getMessage(), e);
throw new RuntimeException(e);
}
return messages;
}
}
I do not think that it is possible. You have to write your own code to perform this kind of filtering.
But it is very simple. If you wish to create clean code write class named ImageAccessor with method getImage(String size). This method will get the data from digester and compare it with predefined size string (or pattern).