Valid RSS 2.0 Using Rome - java

Im using rome 1.0 to generate RSS for my java application.
In my java:
SyndFeed feed = new SyndFeedImpl();
feed.setFeedType( "rss_2.0" );
feed.setTitle( "My Site" );
feed.setLink( "http://example.com" );
feed.setDescription( "Test Site." );
List<SyndEntry> entries = new ArrayList<SyndEntry>();
SyndEntry entry = null;
SyndContent description = null;
entry = new SyndEntryImpl();
entry.setTitle( "Entry1" );
entry.setLink( "http://example.com/entry1" );
entry.setPublishedDate( new Date() );
description = new SyndContentImpl();
description.setType("text/html");
description.setValue( "This is the content of entry 1." );
entry.setDescription( description );
entries.add( entry );
feed.setEntries(entries);
Writer writer = new FileWriter("/home/jr/Desktop/stream.xml");
SyndFeedOutput output = new SyndFeedOutput();
output.output(feed,writer);
writer.close();
The generated RSS:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>My Site</title>
<link>http://example.com</link>
<description>Test Site.</description>
<item>
<title>Entry1</title>
<link>http://example.com/entry1</link>
<description>This is the content of entry 1.</description>
<pubDate>Fri, 09 Nov 2012 01:28:57 GMT</pubDate>
<guid>http://example.com/entry1</guid>
<dc:date>2012-11-09T01:28:57Z</dc:date>
</item>
</channel>
</rss>
When RSS is validated here, it has the following recommendations:
An item should not include both pubDate and dc:date
Missing atom:link with rel="self"
How to do the recommendation in rome library? Is the generated RSS ok?
Thanks.

In your custom SyndFeed class, make sure that you name your Date variable differently from what's on the SyndFeed class (Ie: instead of 'publishedDate', use something like 'pubDate'. This seems to have solved the issue for me.
public class CustomSyndFeed extends SyndFeedImpl {
protected Date pubDate;
#Override
public Date getPublishedDate() {
return pubDate;
}
#Override
public void setPublishedDate(final Date pubDate) {
this.pubDate = new Date(pubDate.getTime());
}
}

So this is happening because the SyndFeedImpl uses the same field for the date and publishedDate fields (from the DC Module) :
#Override
public Date getPublishedDate() {
return getDCModule().getDate();
}
#Override
public void setPublishedDate(final Date publishedDate) {
getDCModule().setDate(publishedDate);
}
Since the RSS093Generator (used by the RSS20Generator) creates a pubDate element from the specified item, but also inherits from the DCModuleGenerator, you get both this:
final Date pubDate = item.getPubDate();
if (pubDate != null) {
eItem.addContent(generateSimpleElement("pubDate", DateParser.formatRFC822(pubDate, Locale.US)));
}
and this:
final Date dcDate = dcModule.getDate();
if (dcDate != null) {
for (final Date date : dcModule.getDates()) {
element.addContent(generateSimpleElement("date", DateParser.formatW3CDateTime(date, Locale.US)));
}
}
This interaction can be prevented by implementing a custom SyndFeed of your own. In this case, all you need to do is create a class variable to store your pubDate so that the DCModule never gets a date set, and will therefore never generate your unwanted dc:date element.
I ran into the exact same problem and solved it by using this SyndFeed implementation:
public class CustomSyndFeed extends SyndFeedImpl {
protected Date publishedDate;
#Override
public Date getPublishedDate() {
return publishedDate;
}
#Override
public void setPublishedDate(final Date publishedDate) {
this.publishedDate = new Date(publishedDate.getTime());
}
}

Little late to the party, but no answer here works out of the box, so I figured I'd add mine.
As #Vitor points out in his comment, the correct way of doing this to extend SyndEntryImpl and use it as SyndEntry entry = new CustomEntryImpl();.
public class CustomEntryImpl extends SyndEntryImpl {
protected Date pubDate;
#Override
public Date getPublishedDate() {
return pubDate;
}
#Override
public void setPublishedDate(final Date pubDate) {
this.pubDate = new Date(pubDate.getTime());
}
}

Related

CassandraIO didn't work for saving Timestamp

