I have found several questions of the name question, but can't get any of them to work. What I want is to get the url of the media:thumbnail tag:
<media:thumbnail width="144" height="81" url="http://c.files.bbci.co.uk/6013/production/_88159542_3e6f2bc3-16a3-407d-9e07-62bae1fa755e.jpg"/>
Above the example of such tag
private void handleText(String text) {
String xmlText = text;
if (currentEntry != null && currentTag != null) {
if (currentTag.equals(TITLE)) {
currentEntry.setTitle(xmlText);
} else if (currentTag.equals(DESC)) {
currentEntry.setDescription(xmlText);
} else if (currentTag.equals(LINK)) {
currentEntry.setLink(xmlText);
} else if (currentTag.equals(IMAGE)) {
currentEntry.setImage("test");
}
}
}
I tried several things as:
xpp.getAttributeValue(null, "url"); and set the image as that. However I noticed that I am not even getting in that else if clause. I tried several values on the IMAGE variable like:
media:thumbnail
media
thumbnail
I have also set namespace aware:
factory.setNamespaceAware(true);
What am I doing wrong?
parser:
XmlPullParser xpp;
int eventType;
protected List<Entry> doInBackground(String... string) {
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
xpp = factory.newPullParser();
xpp.setInput(getInputStream(new URL("http://feeds.bbci.co.uk/news/technology/rss.xml?edition=uk")), "UTF_8");
eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
handleStartTag(xpp.getName());
} else if (eventType == XmlPullParser.END_TAG) {
currentTag = null;
} else if (eventType == XmlPullParser.TEXT) {
handleText(xpp.getText());
}
eventType = xpp.next();
}
} catch (Resources.NotFoundException e) {
Log.d(LOGTAG, e.getMessage());
} catch (XmlPullParserException e) {
Log.d(LOGTAG, e.getMessage());
} catch (IOException e) {
Log.d(LOGTAG, e.getMessage());
}
return entries;
}
I fixed it. I systemed out the start tags it was parsing and it showed up as: thumbnail. So I changed my IMAGE constant to have the value of "thumbnail". It never came in the thumbnail clause since the handleText method only handles found text in a tag. Since media:thumbnail has no text only attributes with values I needed to handle it in the handleStartTag method. There I could say if the current tag name equals "thumbnail" get the attribute value of url and setImage as that value.
Related
I am building an RSS feed parser using XmlPullParser in Android Studio. I would like to display the feed images in my app, however I am having trouble retrieving the url attribute value in the <media:thumbnail> tag. As a note: I am only retrieving things inside <item>. After doing considerable research, I learned it has something to do with XML namespaces. I setNamespaceAware(true), with no luck. All my other elements are being retrieved properly, but I keep getting null for my imageLink variable. I have also tried setting
else if (name.equalsIgnoreCase("media:thumbnail")) {
imageLink = xmlPullParser.getAttributeValue(null, "url");
}
to "media:thumbnail" or "thumbnail".
Link to the RSS feed: https://www.goal.com/feeds/en/news
A snippet of the XML code:
<item>
<title>
<![CDATA[Mexico boss Martino responds after USMNT's Berhalter calls on referee to take control of Gold Cup final]]>
</title>
<pubDate>Sat, 31 Jul 2021 20:30:03 GMT</pubDate>
<link>
<![CDATA[https://www.goal.com/en/news/mexico-boss-martino-responds-after-usmnts-berhalter-calls-on/1h5obazjxkl3c1hrevc53ovtfy]]>
</link>
<guid isPermaLink="false">urn:perform:article:1h5obazjxkl3c1hrevc53ovtfy</guid>
<description>
<![CDATA[The two managers went back and forth when discussing each team's ability to manipulate the match official]]>
</description>
<category>#Geo; Everywhere</category>
<category>#Targeting</category>
<category>#Google Newsstand</category>
<category>#Apple News</category>
<category>#News2021</category>
<category>#News - original</category>
<category>#Manager/coach quotes</category>
<media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
<media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
<media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
<media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
<media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
<media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
<media:content url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" type="image/jpeg" />
<media:thumbnail url="http://images.daznservices.com/di/library/GOAL/36/54/martino-berhalter-split_1bbaicsveobrw1xcg0fsjk04ra.png?t=43319131" />
<df:language>en</df:language>
<dc:language>en</dc:language>
<df:authors/>
<dc:creator/>
</item>
This is my code
public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException, IOException {
String title = null;
String link = null;
String description = null;
String imageLink = null;
boolean isItem = false;
List<RssFeedModel> items = new ArrayList<>();
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(inputStream, "UTF-8");
while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) {
int eventType = xmlPullParser.getEventType();
String name = xmlPullParser.getName();
if (name == null)
continue;
if (eventType == XmlPullParser.END_TAG) {
if (name.equalsIgnoreCase("item")) {
isItem = false;
}
continue;
}
if (eventType == XmlPullParser.START_TAG) {
if (name.equalsIgnoreCase("item")) {
isItem = true;
continue;
}
}
Log.d("MyXmlParser", "Parsing name ==> " + name);
String result = "";
if (xmlPullParser.next() == XmlPullParser.TEXT) {
result = xmlPullParser.getText();
xmlPullParser.nextTag();
}
if (name.equalsIgnoreCase("title")) {
title = result;
} else if (name.equalsIgnoreCase("link")) {
link = result;
} else if (name.equalsIgnoreCase("description")) {
description = result;
} else if (name.equalsIgnoreCase("thumbnail")) {//for image
imageLink = xmlPullParser.getAttributeValue(null, "url");
}
if (title != null && link != null && description != null) {
if (isItem) {
RssFeedModel item = new RssFeedModel(title, link, description, imageLink);
items.add(item);
} else {
mFeedTitle = title;
mFeedLink = link;
mFeedDescription = description;
}
}
}
return items;
} finally {
inputStream.close();
}
}
Just answering my own question for future reference:
public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException, IOException {
/**
* Declares the variables to hold article title, link and description
* Declares List to hold all items once parsed
*/
String title = null;
String link = null;
String description = null;
String imageLink = null;
List<RssFeedModel> items = new ArrayList<>();
/**Logic for parsing through the XML*/
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(inputStream, null);
/**Retrieves eventType (START_DOCUMENT, START_TAG, END_DOCUMENT)*/
int eventType = xpp.getEventType();
/**Only checks items that are within the <item></item> tags*/
boolean insideItem = false;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem) {
title = xpp.nextText();
}
} else if (xpp.getName().equalsIgnoreCase("description")) {
if (insideItem) {
description = xpp.nextText();
}
} else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem) {
link = xpp.nextText();
}
} else if (xpp.getName().equalsIgnoreCase("thumbnail")) {
if (insideItem) {
imageLink = xpp.getAttributeValue(null, "url");
}
}
/**Once cursor arrives at the END_TAG, save parsed items into List*/
} else if (eventType == XmlPullParser.END_TAG) {
if(xpp.getName().equalsIgnoreCase("item")){
if (insideItem) {
RssFeedModel item = new RssFeedModel(title, link, description, imageLink);
items.add(item);
}else if (xpp.getName().equalsIgnoreCase("channel")){
insideItem = false;
}
}
}
eventType = xpp.next();
}
return items;
} finally {
inputStream.close();
}
}
I made a string that contains part of xml that I am working on.
There are some integers in that file and I can not covert them from String to int. I try with getAttributeValue(0) but it didn`t work. So I was wondering if someone may have a solution for my problem. Thanks
import android.os.AsyncTask;
import android.util.Log;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
class ReadXMLFile extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
Log.d("beginning: ", "Pocetak");
//TODO - Call getFeeds Method to populate feeds list & return true/false depending on result of operation
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
String xmldata = <cenovnik>
<cenovnikStavkaList>
<id>12195432</id>
<izlaznaStanica>100</izlaznaStanica>
<kategorijaVozila>0</kategorijaVozila>
<ulaznaStanica>100</ulaznaStanica>
</cenovnikStavkaList>
<cenovnikStavkaList>
<id>12197782</id>
<izlaznaStanica>100</izlaznaStanica>
<kategorijaVozila>1</kategorijaVozila>
<ulaznaStanica>100</ulaznaStanica>
</cenovnikStavkaList>
xpp.setInput(new StringReader( xmldata ));
Log.d("step1a", "string");
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String tagname = xpp.getName();
if(eventType == XmlPullParser.START_DOCUMENT) {
Log.d("Step 2a: ","Start document");
} else if(eventType == XmlPullParser.START_TAG) {
Log.d("Step 2b: ", "Start tag " + xpp.getName());
if(xpp.getName().equals("cenovnikStavkaList")){
String testid = xpp.getAttributeValue(null, "id");
Log.d("Step 2d - ID: ", testid);
}
} else if(eventType == XmlPullParser.END_TAG) {
} else if(eventType == XmlPullParser.TEXT) {
Log.d("Step 2d: ", xpp.getText());
}
eventType = xpp.next();
}
Log.d("Step 2e: ", "End document");
Log.d("Step 2: ", "radi");
return true;
} catch (Exception e) {
return false;
}
}
#Override
protected void onPostExecute(Boolean result) {
if(result){
Log.d("END TEST","done");
}
}
public static InputStream getInputStream(URL url) {
try {
return url.openConnection().getInputStream();
} catch (IOException e) {
return null;
}
}
}
The numbers are inside leaf tags, like <id>12195432</id>.
The XML parsing events needs states, keeping data in variables.
Officially you could have several TEXTs inside two tags, hence:
StringBuilder text;
} else if(eventType == XmlPullParser.START_TAG) {
text = new StringBuilder();
} else if(eventType == XmlPullParser.TEXT) {
if (text != null) {
text.append(xpp.getText());
}
} else if(eventType == XmlPullParser.END_TAG) {
if (text != null) {
String s = text.toString();
try {
int n = Integer.parseInt(s);
// do something with number n
} catch (NumberFormatException e) {
// No number
}
text = null;
}
}
Create a new field cenovnikStavkaList with itself a field id for every same named tag, and do
cenovnikStavkaList.id = n;
and on END_TAG add it to a list.
I'm currently trying to parse some XML using XmlResourceParser and then show the information on a ListView using ArrayAdapter. The problem is, I don't get ant results.
My xml structure is like this:
<resources>
<categories>
<animal>
<word>
<english>Animal</english>
<french>Animal</french>
<spanish>Animal</spanish>
<portuguese>Animal</portuguese>
</word>
</animal>
<transportation></transportation>
<location></location>
<clothing></clothing>
<color></color>
<people></people>
<job></job>
<society></society>
<art></art>
<beverages></beverages>
<food></food>
<home></home>
<electronics></electronics>
<body></body>
<nature></nature>
<material></material>
<math></math>
<directions></directions>
<seasons></seasons>
<numbers></numbers>
<months></months>
<days></days>
<time></time>
<verbs></verbs>
<adjectives></adjectives>
</categories>
Now, each category will have different words on them but, at this moment I only want to get all the categories and show them in a ListView. To try and get all the categories I'm using the following code:
public class MainActivity extends ActionBarActivity {
private ListView list;
private ArrayList<String> arrayCategories;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
list = (ListView) findViewById(R.id.listView1);
try {
arrayCategories = parseCategories();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
R.id.listView1,
arrayCategories );
list.setAdapter(arrayAdapter);
} catch (IOException e) {
e.printStackTrace();
}
}
And the parseCategories function is the following:
private ArrayList<String> parseCategories() throws IOException {
ArrayList<String> categories = new ArrayList<String>();
XmlResourceParser parser = getResources().getXml(R.xml.database);
try {
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals("categories")) {
categories.add(parser.nextText());
}
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
Log.e("XmlPullParserException", e.toString());
}
parser.close();
return categories;
}
I'm still a little bit unexperienced when it comes to parse xml, can you guys help me with this one?
The problem is there is no "text" in the categories element; there are, however, many child elements.
The real task can be trivially summed up as:
How to get the names of all elements which are direct children of the categories element?
This problem is made a little bit complicated by XmlPullParser (using a DOM and/or XPath would be much easier), but it is doable. The trick here is to "skip" the subtrees by keeping a little depth counter; recursive functions would also work.
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG
&& parser.getName().equals("categories")) { // catergories start
int depth = 0;
eventType = parser.next();
while (!(depth == 0 && eventType == XmlPullParser.END_TAG)) { // end categories
if (eventType == XmlPullParser.START_TAG) {
if (depth == 0) { // direct child of categories
categories.add(parser.getName());
}
depth++;
} else if (eventType == XmlPullParser.END_TAG) { // depth > 0
depth--;
}
eventType = parser.next();
}
}
eventType = parser.next();
}
I have been creating an app recently that I am working on. The app simply shows the contents of a RSS feed in a ListView where the list items is clickable. It worked on Android 3.0 and below, but once i upgraded my app and device to 4.0 and above, it failed. I can see that I need to use a custom thread because of the NetworkOnMainThreadException, so I have chosen AsyncTask. I simply have a listview in my XML with id android:id/list and the code I use to load the feed looks like this:
//Load RSS news feed
// Initializing instance variables
headlines = new ArrayList();
links = new ArrayList();
try {
URL url = new URL("http://www.vg.no/rss/create.php?categories=25,10,49,26,23,20,21,12,32,30,34&keywords=85,98,1724,84,476,821,820,512,8317,343&limit=15");
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
// We will get the XML from an input stream
xpp.setInput(getInputStream(url), "UTF_8");
/* We will parse the XML content looking for the "<title>" tag which appears inside the "<item>" tag.
* However, we should take in consideration that the rss feed name also is enclosed in a "<title>" tag.
* As we know, every feed begins with these lines: "<channel><title>Feed_Name</title>...."
* so we should skip the "<title>" tag which is a child of "<channel>" tag,
* and take in consideration only "<title>" tag which is a child of "<item>"
*
* In order to achieve this, we will make use of a boolean variable.
*/
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, etc..
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem)
headlines.add(xpp.nextText()); //extract the headline
} else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem)
links.add(xpp.nextText()); //extract the link of article
}
}else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){
insideItem=false;
}
eventType = xpp.next(); //move to next element
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Binding data
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, headlines);
setListAdapter(adapter);
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Cannot load news, please check internett connection", Toast.LENGTH_LONG).show();
}
I have been trying to understand it; however, I cannot get it to work. If someone could please help me put all of this in AsyncTask and call the RSS refresh on onCreate() and on onClick() and explain how, it would be great.
Thanks!
this is a boilerplate inline AsyncTask method
new AsyncTask<Void, Void, Void>({
//initialize headlines here or outside of here or before this Asynctask
headlines = new ArrayList();
links = new ArrayList();
#Override
protected Void doInBackground(Void... params)
try {
URL url = new URL("http://www.vg.no/rss/create.php?categories=25,10,49,26,23,20,21,12,32,30,34&keywords=85,98,1724,84,476,821,820,512,8317,343&limit=15");
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(false);
XmlPullParser xpp = factory.newPullParser();
// We will get the XML from an input stream
xpp.setInput(getInputStream(url), "UTF_8");
/* We will parse the XML content looking for the "<title>" tag which appears inside the "<item>" tag.
* However, we should take in consideration that the rss feed name also is enclosed in a "<title>" tag.
* As we know, every feed begins with these lines: "<channel><title>Feed_Name</title>...."
* so we should skip the "<title>" tag which is a child of "<channel>" tag,
* and take in consideration only "<title>" tag which is a child of "<item>"
*
* In order to achieve this, we will make use of a boolean variable.
*/
boolean insideItem = false;
// Returns the type of current event: START_TAG, END_TAG, etc..
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
if (xpp.getName().equalsIgnoreCase("item")) {
insideItem = true;
} else if (xpp.getName().equalsIgnoreCase("title")) {
if (insideItem)
headlines.add(xpp.nextText()); //extract the headline
} else if (xpp.getName().equalsIgnoreCase("link")) {
if (insideItem)
links.add(xpp.nextText()); //extract the link of article
}
}else if(eventType==XmlPullParser.END_TAG && xpp.getName().equalsIgnoreCase("item")){
insideItem=false;
}
eventType = xpp.next(); //move to next element
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected Void onPostExecute() //UI THREAD STUFF , onPostExecute may need an argument, not sure yet though
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1, headlines);
setListAdapter(adapter);
}
}).execute();
good luck, you can put a loading progress bar in onPreExecute()
I'm trying to extract data from an Xml file, I followed this tutorial:
XmlPullParser tutorial
And now have the following code:
public void parse(InputStream is) {
// create new Study object to hold data
try {
// get a new XmlPullParser object from Factory
XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
// set input source
parser.setInput(is, null);
// get event type
int eventType = parser.getEventType();
// process tag while not reaching the end of document
while(eventType != XmlPullParser.END_DOCUMENT) {
switch(eventType) {
// at start of document: START_DOCUMENT
case XmlPullParser.START_DOCUMENT:
break;
// at start of a tag: START_TAG
case XmlPullParser.START_TAG:
// get tag name
String tagName = parser.getName();
Log.i("AT START TAG","AT START TAG..."+tagName);
// if <study>, get attribute: 'id'
if(tagName.equalsIgnoreCase("Date")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
eventDates.add(parser.nextText());
//study.mId = Integer.parseInt(parser.getAttributeValue(null, Study.ID));
}
// if <content>
else if(tagName.equalsIgnoreCase("Name")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
performanceNames.add(parser.nextText());
//study.mContent = parser.nextText();
}
// if <topic>
else if(tagName.equalsIgnoreCase("RequestURL")) {
Log.i("****PARSER INFO","TAG NAME="+tagName+"...."+parser.nextText());
eventsURLS.add(parser.nextText());
//study.mTopic = parser.nextText();
}
break;
}
// jump to next event
eventType = parser.next();
}
// exception stuffs
} catch (XmlPullParserException e) {
//study = null;
} catch (IOException e) {
//study = null;
}
// return Study object
}
For some reason, the code within the IF statements is not running even though I have made sure the tag names do equal the strings above.
What am I doing wrong?