I'm having a problem with SAX XML parser.
It Does parse everything, except quotation marks (").
For example, if the text is hell"3o in a node, the result is hell.
Here are my codes:
XML Handler:
public class MyXMLHandler extends DefaultHandler {
Boolean currentElement = false;
String currentValue = null;
public static SitesList sitesList = null;
public static SitesList getSitesList() {
return sitesList;
}
public static void setSitesList(SitesList sitesList) {
MyXMLHandler.sitesList = sitesList;
}
/** Called when tag starts ( ex:- <name>AndroidPeople</name>
* -- <name> )*/
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
currentElement = true;
if (localName.equals("channel"))
{
/** Start */
sitesList = new SitesList();
} else if (localName.equals("item")) {
String attr=attributes.getValue("item");
sitesList.setItem(attr);
} else if (localName.equals("title")) {
/** Get attribute value */
String attr = attributes.getValue("title");
sitesList.setTitle(attr);
}
else if (localName.equals("link")) {
/** Get attribute value */
String attr = attributes.getValue("link");
sitesList.setLink(attr);
}
else if (localName.equals("description")) {
/** Get attribute value */
String attr = attributes.getValue("description");
sitesList.setDescription(attr);
}
else if (localName.equalsIgnoreCase("pubDate")) {
/** Get attribute value */
String attr = attributes.getValue("pubDate");
sitesList.setPubDate(attr);
}
}
/** Called when tag closing ( ex:- <name>AndroidPeople</name>
* -- </name> )*/
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
currentElement = false;
/** set value */
if (localName.equalsIgnoreCase("item"))
sitesList.setItem(currentValue);
else if (localName.equalsIgnoreCase("title"))
sitesList.setTitle(currentValue);
else if (localName.equalsIgnoreCase("link"))
sitesList.setLink(currentValue);
else if (localName.equalsIgnoreCase("description"))
sitesList.setDescription(currentValue);
else if (localName.equalsIgnoreCase("pubDate"))
sitesList.setPubDate(currentValue);
}
/** Called to get tag characters ( ex:- <name>AndroidPeople</name>
* -- to get AndroidPeople Character ) */
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentElement) {
currentValue = new String(ch, start, length);
currentElement = false;
}
}
}
Getter and Setter:
import java.util.ArrayList;
/** Contains getter and setter method for variables */
public class SitesList {
/** Variables */
private ArrayList<String> title = new ArrayList<String>();
private ArrayList<String> link = new ArrayList<String>();
private ArrayList<String> description = new ArrayList<String>();
private ArrayList<String> pubDate = new ArrayList<String>();
private ArrayList<String> item=new ArrayList<String>();
/** In Setter method default it will return arraylist
* change that to add */
public ArrayList<String> getTitle() {
return title;
}
public void setTitle(String title) {
this.title.add(title);
}
public ArrayList<String> getLink() {
return link;
}
public void setLink(String link) {
this.link.add(link);
}
public ArrayList<String> getDescription() {
return description;
}
public void setDescription(String description) {
this.description.add(description);
}
public ArrayList<String> getPubDate() {
return this.pubDate;
}
public void setPubDate(String PubDate) {
this.pubDate.add(PubDate);
}
public ArrayList<String> getItem() {
return this.item;
}
public void setItem(String item) {
this.item.add(item);
}
}
And RSS Thread class:
public class RssThread {
private String title,html,pubDate;
public RssThread(String title,String html,String pubDate)
{
this.title=title;
this.html=html;
this.pubDate=CovertToDate(pubDate);
}
private String CovertToDate(String pubDate) {
// TODO Auto-generated method stub
//Wed, 28 Sep 2011 11:40:51//
String newDate="";
if (pubDate.substring(0,pubDate.indexOf(",")).equals("Sun"))
newDate+="יום ראשון";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Mon"))
newDate+="יום שני";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Tue"))
newDate+="יום שלישי";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Wed"))
newDate+="יום רביעי";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Thu"))
newDate+="יום חמישי";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Fri"))
newDate+="יום שישי";
else if (pubDate.subSequence(0, pubDate.indexOf(",")).equals("Sat"))
newDate+="יום שבת";
newDate+=", ";
String[] splited = pubDate.split(" ");
newDate += splited[1]+".";
if (splited[2].equals("Jan"))
newDate+="1.";
else if (splited[2].equals("Feb"))
newDate+="2.";
else if (splited[2].equals("Mar"))
newDate+="3.";
else if (splited[2].equals("Apr"))
newDate+="4.";
else if (splited[2].equals("May"))
newDate+="5.";
else if (splited[2].equals("Jun"))
newDate+="6.";
else if (splited[2].equals("Jul"))
newDate+="7.";
else if (splited[2].equals("Aug"))
newDate+="8.";
else if (splited[2].equals("Sep"))
newDate+="9.";
else if (splited[2].equals("Oct"))
newDate+="10.";
else if (splited[2].equals("Nov"))
newDate+="11.";
else if (splited[2].equals("Dec"))
newDate+="12.";
newDate+=splited[3];
newDate+=", בשעה "+splited[4].substring(0,splited[4].lastIndexOf(":"));
return newDate;
}
public String getTitle() {
return this.title;
}
public String getHTML() {
return html;
}
public String getPubDate() {
return this.pubDate;
}
}
I have forgotten to put another class:
public class XMLParsingExample {
private static String[] RssString;
/** Create Object For SiteList Class */
SitesList sitesList = null;
/** Called when the activity is first created. */
/** Create a new textview array to display the results */
String[] title;
String[] link;
String[] pubDate;
{
try {
/** Handling XML */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
/** Send URL to parse XML Tags */
URL sourceUrl = new URL(
"http://www.blich.co.il/rss.xml");
/** Create handler to handle XML Tags ( extends DefaultHandler ) */
MyXMLHandler myXMLHandler = new MyXMLHandler();
xr.setContentHandler(myXMLHandler);
xr.parse(new InputSource(sourceUrl.openStream()));
} catch (Exception e) {
System.out.println("XML Pasing Excpetion = " + e);
}
/** Get result from MyXMLHandler SitlesList Object */
sitesList = MyXMLHandler.sitesList;
/** Assign textview array lenght by arraylist size */
title = new String[sitesList.getTitle().size()];
link = new String[sitesList.getTitle().size()];
pubDate = new String[sitesList.getTitle().size()];
/** Set the result text in textview and add it to layout */
RssString=new String[sitesList.getItem().size()/2];
for (int i=0;i<RssString.length;i++)
RssString[i]="";
int counter=1;
for (int i = 0; i < sitesList.getItem().size(); i++) {
if (i%2!=0) {
title[i-counter]=sitesList.getTitle().get(i);
if (title[i-counter]!=null)
RssString[i-counter]+=title[i-counter]+"~";
link[i-counter]=sitesList.getLink().get(i);
if (link[i-counter]!=null)
RssString[i-counter]+=link[i-counter]+"~";
pubDate[i-counter]=sitesList.getPubDate().get(i);
if (pubDate[i-counter]!=null)
RssString[i-counter]+=pubDate[i-counter]+"~";
counter++;
}
}
}
public static String[] getRSSarray() {
return RssString;
}
}
I gave you all the codes so you can see everything.
the characters method can be called several times. try to look what you get in there and try to accumulate values in a stringbuffer
You can create an HTML object that will convert the HTML codes to the appropriate symbol (i.e. " to "), then convert that back to a String (or a SpannedString if you want to format it)
CharSequence seq = Html.fromHtml(title);
String str = new String(seq);
Maybe what both of you told me would work, but it would be complicated.
I have found an easier and more simple solution:
Other parser.
It uses 1 class (vs the sax parser that uses 3 classes), much much easier to understand, and of course, doesn't ignore quotation marks :D
Thanks anyway.
Have you tried to convert quotation marks to an XML entity, before you parse the element?
Several characters have special XML entity references:
& &
< <
> >
" "
' '
Related
Previously, I was able to display the data of one tag, but this time not several values are displayed, but only one.
This my parser code:
public class Runner {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
MyHandler handler = new MyHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse("src/countries.xml");
Countries branches = handler.getBranches();
try (FileWriter files = new FileWriter("src/diploma/SAX.txt")) {
files.write("Item " + "\n" + String.valueOf(branches.itemList) + "\n");
}
}
private static class MyHandler extends DefaultHandler{
static final String HISTORY_TAG = "history";
static final String ITEM_TAG = "item";
static final String NAME_ATTRIBUTE = "name";
public Countries branches;
public Item currentItem;
private String currencyElement;
Countries getBranches(){
return branches;
}
public void startDocument() throws SAXException {
}
#Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currencyElement = qName;
switch (currencyElement) {
case HISTORY_TAG: {
branches.itemList = new ArrayList<>();
currentItem = new Item();
currentItem.setHistoryName(String.valueOf(attributes.getValue(NAME_ATTRIBUTE)));
} break;
default: {}
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
String text = new String(ch, start, length);
if (text.contains("<") || currencyElement == null){
return;
}
switch (currencyElement) {
case ITEM_TAG: {
currentItem.setItem(text);
} break;
default: { }
}
}
#Override
public void endElement(String uri, String localName, String qName) throws SAXException{
switch (qName) {
case HISTORY_TAG: {
branches.itemList.add(currentItem);
currentItem = null;
} break;
default: {
}
}
currencyElement = null;
}
public void endDocument() throws SAXException {
System.out.println("SAX parsing is completed...");
}
}
}
Class Item:
public class Item {
private String historyName;
private String item;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getHistoryName() {
return historyName;
}
public void setHistoryName(String historyName) {
this.historyName = historyName;
}
#Override
public String toString() {
return
"historyName = " + historyName + ", " + "\n" + "item = " + item + ", ";
}
}
And class Countries
public class Countries {
public List<Item> itemList;
}
I have problems with this part
<history name="История">
<item>
История белорусских земель очень богата и самобытна.
</item>
<item>
Эту страну постоянно раздирали внутренние конфликты и противоречия, много раз она была втянута в войны.
</item>
<item>
В 1945 году Беларусь вступила в состав членов-основателей Организации Объединенных Наций.
</item>
</history>
I only display the last "item" tag, and other duplicate tags are displayed only in the singular. I can't figure out where the error is, but I noticed that in "endElement" all values are displayed, but as one element. Maybe someone knows what's the matter?
You are creating a new ArrayList every time you encounter the item tag.
That is why you only see one item displayed after parsing.
My implemented SAXParser class which uses URL address to process XML data does not returns the result. The class uses additional Currency class which in turn stores two variables currId and rate with setters/getters. When I run my class nothing shows up in java console. Here is the code:
public class MySAXParser extends DefaultHandler {
private static List<Currencies> currencies = new ArrayList<Currencies>();
private static Currencies curr = null;
private static String text = null;
public static void main(String[] args) {
String url = "http://nbt.tj/en/kurs/export_xml.php?date=2016-08-01&export=xmlout";
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
MySAXParser handler = new MySAXParser();
URL uri = new URL(url);
sp.parse(new InputSource(uri.openStream()), handler);
} catch (Exception ex) {
ex.printStackTrace();
}
for (Currencies curr : currencies) {
System.out.println(curr.toString());
}
}
public void startElement (String s, String s1, String elementName, Attributes atts) throws SAXException {
if (elementName.equalsIgnoreCase("valute")) {
curr = new Currencies();
curr.setCurrId(atts.getValue("id"));
}
}
public void endElement (String s, String s1, String element) throws SAXException {
if (element.equals("valute")) {
currencies.add(curr);
}
if (element.equalsIgnoreCase("value")) {
curr.setRate(Double.parseDouble(text));
}
}
#Override
public void characters (char[] ch, int start, int length) throws SAXException {
text = String.copyValueOf(ch, start, length).trim();
}
}
So, what I missed or doing wrong? Any help would be appreciated.
Here is my attempt that works fine with Java 1.8:
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MySAXParser extends DefaultHandler {
private List<Currency> currencies = new ArrayList<>();
private Currency curr = null;
private StringBuilder sb;
public static void main(String[] args) {
String url = "http://nbt.tj/en/kurs/export_xml.php?date=2016-08-01&export=xmlout";
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
SAXParser sp = spf.newSAXParser();
MySAXParser handler = new MySAXParser();
sp.parse(new InputSource(url), handler);
for (Currency curr : handler.getCurrencies()) {
System.out.println(curr.toString());
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public List<Currency> getCurrencies() {
return currencies;
}
#Override
public void startElement(String s, String localName, String elementName, Attributes atts) throws SAXException {
if (elementName.equalsIgnoreCase("valute")) {
curr = new Currency();
currencies.add(curr);
curr.setCurrId(atts.getValue("ID"));
} else if (elementName.equalsIgnoreCase("value") || elementName.equalsIgnoreCase("CharCode")) {
sb = new StringBuilder();
}
}
#Override
public void endElement(String s, String localName, String elementName) throws SAXException {
if (elementName.equalsIgnoreCase("value")) {
curr.setRate(Double.parseDouble(sb.toString()));
sb = null;
}
else if (elementName.equalsIgnoreCase("CharCode")) {
curr.setCharCode(sb.toString());
sb = null;
}
}
#Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (sb != null) {
sb.append(ch, start, length);
}
}
}
The class is
public class Currency {
private String currId;
/**
* Get the value of currId
*
* #return the value of currId
*/
public String getCurrId() {
return currId;
}
/**
* Set the value of currId
*
* #param currId new value of currId
*/
public void setCurrId(String currId) {
this.currId = currId;
}
private double rate;
/**
* Get the value of rate
*
* #return the value of rate
*/
public double getRate() {
return rate;
}
/**
* Set the value of rate
*
* #param rate new value of rate
*/
public void setRate(double rate) {
this.rate = rate;
}
private String charCode;
/**
* Get the value of charCode
*
* #return the value of charCode
*/
public String getCharCode() {
return charCode;
}
/**
* Set the value of charCode
*
* #param charCode new value of charCode
*/
public void setCharCode(String charCode) {
this.charCode = charCode;
}
#Override
public String toString() {
return "Currency{" + "currId=" + currId + ", rate=" + rate + ", charCode=" + charCode + '}';
}
}
A sample output I get is
Currency{currId=840, rate=7.8683, charCode=USD}
Currency{currId=978, rate=8.7448, charCode=EUR}
Currency{currId=960, rate=10.9395, charCode=XDR}
Currency{currId=156, rate=1.1828, charCode=CNY}
Currency{currId=756, rate=8.075, charCode=CHF}
Currency{currId=810, rate=0.1146, charCode=RUB}
Currency{currId=860, rate=0.2655, charCode=UZS}
Currency{currId=417, rate=1.1643, charCode=KGS}
Currency{currId=398, rate=0.2234, charCode=KZT}
Currency{currId=933, rate=3.9424, charCode=BYR}
Currency{currId=364, rate=0.2617, charCode=IRR}
Currency{currId=971, rate=1.139, charCode=AFN}
Currency{currId=586, rate=0.7504, charCode=PKR}
Currency{currId=949, rate=2.6076, charCode=TRY}
Currency{currId=934, rate=2.2481, charCode=TMT}
Currency{currId=826, rate=10.3618, charCode=GBP}
Currency{currId=36, rate=5.9162, charCode=AUD}
Currency{currId=208, rate=1.1755, charCode=DKK}
Currency{currId=352, rate=0.659, charCode=ISK}
Currency{currId=124, rate=5.9699, charCode=CAD}
Currency{currId=414, rate=26.004, charCode=KWD}
Currency{currId=578, rate=0.9193, charCode=NOK}
Currency{currId=702, rate=5.8215, charCode=SGD}
Currency{currId=752, rate=0.9136, charCode=SEK}
Currency{currId=392, rate=0.761, charCode=JPY}
Currency{currId=944, rate=4.9639, charCode=AZN}
Currency{currId=51, rate=1.6516, charCode=AMD}
Currency{currId=981, rate=3.3539, charCode=GEL}
Currency{currId=498, rate=0.3979, charCode=MDL}
Currency{currId=980, rate=0.317, charCode=UAH}
Currency{currId=784, rate=2.1421, charCode=AED}
Currency{currId=682, rate=2.0979, charCode=SAR}
Currency{currId=356, rate=1.175, charCode=INR}
Currency{currId=985, rate=2.0039, charCode=PLN}
Currency{currId=458, rate=1.9313, charCode=MYR}
Currency{currId=764, rate=0.2258, charCode=THB}
I have this string coming from my dataBase:
<user>
<name>John</name>
<surname>Shean</surname>
<birthdate>1/1/1111</birthdate>
<phone >(555) 444-1111</phone>
<city>NY</city>
</user>
I need to parse it and add to:
arrayList<User>.(User(name,surname,...))
It should end up looking like this:
user[1]={name="John",surname="Shena",...}
I used the following method but it isn't working right. Does anyone have a method to will do this?
public User parseList(String array) {
User user = new User();
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
URL u = new URL("xmldb:exist://192.168.1.71:8094/exist/xmlrpc/db/testDB/userInformation.xml");
Document doc = builder.parse(u.openStream());
NodeList nodes = doc.getElementsByTagName("user");
Element element = (Element) nodes.item(0);
user.setName(getElementValue(element, "name"));
user.setSurname(getElementValue(element, "surname"));
user.setBirthdate(getElementValue(element, "birthdate"));
user.setPhone(getElementValue(element, "phone"));
user.setCity(getElementValue(element, "city"));
System.out.println(user);
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
protected String getElementValue(Element parent, String label) {
return getCharacterDataFromElement((Element) parent.getElementsByTagName(label).item(0));
}
private String getCharacterDataFromElement(Element e) {
try {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
} catch (Exception ex) {
}
return "";
}
1 - model your use class:
package com.howtodoinjava.xml.sax;
/**
* Model class. Its instances will be populated using SAX parser.
* */
public class User
{
//XML attribute id
private int id;
//XML element name
private String Name;
//XML element surname
private String SurName;
//...
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public String getSurName() {
return SurName;
}
public void setSurName(String SurName) {
this.SurName = SurName;
}
// [...]
#Override
public String toString() {
return this.id + ":" + this.Name + ":" +this.SurName ;
}
}
2 - Build the handler by extending DefaultParser
package com.howtodoinjava.xml.sax;
import java.util.ArrayList;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class UserParserHandler extends DefaultHandler
{
//This is the list which shall be populated while parsing the XML.
private ArrayList userList = new ArrayList();
//As we read any XML element we will push that in this stack
private Stack elementStack = new Stack();
//As we complete one user block in XML, we will push the User instance in userList
private Stack objectStack = new Stack();
public void startDocument() throws SAXException
{
//System.out.println("start of the document : ");
}
public void endDocument() throws SAXException
{
//System.out.println("end of the document document : ");
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
//Push it in element stack
this.elementStack.push(qName);
//If this is start of 'user' element then prepare a new User instance and push it in object stack
if ("user".equals(qName))
{
//New User instance
User user = new User();
//Set all required attributes in any XML element here itself
if(attributes != null && attributes.getLength() == 1)
{
user.setId(Integer.parseInt(attributes.getValue(0)));
}
this.objectStack.push(user);
}
}
public void endElement(String uri, String localName, String qName) throws SAXException
{
//Remove last added element
this.elementStack.pop();
//User instance has been constructed so pop it from object stack and push in userList
if ("user".equals(qName))
{
User object = this.objectStack.pop();
this.userList.add(object);
}
}
/**
* This will be called everytime parser encounter a value node
* */
public void characters(char[] ch, int start, int length) throws SAXException
{
String value = new String(ch, start, length).trim();
if (value.length() == 0)
{
return; // ignore white space
}
//handle the value based on to which element it belongs
if ("name".equals(currentElement()))
{
User user = (User) this.objectStack.peek();
user.setName(value);
}
else if ("surname".equals(currentElement()))
{
User user = (User) this.objectStack.peek();
user.setSurName(value);
}
}
/**
* Utility method for getting the current element in processing
* */
private String currentElement()
{
return this.elementStack.peek();
}
//Accessor for userList object
public ArrayList getUsers()
{
return userList;
}
}
3 - Write parser for xml file
package com.howtodoinjava.xml.sax;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class UsersXmlParser
{
public ArrayList parseXml(InputStream in)
{
//Create a empty link of users initially
ArrayList<user> users = new ArrayList</user><user>();
try
{
//Create default handler instance
UserParserHandler handler = new UserParserHandler();
//Create parser from factory
XMLReader parser = XMLReaderFactory.createXMLReader();
//Register handler with parser
parser.setContentHandler(handler);
//Create an input source from the XML input stream
InputSource source = new InputSource(in);
//parse the document
parser.parse(source);
//populate the parsed users list in above created empty list; You can return from here also.
users = handler.getUsers();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
return users;
}
}
4 - Test parser
package com.howtodoinjava.xml.sax;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
public class TestSaxParser
{
public static void main(String[] args) throws FileNotFoundException
{
//Locate the file OR String
File xmlFile = new File("D:/temp/sample.xml");
//Create the parser instance
UsersXmlParser parser = new UsersXmlParser();
//Parse the file Or change to parse String
ArrayList users = parser.parseXml(new FileInputStream(xmlFile));
//Verify the result
System.out.println(users);
}
}
If you want to parse XML, you can use an XML parser.
This may help you:
Java:XML Parser
I have the following problem:
I am using an XML SAXParser to parse an xml file and create dynamicly classes and set their properties.
I have written code that works now to make 4 classes and set the properiets of the classes but the problem is that the code is one big conditional case (if/else if/else) and that it is very difficult to read.
I would like to parse the xml so I can create 15 different classes, so the code is getting very big.
Now the exact question is how to refactor the if/elseif/else to better readable code? I've searched around for a while now and found some methods like using a map or the command pattern but I don't understand how to use this?
This is the code I'm currently using and that is working:
public class XmlParserSax extends DefaultHandler {
List<Fragment> fragments = null;
String atType = null;
String typeObject;
String currentelement = null;
String atColor = null;
RouteFragment route = null;
ChapterFragment chapter = null;
FirstFragment first = null;
ExecuteFragment execute = null;
StringBuilder textBuilder;
public XmlParserSax() {
fragments = new ArrayList<Fragment>();
try {
/**
* Create a new instance of the SAX parser
**/
SAXParserFactory saxPF = SAXParserFactory.newInstance();
SAXParser sp = saxPF.newSAXParser();
XMLReader xr = sp.getXMLReader();
/**
* Create the Handler to handle each of the XML tags.
**/
String file = "assets/test.xml";
InputStream in = this.getClass().getClassLoader()
.getResourceAsStream(file);
xr.setContentHandler(this);
xr.parse(new InputSource(in));
} catch (Exception e) {
System.out.println(e);
}
}
#Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
atColor = attributes.getValue("color");
atType = attributes.getValue("type");
currentelement = localName;
textBuilder = new StringBuilder();
if (localName.equalsIgnoreCase("template")) {
if (atType.equalsIgnoreCase("route")) {
route = new RouteFragment();
typeObject = "route";
} else if (atType.equalsIgnoreCase("chapter")) {
chapter = new ChapterFragment();
typeObject = "chapter";
} else if (atType.equalsIgnoreCase("first")) {
first = new FirstFragment();
typeObject = "first";
} else if (atType.equalsIgnoreCase("execute")) {
execute = new ExecuteFragment();
typeObject = "execute";
}
} else if (localName.equalsIgnoreCase("number")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setNumberTextcolor("#" + atColor);
}
} else if (localName.equalsIgnoreCase("maxnumber")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setMaxNumberColor("#" + atColor);
}
} else if (localName.equalsIgnoreCase("title")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setTitleColor("#" + atColor);
} else if (typeObject.equalsIgnoreCase("first")) {
first.setTitleColor("#" + atColor);
}
} else if (localName.equalsIgnoreCase("subtitle")) {
if (typeObject.equalsIgnoreCase("first")) {
first.setSubtitleColor("#" + atColor);
}
} else if (localName.equalsIgnoreCase("text")) {
if (typeObject.equalsIgnoreCase("execute")) {
execute.setTextColor("#" + atColor);
}
}
}
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
String text = textBuilder.toString();
if (localName.equalsIgnoreCase("template")) {
if (typeObject.equalsIgnoreCase("route")) {
fragments.add(route); // nieuw routefragment
// toevoegen aan de lijst
} else if (typeObject.equalsIgnoreCase("chapter")) {
fragments.add(chapter); // nieuw chapterfragment
// toevoegen aan de lijst
} else if (typeObject.equalsIgnoreCase("first")) {
fragments.add(first);
} else if (typeObject.equalsIgnoreCase("execute")) {
fragments.add(execute);
}
} else if (localName.equalsIgnoreCase("text")) {
if (typeObject.equalsIgnoreCase("route")) {
// route.setOmschrijving(text);
} else if (typeObject.equalsIgnoreCase("execute")) {
execute.setText(text);
}
} else if (localName.equalsIgnoreCase("background")) {
if (typeObject.equalsIgnoreCase("route")) {
// route.setKleur("#" + text);
} else if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setBackgroundColor("#" + text);
} else if (typeObject.equalsIgnoreCase("first")) {
first.setBackgroundColor("#" + text);
} else if (typeObject.equalsIgnoreCase("execute")) {
execute.setBackgroundColor("#" + text);
}
} else if (localName.equalsIgnoreCase("number")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setNumber(text);
}
} else if (localName.equalsIgnoreCase("maxnumber")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setMaxNumber(text);
}
} else if (localName.equalsIgnoreCase("title")) {
if (typeObject.equalsIgnoreCase("chapter")) {
chapter.setTitle(text);
} else if (typeObject.equalsIgnoreCase("first")) {
first.setTitle(text);
}
} else if (localName.equalsIgnoreCase("subtitle")) {
if (typeObject.equalsIgnoreCase("first")) {
first.setSubtitle(text);
}
} else if (localName.equalsIgnoreCase("square")) {
if (typeObject.equalsIgnoreCase("execute")) {
execute.setBorderColor("#" + text);
}
}
}
public List<Fragment> getList() {
return fragments;
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
textBuilder.append(ch, start, length);
}
}
There is another way of doing this; using startElementListener and EndTextElementListeners
First define your root element:
RootElement root = new RootElement("root");
Define your child elements
Element nodeA = root.getChild("nodeA");
Element nodeB = root.getChild("nodeB");
Element nodeC = root.getChild("nodeC");
Now set the listeners
root.setStartElementListener(new StartElementListener() {
public void start(Attributes attributes) {
foundElement = true;// tells you that you are parsing the intended xml
}
});
nodeA.setEndTextElementListener(new EndTextElementListener() {
public void end(String body) {
//populate your pojo
}
});
This way you can do away with all those if-else statements and booleans, but you have to live with the N number of listeners.
I have the ff. XML from a URL:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<Phonebook>
<PhonebookEntry>
<firstname>Michael</firstname>
<lastname>De Leon</lastname>
<Address>5, Cat Street</Address>
</PhonebookEntry>
<PhonebookEntry>
<firstname>John</firstname>
<lastname>Smith</lastname>
<Address>6, Dog Street</Address>
</PhonebookEntry>
</Phonebook>
I want to display both PhonebookEntry values (firstname,lastname,Address). Currently, my code displays only the PhonebookEntry of John Smith (the last entry). Here's my code.
ParsingXML.java
package com.example.parsingxml;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class ParsingXML extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* Create a new TextView to display the parsingresult later. */
TextView tv = new TextView(this);
try {
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://somedomain.com/jm/sampleXML.xml");
URLConnection ucon = url.openConnection();
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
ExampleHandler myExampleHandler = new ExampleHandler();
xr.setContentHandler(myExampleHandler);
/* Parse the xml-data from our URL. */
xr.parse(new InputSource(url.openStream()));
/* Parsing has finished. */
/* Our ExampleHandler now provides the parsed data to us. */
ParsedExampleDataSet parsedExampleDataSet =
myExampleHandler.getParsedData();
/* Set the result to be displayed in our GUI. */
tv.setText(parsedExampleDataSet.toString());
} catch (Exception e) {
/* Display any Error to the GUI. */
tv.setText("Error: " + e.getMessage());
}
/* Display the TextView. */
this.setContentView(tv);
}
}
ExampleHandler.java
package com.example.parsingxml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ExampleHandler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private boolean in_outertag = false;
private boolean in_innertag = false;
private boolean in_firstname = false;
private boolean in_lastname= false;
private boolean in_Address=false;
private ParsedExampleDataSet myParsedExampleDataSet = new ParsedExampleDataSet();
// ===========================================================
// Getter & Setter
// ===========================================================
public ParsedExampleDataSet getParsedData() {
return this.myParsedExampleDataSet;
}
// ===========================================================
// Methods
// ===========================================================
#Override
public void startDocument() throws SAXException {
this.myParsedExampleDataSet = new ParsedExampleDataSet();
}
#Override
public void endDocument() throws SAXException {
// Nothing to do
}
/** Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">*/
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equals("PhoneBook")) {
this.in_outertag = true;
}else if (localName.equals("PhonebookEntry")) {
this.in_innertag = true;
}else if (localName.equals("firstname")) {
this.in_firstname = true;
}else if (localName.equals("lastname")) {
this.in_lastname= true;
}else if(localName.equals("Address")) {
this.in_Address= true;
}
}
/** Gets be called on closing tags like:
* </tag> */
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("Phonebook")) {
this.in_outertag = false;
}else if (localName.equals("PhonebookEntry")) {
this.in_innertag = false;
}else if (localName.equals("firstname")) {
this.in_firstname = false;
}else if (localName.equals("lastname")) {
this.in_lastname= false;
}else if(localName.equals("Address")) {
this.in_Address= false;
}
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
#Override
public void characters(char ch[], int start, int length) {
if(this.in_firstname){
myParsedExampleDataSet.setfirstname(new String(ch, start, length));
}
if(this.in_lastname){
myParsedExampleDataSet.setlastname(new String(ch, start, length));
}
if(this.in_Address){
myParsedExampleDataSet.setAddress(new String(ch, start, length));
}
}
}
ParsedExampleDataSet.java
package com.example.parsingxml;
public class ParsedExampleDataSet {
private String firstname = null;
private String lastname=null;
private String Address=null;
//Firstname
public String getfirstname() {
return firstname;
}
public void setfirstname(String firstname) {
this.firstname = firstname;
}
//Lastname
public String getlastname(){
return lastname;
}
public void setlastname(String lastname){
this.lastname=lastname;
}
//Address
public String getAddress(){
return Address;
}
public void setAddress(String Address){
this.Address=Address;
}
public String toString(){
return "Firstname: " + this.firstname + "\n" + "Lastname: " + this.lastname + "\n" + "Address: " + this.Address;
}
}
I'm new to java and android dev, many thanks in advance for any help! :)
The other responses have already pointed out that you require a list to store all the ParsedExampleDataSet objects gotten from the XML.
But I want to point your attention to another thing about XML handlers which may bite you only later (and randomly). The characters method is not a good place to assign the values found between tags in you XML, because the characters method is not guaranteed to return all the characters in an element at once. It may be called multiple times within the same element to report characters found so far. With your implementation as it is right now, you will end up with missing data and wonder what is going on.
That said, what I would do it use a StringBuilder to accumulate your characters and then assign them in an endElement(...) call. Like so:
public class ExampleHandler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private StringBuilder mStringBuilder = new StringBuilder();
private ParsedExampleDataSet mParsedExampleDataSet = new ParsedExampleDataSet();
private List<ParsedExampleDataSet> mParsedDataSetList = new ArrayList<ParsedExampleDataSet>();
// ===========================================================
// Getter & Setter
// ===========================================================
public List<ParsedExampleDataSet> getParsedData() {
return this.mParsedDataSetList;
}
// ===========================================================
// Methods
// ===========================================================
/** Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">*/
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equals("PhonebookEntry")) {
this.mParsedExampleDataSet = new ParsedExampleDataSet();
}
}
/** Gets be called on closing tags like:
* </tag> */
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("PhonebookEntry")) {
this.mParsedDataSetList.add(mParsedExampleDataSet);
}else if (localName.equals("firstname")) {
mParsedExampleDataSet.setfirstname(mStringBuilder.toString().trim());
}else if (localName.equals("lastname")) {
mParsedExampleDataSet.setlastname(mStringBuilder.toString().trim());
}else if(localName.equals("Address")) {
mParsedExampleDataSet.setAddress(mStringBuilder.toString().trim());
}
mStringBuilder.setLength(0);
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
#Override
public void characters(char ch[], int start, int length) {
mStringBuilder.append(ch, start, length);
}
}
You can then retrieve the list of ParsedExampleDataSets in your activity and either display in multiple text views or only in one. Your Activity.onCreate(...) method may look like:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
/* Create a new TextView to display the parsingresult later. */
TextView tv = new TextView(this);
try {
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://somedomain.com/jm/sampleXML.xml");
URLConnection ucon = url.openConnection();
/* Create a new ContentHandler and apply it to the XML-Reader*/
ExampleHandler myExampleHandler = new ExampleHandler();
//remember to import android.util.Xml
Xml.parse(url.openStream(), Xml.Encoding.UTF_8, myExampleHandler);
/* Our ExampleHandler now provides the parsed data to us. */
List<ParsedExampleDataSet> parsedExampleDataSetList =
myExampleHandler.getParsedData();
/* Set the result to be displayed in our GUI. */
for(ParsedExampleDataSet parsedExampleDataSet : parsedExampleDataSetList){
tv.append(parsedExampleDataSet.toString());
}
} catch (Exception e) {
/* Display any Error to the GUI. */
tv.setText("Error: " + e.getMessage());
}
/* Display the TextView. */
this.setContentView(tv);
}
You only have one ParsedExampleDataSet object in your handler, so there's only room to store one entry. Change ExampleHandler to have an ArrayList<ParsedExampleDataSet> results and also a ParsedExampleDataSet currentSet. Inside startElement, when you see the PhoneBook tag, set currentSet to a new instance of ParsedExampleDataSet and add it to results. After parsing, results should contain everything you want.
You were close. Since you have many PhoneBookeEntrys you need to store them somewhere:
public class ExampleHandler extends DefaultHandler{
// ===========================================================
// Fields
// ===========================================================
private boolean in_outertag = false;
private boolean in_innertag = false;
private boolean in_firstname = false;
private boolean in_lastname= false;
private boolean in_Address=false;
private ParsedExampleDataSet myParsedExampleDataSet = new ParsedExampleDataSet();
private List<ParsedExampleDataSet> allSets = new ArrayList<ParsedExampleDataSet>();
// ===========================================================
// Getter & Setter
// ===========================================================
public ParsedExampleDataSet getParsedData() {
return this.myParsedExampleDataSet;
}
// ===========================================================
// Methods
// ===========================================================
/** Gets be called on opening tags like:
* <tag>
* Can provide attribute(s), when xml was like:
* <tag attribute="attributeValue">*/
#Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equals("PhoneBook")) {
this.in_outertag = true;
}else if (localName.equals("PhonebookEntry")) {
this.in_innertag = true;
this.myParsedExampleDataSet = new ParsedExampleDataSet();
}else if (localName.equals("firstname")) {
this.in_firstname = true;
}else if (localName.equals("lastname")) {
this.in_lastname= true;
}else if(localName.equals("Address")) {
this.in_Address= true;
}
}
/** Gets be called on closing tags like:
* </tag> */
#Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (localName.equals("Phonebook")) {
this.in_outertag = false;
}else if (localName.equals("PhonebookEntry")) {
this.in_innertag = false;
allSets.add(myParsedExampleDataSet);
}else if (localName.equals("firstname")) {
this.in_firstname = false;
}else if (localName.equals("lastname")) {
this.in_lastname= false;
}else if(localName.equals("Address")) {
this.in_Address= false;
}
}
/** Gets be called on the following structure:
* <tag>characters</tag> */
#Override
public void characters(char ch[], int start, int length) {
if(this.in_firstname){
myParsedExampleDataSet.setfirstname(new String(ch, start, length));
}
if(this.in_lastname){
myParsedExampleDataSet.setlastname(new String(ch, start, length));
}
if(this.in_Address){
myParsedExampleDataSet.setAddress(new String(ch, start, length));
}
}
}
I found an XML tutorial online here and editied it to work with your XML file. Below is the code. For the sake of testing it on my machine, I've sourced the XML file from a local file rather than online, but it shouldn't be too hard to work out.
This should hopefully point you in the right direction.
package phonebook;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class program {
public static void main(String argv[]) {
try {
File file = new File("phonebook.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
System.out.println("Root element " + doc.getDocumentElement().getNodeName());
NodeList nodeLst = doc.getElementsByTagName("PhonebookEntry");
System.out.println("Information of all entries");
for (int s = 0; s < nodeLst.getLength(); s++) {
Node fstNode = nodeLst.item(s);
if (fstNode.getNodeType() == Node.ELEMENT_NODE)
{
Element fstElmnt = (Element) fstNode;
// Firstname
NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("firstname");
Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
NodeList fstNm = fstNmElmnt.getChildNodes();
System.out.println("First Name : " + ((Node) fstNm.item(0)).getNodeValue());
// Lastname
NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("lastname");
Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
NodeList lstNm = lstNmElmnt.getChildNodes();
System.out.println("Last Name : " + ((Node) lstNm.item(0)).getNodeValue());
// Address
NodeList addrNmElmntLst = fstElmnt.getElementsByTagName("Address");
Element addrNmElmnt = (Element) addrNmElmntLst.item(0);
NodeList addrNm = addrNmElmnt.getChildNodes();
System.out.println("Address : " + ((Node) addrNm.item(0)).getNodeValue());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}