Here it is my simple code, it read from pubsub subscription and save the body of the message to Cassandra table with current timestamp.
The message is consumed from subscription but there is no record insert to table and there is no error messages.
But if I change Date type "Timestamp" to Long in class TestTable, this code is working and insert the record to the table.
here it is the script to create the table.
DROP TABLE IF EXISTS test_table;
CREATE TABLE IF NOT EXISTS test_table(
post_index int,
ingestion_time TIMESTAMP,
body text,
PRIMARY KEY ((post_index))
);
#Table(keyspace = "{keyspace_name}", name = "{table_name}",
readConsistency = "LOCAL_QUORUM",
writeConsistency = "LOCAL_QUORUM",
caseSensitiveKeyspace = false,
caseSensitiveTable = false)
class TestTable implements Serializable {
#PartitionKey
#Column(name="post_index")
Integer postIndex;
#Column(name="ingestion_time")
Timestamp ingestionTime;
#Column(name = "body")
String body;
public Integer getPostIndex() {
return postIndex;
}
public void setPostIndex(Integer postIndex) {
this.postIndex = postIndex;
}
public Timestamp getIngestionTime() {
return ingestionTime;
}
public void setIngestionTime(Timestamp ingestionTime) {
this.ingestionTime = ingestionTime;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public TestTable(Integer postIndex, Timestamp ingestionTime, String body) {
this.body = body;
this.ingestionTime = ingestionTime;
this.postIndex = postIndex;
}
public TestTable() {
this.body = "";
this.ingestionTime = Timestamp.from(Instant.now());
this.postIndex = 0;
}
}
public class TestCassandraJobJava {
public static void main(String[] args) {
Pipeline pipeline = Pipeline.create(PipelineOptionsFactory.fromArgs(args).create());
PCollection<String> data = pipeline.apply("ReadStrinsFromPubsub",
PubsubIO.readStrings().fromSubscription("projects/{project_id}/subscriptions/{subscription_name}"))
.apply("window", Window.into(FixedWindows.of(Duration.standardSeconds(5))))
.apply("CreateMutation", ParDo.of(new DoFn<String, TestTable>() {
#ProcessElement
public void processElement(#Element String word, OutputReceiver<TestTable> out) {
TestTable t = new TestTable(new Random().nextInt(), java.sql.Timestamp.from(Instant.now()), word);
out.output(t);
}
})).apply(CassandraIO.<TestTable>write()
.withHosts(Arrays.asList("127.0.0.1"))
.withPort(9042)
.withKeyspace("{keyspace}")
.withLocalDc("Cassandra")
.withEntity(TestTable.class)
);
pipeline.run().waitUntilFinish();
}
}
To get this working you need to have a codec between the Cassandra's timestamp and java.sql.Timestamp. By default, in Java driver 3.x, the timestamp is converted into java.util.Date (see mapping), although you can also use Joda Time, or Java 8.x time API via extra codecs. And in Java driver 4.x, the Instant is used for representation of timestamps.
There is no built-in codec for java.sql.Timestamp, but it shouldn't be very hard to implement your own - the documentation describes process of custom codec creation & usage in much details.

Load all ResourceBundles and pick correct resource based on key and Locale

Okay, so I have been given this challenge to implement a "Service" that loads in all the resources for all locales that we support. Then it should be possible to pick they resource from correct ResourceBundle based on the key and the current Locale. How can I achieve this?
So this is how I have made my solution, I have a Service called TranslationService
public class TranslationService {
private List<ResourceBundle> resourceBundles;
public TranslationService(final Locale locale) {
ResourceBundle messageTexts = ResourceBundle.getBundle("MessageTexts", locale, new Utf8Control());
ResourceBundle notificationTexts = ResourceBundle.getBundle("NotificationTexts", locale, new Utf8Control());
ResourceBundle generalTexts = ResourceBundle.getBundle("GeneralTexts", locale, new Utf8Control());
Collections.addAll(this.resourceBundles, messageTexts, notificationTexts, generalTexts);
}
public String getText(String key) {
String text = null;
for (ResourceBundle resourceBundle : resourceBundles) {
try {
text = resourceBundle.getString(key);
} catch (MissingResourceException e) {
// DO NOTHING: If the key is not found in first resource means not that it isn't in the next
// check all resources for the key.
}
}
if (text == null) {
log.error("Could not find key {} in any resource.", key);
}
return text;
}
}
So what I want to achieve is to be able to load in all the specified Bundles for all supported Locales so to say I want to load in on initialization ex the MessageTexts_en_GB.properties, MessageTexts_fr_FR.properties, MessageTexts_ja_JP.properties etc. And then based on what locale is used and what key I am sending in I should be able to tell which Bundle to look into for the key without looping through all my Bundles. So to say if I get the Locale for fr_FR and the key PUSH_NOTIFICATION_REMINDER, then I would know that I have to lookup for the text in NotificationTexts_fr_FR.properties without having to loop through all the resources as I am doing. So is it even possible to do it like this or do I have to loop through all my resources as I am doing now, and if loading resources for all Locales is possible how would I eventually need to handle property naming clashes so I do not get the wrong language property?
So I am working currently on a solution which looks like this:
public class MyResourceBundle {
private Map<Locale, Map<String, String>> localeResources;
public MyResourceBundle() {
localeResources = new HashMap<>();
for (LocaleConfig config : LocaleConfig.values()) {
Map<String, String> resources = new HashMap<>();
ResourceBundle systemTexts = ResourceBundle.getBundle("SystemTexts", config.getLocale());
ResourceBundle translationTexts = ResourceBundle.getBundle("TranslationTexts", config.getLocale());
Enumeration systemKeys = systemTexts.getKeys();
while (systemKeys.hasMoreElements()) {
String key = (String) systemKeys.nextElement();
resources.put(key, systemTexts.getString(key));
}
Enumeration translationKeys = translationTexts.getKeys();
while (translationKeys.hasMoreElements()) {
String key = (String) translationKeys.nextElement();
resources.put(key, translationTexts.getString(key));
}
localeResources.put(config.getLocale(), resources);
}
}
public String getText(Locale locale, String key) {
String text = null;
text = localeResources.get(locale).get(key);
if (text == null) {
String errorMessage = "Key: " + key + " does not exist for locale " + locale.toString();
throw new MissingResourceException(errorMessage, this.getClass().getName(), key);
}
return text;
}
}
LocaleConfig.java :
public enum LocaleConfig {
DANISH("da", "DK"),
ENGLISH("en", "GB")
;
private String language;
private String country;
LocaleConfig(String language, String country) {
this.language = language;
this.country = country;
}
public Locale getLocale() {
return new Locale(language, country);
}
}
SystemTexts_da_DK.properties:
PERSON_1=Hans Hansen
PERSON_2=Anders Andersen
PERSON_3=Ib Ibsen
REMINDER_MESSAGE=Husk at teste...
SystemTexts_en_GB.properties:
PERSON_1=Frank Testerson
PERSON_2=Julie Testerson
PERSON_3=Test Testerson
REMINDER_MESSAGE=Remember to test...
TranslationTexts_da_DK.properties:
NOTE_NEW=Ny
NOTE_SEEN=Set
TranslationTexts_en_GB.properties:
NOTE_NEW=New
NOTE_SEEN=Seen
Now I can just call:
public class MyResourceBundleExample {
public static void main(String[] args) {
Locale locale = new Locale("da", "DK");
MyResourceBundle myResourceBundle = new MyResourceBundle();
System.out.println(myResourceBundle.getText(locale, "PERSON_3"));
}
}
Initial tests on this solution show that this would work fine, but if anyone has a better solution or a more smooth way of doing this I am all ears :).

JAK generated KML not work with Google My Maps

I write manually a KML file trying to import some polygons in MyMaps. This way works fine:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Document>
<Placemark>
<Style>
<PolyStyle>
<color>#a00000ff</color>
<outline>0</outline>
</PolyStyle>
</Style>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>9.184254,45.443636 9.183379,45.434288 9.224836,45.431499 9.184254,45.443636</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>
I try to write a java program using JAK that generate a most possibile equal file, but it doesn't work with Maps
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:kml xmlns:atom="http://www.w3.org/2005/Atom" xmlns:ns3="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:xal="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0">
<ns3:Document>
<ns3:Placemark>
<ns3:Style>
<ns3:PolyStyle>
<ns3:color>#EABCFF</ns3:color>
<ns3:outline>0</ns3:outline>
</ns3:PolyStyle>
</ns3:Style>
<ns3:Polygon>
<ns3:innerBoundaryIs>
<ns3:LinearRing>
<ns3:coordinates>9.184254,45.443636 9.183379,45.434288 9.224836,45.431499 9.184254,45.443636</ns3:coordinates>
</ns3:LinearRing>
</ns3:innerBoundaryIs>
</ns3:Polygon>
</ns3:Placemark>
</ns3:Document>
</ns3:kml>
That's program:
public static void main(String[] args) throws IOException {
// Style
PolyStyle polystyle = KmlFactory.createPolyStyle();
polystyle.setColor("#EABCFF");
// polystyle.setFill(true);
polystyle.setOutline(false);
//
Kml kml = KmlFactory.createKml();
Document document = kml.createAndSetDocument();
Placemark pm = document.createAndAddPlacemark();
LinearRing linearRing = pm.createAndSetPolygon().createAndAddInnerBoundaryIs().createAndSetLinearRing();
linearRing.addToCoordinates(9.184254, 45.443636, 0);
linearRing.addToCoordinates(9.183379, 45.434288, 0);
linearRing.addToCoordinates(9.224836, 45.431499, 0);
linearRing.addToCoordinates(9.184254, 45.443636, 0);
pm.createAndAddStyle().setPolyStyle(polystyle);
//
kml.marshal(new FileWriter("D:/prova.kml"));
}
I view <ns3: in your kml this make the kml invalid for google maps
Try to correct the file
I had the same problem.
Instead of using kml.marshal(new FileWriter("D:/prova.kml")); I did this...
String name = kml.getClass().getSimpleName();
if ("Kml".equals(name)) {
name = name.toLowerCase();
}
JAXBContext jaxbContext = JAXBContext.newInstance(Kml.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NameSpaceBeautyfier());
JAXBElement<Kml> jaxbKml = new JAXBElement<>(new QName("http://www.opengis.net/kml/2.2", name), (Class<Kml>) kml.getClass(), kml);
jaxbMarshaller.marshal(jaxbKml, file);
With a NameSpaceBeautifier like this ...
private static final class NameSpaceBeautyfier extends NamespacePrefixMapper {
private static final String KML_PREFIX = ""; // DEFAULT NAMESPACE
private static final String KML_URI= "http://www.opengis.net/kml/2.2";
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if(KML_URI.equals(namespaceUri)) {
return KML_PREFIX;
}
return suggestion;
}
#Override
public String[] getPreDeclaredNamespaceUris() {
return new String[] { KML_URI };
}
private NameSpaceBeautyfier() {
}
}
Hope this helps..

How to format xml instead of original format in springMVC (Restful webservice)

Currently, I want to return the return xml result with XML with the below format :
I tried to use something like this
#XmlRootElement(name = "item")
public class Book implements Serializable {
#XmlAttribute
public int getBookId() {
return bookId;
}
...
....
and
#XmlRootElement(name = "OneBoxResults")
public class JavaClazz {
private List<Book> OneBoxResults;
public List<Book> getOneBoxResults() {
return OneBoxResults;
}
#XmlElements(#XmlElement(name = "book", type = Book.class))
public void setOneBoxResults(List<Book> oneBoxResults) {
OneBoxResults = oneBoxResults;
}
...
However, the return result which I received is only Json format as below :
{"oneBoxResults":[{"bookId":1,"bookName":"Search
Deployment","update":"2014-01-07","description":"A successful deployment
typically involves the following
elements:","path":null},{"bookId":2,"bookName":"GSA
Information","update":"2015-01-07","description":"Configure the OneBox
module so it sends search queries to the provider (a custom
application","path":null}]}
I also attemped to create new format in controller as below :
#RequestMapping(value = "/rest.oneboxSample",produces = MediaType.APPLICATION_XML_VALUE, method = RequestMethod.GET)
public #ResponseBody String oneboxSample(){
String tmpOpenField = "<Field name=\"";
String tmpCloseField = "</Field>";
StringBuilder builder = new StringBuilder();
builder.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
builder.append("<OneBoxResults>").append("<resultCode>");
builder.append("Listbook").append("<resultCode>");
for(int i = 0; i < bookDao.getBooks().size(); i++){
Book tmpBook = bookDao.getBooks().get(i);
builder.append("<MODULE_RESULT>");
builder.append(tmpOpenField).append("bookId\">").append(tmpBook.getBookId()).append(tmpCloseField);
builder.append(tmpOpenField).append("bookName\">").append(tmpBook.getBookName()).append(tmpCloseField);
builder.append(tmpOpenField).append("update\">").append(tmpBook.getUpdate()).append(tmpCloseField);
builder.append(tmpOpenField).append("description\">").append(tmpBook.getDescription()).append(tmpCloseField);
builder.append(tmpOpenField).append("path\">").append(tmpBook.getPath()).append(tmpCloseField);
builder.append("</MODULE_RESULT>");
}
builder.append("</OneBoxResults>");
return builder.toString();
}
But the result is not good. It returned a string instead of xml format which we need.
Now, our system need to receive a xml format instead of an original xml format.
Please tell me know the way to do it .
The below is my source code which I wrote
https://www.dropbox.com/s/4tyg0kp7gkzodod/onebox-service.zip?dl=0
Thanks,

XML parsing problem in android using android.sax

I have an xml file as
<?xml version="1.0" encoding="utf-8"?>
<sections>
<section>
<name>Most Pouplar</name>
<items>
<item pos="1">
<name>
AcaiBerry Diet
</name>
<description>
<![CDATA[
Natrol AcaiBerry Diet supports weight loss goals when combined with a healthy reduced-calorie diet and exercise program. Acai is a wild fruit harvested in the rain forests of Brazil recognized for its high ORAC (oxygen-radical absorbance capacity) value - a measure of its antioxidant capacity. An adequate intake of antioxidants helps neutralize harmful free radicals that are produced by the body as a result of regular exercise.
]]>
</description>
</item>
<item pos="2">
<name>
AcaiBerry Weekend Cleanse
</name>
<description>
<![CDATA[
AcaiBerry Weekend Cleanse is a 3-step, easy-to-use cleansing program. Step 1 helps minimize occasional constipation/bloating, step 2 helps reduce toxins via antioxidant protection & cell regeneration and step 3 helps to restore the friendly bacteria that protect & strengthen the GI tract.
]]>
</description>
</item>
<item pos="4">
<name>
Carb Intercept Phase 2 + Chromium
</name>
<description>
<![CDATA[
Natrol Carb Intercept supports a low-carb lifestyle by controlling carbohydrates found in breads, cereals, rice, pasta and other starch-containing foods. Each serving provides 1,000mg of Phase 2 Carb Controller; a clinically tested ingredient that inhibits the enzyme responsible for digesting starch into simple sugars your body can absorb.
]]>
</description>
</item>
<item pos="3">
<name>
Resveratrol Diet
</name>
<description>
<![CDATA[
Losing weight has never been so rejuvenating! Natrol introduces Resveratrol Diet, a complex blend of antioxidants, enzymes and other nutrientsto help boost your metabolism and promote calorie burning.
]]>
</description>
</item>
</items>
</section>
<section>
<name>Least Popular</name>
<items>
<item pos="1">
<name>
Advanced Sleep Melatonin 10mg Maximum Strength
</name>
<description>
<![CDATA[
Getting a good night's sleep is even easier with Natrol Melatonin - a natural nightcap. A hormone found in the body, melatonin, helps promote more restful sleep. Natrol Melatonin provides relief for occasional sleeplessness, and helps promote a more relaxing night and better overall health.
]]>
</description>
</item>
<item pos="2">
<name>
Sleep 'N Restore
</name>
<description>
<![CDATA[
If you need to feel more rested due to lack of sleep, try Natrol Sleep 'N Restore. Sleep 'N Restore helps promote a more restful, deeper sleep, while supporting your body's natural restoration processes.* A combination of melatonin and valerian, this natural sleep aide includes antioxidants that can help your body protect its cells from damage to help you restore and recharge while you sleep.
]]>
</description>
</item>
</items>
</section>
</sections>
I defined a POJO as
public class ItemPojo {
//Fields of an item
private String itemName;
private String itemDescription;
private int itemPosition;
//Getters and Setters
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemDescription() {
return itemDescription;
}
public void setItemDescription(String itemDescription) {
this.itemDescription = itemDescription;
}
public int getItemPosition() {
return itemPosition;
}
public void setItemPosition(int itemPosition) {
this.itemPosition = itemPosition;
}
}
I am implementing a method for parsing xml file, but I have no idea about how can I read multiple <item> tag, which are within <items> tag.
Edited
I am putting part of code, which I am trying
//Store all items with a particular section
ArrayList<ItemPojo> itemList = new ArrayList<ItemPojo>();
//Store all items categorized by section
Map<String, ArrayList<ItemPojo>> itemStore = new HashMap<String, ArrayList<ItemPojo>>(1);
//Single item
ItemPojo currentItem = null;
//Current section name
String sectionName = null;
public AndroidSaxFeedParser() {
super();
}
public void parse() { //Map<String, ArrayList<ItemPojo>>
RootElement root = new RootElement(SECTIONS);
Element section = root.getChild(SECTION);
Element itemHeader = section.getChild(ITEM_HEADER);
//Read <name> tag as used as section
itemHeader.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
sectionName = body;
}
});
//TODO set item header here
Element items = section.getChild(ITEMS);
Element item = items.getChild(ITEM);
/*//Put all items of same category
items.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
//sort item with position
Collections.sort(itemList, ItemPojo.COMPARE_BY_POSITION);
//Putting it into master list
itemStore.put(sectionName, itemList);
//And clear the item list
itemList.clear();
}
});*/
item.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
currentItem = new ItemPojo();
Log.i("Test xml", "item initalised " + currentItem.toString());
}
});
item.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
// TODO Auto-generated method stub
itemList.add(currentItem);
Log.i("Test xml", "New items found " + currentItem.toString());
}
});
item.getChild(ITEM_NAME).setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
currentItem.setItemName(body);
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
currentItem.setItemDescription(body);
}
});
try {
Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
//return itemStore;
}
Now I am getting exception as
06-30 12:40:45.312: ERROR/AndroidRuntime(315): Uncaught handler: thread main exiting due to uncaught exception
06-30 12:40:45.342: ERROR/AndroidRuntime(315): java.lang.IllegalStateException: This element already has an end text element listener. It cannot have children.
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at android.sax.Element.getChild(Element.java:68)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at android.sax.Element.getChild(Element.java:60)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at org.us.ssg.AndroidSaxFeedParser.parse(AndroidSaxFeedParser.java:82)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at org.us.ssg.DesTestDemoActivity.checkXml(DesTestDemoActivity.java:109)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at org.us.ssg.DesTestDemoActivity.onClick(DesTestDemoActivity.java:81)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at android.view.View.performClick(View.java:2364)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at android.view.View.onTouchEvent(View.java:4179)
06-30 12:40:45.342: ERROR/AndroidRuntime(315): at android.widget.TextView.onTouchEvent(TextView.java:6541)
What I need
I need to read all items (with pos, name and description) and section. I am taking a HashMap, as key I am putting section and as value of that key I am puting an ArrayList of all items (with pos, name, description) related to that particular key (as section name).
You are well on your way. Next step is:
Define a startElementListener for you item element.
Like this:
item.setStartElementListener(new StartElementListener() {
#Override
public void start(Attributes attributes) {
myPojoItem = new PojoItem();
}
});
Define a endElementListener for you item element:
Like this:
item.setEndElementListener(new EndElementListener() {
#Override
public void end() {
itemList.add(myPojoItem);
}
});
For each of the children of item do something like the following:
itemName.setEndTextElementListener(new EndTextElementListener() {
#Override
public void end(String body) {
myPojoItem.setName(body);
}
});
finish with:
try {
Xml.parse(myXmlAsFileInputStream, Xml.Encoding.UTF_8, root.getContentHandler());
} catch (Exception e) {
e.printStackTrace();
}
Update: In response to comment by OP, here is how to access attributes of elements:
item.setStartElementListener(new StartElementListener() {
#Override
public void start(Attributes attributes) {
position = attributes.getValue("pos");
}
});
Final solution
From OP : I have done it with these way
AndroidSaxFeedParser.java
.
public class AndroidSaxFeedParser extends BaseFeedParser {
//Store all items with a particular section
ArrayList<ItemPojo> itemList = new ArrayList<ItemPojo>();
//Store all items categorized by section
Map<String, ArrayList<ItemPojo>> itemStore = new HashMap<String, ArrayList<ItemPojo>>(1);
//Single item
ItemPojo currentItem = null;
//Current section name
String sectionName = null;
public AndroidSaxFeedParser() {
super();
}
public Map<String, ArrayList<ItemPojo>> parse() {
RootElement root = new RootElement(SECTIONS);
Element section = root.getChild(SECTION);
Element itemHeader = section.getChild(ITEM_HEADER);
//Read <name> tag as used as section
itemHeader.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
sectionName = body.trim();
Log.i("New Section", "New section found : " + sectionName);
}
});
section.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
//Clear the item list
itemList = new ArrayList<ItemPojo>(0);
Log.i("Size of list", "Size : " +itemList.size());
}
});
section.setEndElementListener(new EndElementListener() {
public void end() {
//Putting it into master list
itemStore.put(sectionName, itemList);
}
});
Element items = section.getChild(ITEMS);
Element item = items.getChild(ITEM);
items.setEndElementListener(new EndElementListener() {
public void end() {
//sort item with position
Collections.sort(itemList, ItemPojo.COMPARE_BY_POSITION);
}
});
item.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
currentItem = new ItemPojo();
currentItem.setItemPosition(Integer.parseInt(attributes.getValue("pos")));
//Log.i("Test xml", "item initalised " + currentItem.toString());
}
});
item.setEndElementListener(new EndElementListener() {
public void end() {
itemList.add(currentItem);
Log.i("Test xml", "New items found " + currentItem.toString());
}
});
item.getChild(ITEM_NAME).setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
currentItem.setItemName(body.trim());
}
});
item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
currentItem.setItemDescription(body.trim());
}
});
try {
Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
return itemStore;
}
}
.
public abstract class BaseFeedParser implements FeedParser {
// names of the XML tags
static final String SECTIONS = "sections";
static final String SECTION = "section";
static final String ITEM_HEADER = "name";
static final String DESCRIPTION = "description";
static final String ITEM_NAME = "name";
static final String ITEM_POSITION = "pos";
static final String ITEM = "item";
static final String ITEMS = "items";
public InputStream inStream;
public BaseFeedParser() {
//super();
}
protected InputStream getInputStream() {
//Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(DesTestDemoActivity.INDEX_URL);
HttpResponse response = null;
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("request_for", "xml_data"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
if (entity != null)
inStream = entity.getContent();
return inStream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
.
public interface FeedParser {
Map<String, ArrayList<ItemPojo>> parse();
}
I have done with the help of you guys. So thank you all.
You don't seem to be using a SAX parser here but doing a DOM traveral.
If you want to parse the XML with a SAX parser, you need to initialize a SAXParser and define a ContentHandler where you will implement your parsing logic.
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
/** Send URL to parse XML Tags */
URL sourceUrl = new URL(xmlFile);
/** Create handler to handle XML Tags ( extends DefaultHandler ) */
MyXMLHandler myXMLHandler = new MyXMLHandler();
xr.setContentHandler(myXMLHandler);
xr.parse(new InputSource(sourceUrl.openStream()));
The ContentHandler has callbacks for when the parser reaches a start and end element. There you can put the logic required to fill up your POJO.
In your particular case, you need to check for the item tag and start filling up your POJOs.
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyXMLHandler extends DefaultHandler {
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (localName.equals("sometag")) {
// process tag
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// handle end element
}
}
There are several articles on the web with full code samples for this. Just google for Android and SAX Parser.
One example where an XML file (containing item elements) is parsed using SAX can be found here.

Categories