I created a Java application which opens an xml file that looks something like this:
<AnimalTree>
<animal>
<mammal>canine</mammal>
<color>blue</color>
</animal>
<!-- ... -->
</AnimalTree>
And I can open it using:
File fXmlFile = getResources.getXml("res/xml/data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList animalNodes = doc.getElementsByTagName("animal");
Then I can simply create a node, push the object into a ListArray, then do what I want with the objects as I loop through the ListArray.
for (int temp = 0; temp < animalNodes.getLength(); temp++) {
Node nNode = animalNodes.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
question thisAnimal = new animal();
thisAnimal.mammal = getTagValue("mammal",eElement);
// ...
Plain and simple! Now only, in Android I cannot simply read the file "res/xml/data.xml" because "File();" requires a String not an integer (id). This is where I am lost. Is there some way I can make "File();" open the file, or is this impossible without using SAXparser or XPP? (both of which I really cannot understand, no matter how hard I try.)
If I am forced to use those methods, can someone show me some simple code analogous to my example?
If it's in the resource tree, it'll get an ID assigned to it, so you can open a stream to it with the openRawResource function:
InputStream is = context.getResources().openRawResource(R.xml.data);
As for working with XML in Android, this link on ibm.com is incredibly thorough.
See Listing 9. DOM-based implementation of feed parser in that link.
Once you have the input stream (above) you can pass it to an instance of DocumentBuilder:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(this.getInputStream());
Element root = dom.getDocumentElement();
NodeList items = root.getElementsByTagName("TheTagYouWant");
Keep in mind, I haven't done this personally -- I'm assuming the code provided by IBM works.
I tried the approach using openRawResource and got a SAXParseException. So, instead, I used getXml to get a XmlPullParser. Then I used next() to step through the parsing events. The actual file is res/xml/dinosaurs.xml.
XmlResourceParser parser = context.getResources().getXml(R.xml.dinosaurs);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT :
Log.v(log_tag, "Start document");
break;
case XmlPullParser.START_TAG :
Log.v(log_tag, "Start tag " + parser.getName() );
break;
case XmlPullParser.END_TAG :
Log.v(log_tag, "End tag " + parser.getName() );
break;
case XmlPullParser.TEXT :
Log.v(log_tag, "Text " + parser.getText() );
break;
default :
Log.e(log_tag, "Unexpected eventType = " + eventType );
}
eventType = parser.next();
}
Try this,
this.getResources().getString(R.xml.test); // returns you the path , in string,invoked on activity object
Related
I'm trying to write to an XML file, within my XML file I have:
<user>
<name></name>
</user>
And the method I can to write to the XML file:
public void WriteToXML() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputStream);
Element element = doc.getDocumentElement();
element.normalize();
NodeList nList = doc.getElementsByTagName("user");
Node node = nList.item(0);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element2 = (Element) node;
if(element2.getTagName() == "name")
{
element2.setNodeValue("SFDSFSDF");
}
}
}
However, the method gets called but for some reason it doesnt actually write to the XML file because when I read it their isn't actually anything within the XML?
Try to replace :
element2.getTagName() == "name"
by :
(element2.getTagName()).equals("name")
Also, try to replace :
element2.setNodeValue("SFDSFSDF");
by :
element2.setTextContent("SFDSFSDF"); //adds content
I have noticed that for Android 4.4 handsets, saving a webview with:
webview.saveWebArchive(name);
and reading it after with WebArchiveReader WebArchiveReader (see code below) throws an Encoding Exception:
11-08 15:10:31.976: W/System.err(2240): org.xml.sax.SAXParseException: Unexpected end of document
11-08 15:10:31.976: W/System.err(2240): at org.apache.harmony.xml.parsers.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:125)
The method used to read the stored XML file worked perfectly fine until 4.3 and it is (NOTE: I tried to parse it in two different ways):
public boolean readWebArchive(InputStream is) {
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
myDoc = null;
try {
builder = builderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
try {
//New attempt
InputSource input = new InputSource(is);
input.setEncoding("UTF-8");
myDoc = builder.parse(input);
//This used to be the way it used to work for
//Android 4.3 and below without trouble
//myDoc = builder.parse(is);
NodeList nl = myDoc.getElementsByTagName("url");
for (int i = 0; i < nl.getLength(); i++) {
Node nd = nl.item(i);
if(nd instanceof Element) {
Element el = (Element) nd;
// siblings of el (url) are: mimeType, textEncoding, frameName, data
NodeList nodes = el.getChildNodes();
for (int j = 0; j < nodes.getLength(); j++) {
Node node = nodes.item(j);
if (node instanceof Text) {
String dt = ((Text)node).getData();
byte[] b = Base64.decode(dt, Base64.DEFAULT);
dt = new String(b);
urlList.add(dt);
urlNodes.add((Element) el.getParentNode());
}
}
}
}
} catch (SAXParseException se){
//Some problems parsing the saved XML file
se.printStackTrace();
myDoc = null;
} catch (Exception e) {
e.printStackTrace();
myDoc = null;
}
return myDoc != null;
}
I've played a bit with the way the buider is invoked. Instead of giving it a FileInputStream, I first create an InputSource as you can see to force a given encoding. However, I had no success. By not including the InputSource, the exception was instead:
org.xml.SAXParseException: Unexpected token
I've read in previous posts that this may be an encoding issue (e.g. android-utf-8-file-parsing) but none of the proposed solutions worked for me.
Does anyone else have the same issue or does anyone know what has changed on Kit Kat, and if so, how could it be avoided?
Many thanks in advance
My WebArchiveReader code is not needed under Android 4.4 KitKat and newer to read back a saved web archive. If you save your page with webview.saveWebArchive(name); method on KitKat, you get an MHTML formatted file, as "#Dragon warrior" indicates above. To read this file back into webview, just use:
webView.loadUrl("file:///my_folder/mySavedPage.mht");
Just make sure to give your file the .mht or .mhtml extension, so that WebView recognizes its contents. Otherwise it may just display the MHTML code in text format.
Greg
I have the exactly same problem as you do.
Apparently, Android 4.4 WebView saves web archives as MHTML. Therefore, you can't use WebArchiveReader anymore.
You might want to parse MHTML files with some other 3rd party lib. Good luck!
So im trying to parse and xml file in android. Bellow is a link to the file and my code. I'm trying to get the current temp stored as "temp_f" in the "current_conditions" element. But every time i run it i get this error, 09-15 20:26:47.359: DEBUG/ErOr(17663): java.lang.ClassCastException: org.apache.harmony.xml.dom.ElementImpl
http://www.google.com/ig/api?weather=10598
DocumentBuilderFactory factory1 = DocumentBuilderFactory.newInstance();
factory1.setNamespaceAware(true); // never forget this!
InputSource source = new InputSource(new StringReader(xmltemp));
Document doc = factory1.newDocumentBuilder().parse(source);
String newstring = "" + ((DocumentBuilderFactory) ((Document) doc.getDocumentElement().
getElementsByTagName("current_conditions").item(0)).
getElementsByTagName("temp_f").item(0)).
getAttribute("data");
Have a look at the Java XPath API -- that should be much nicer than traversing the DOM to find your data:
URL url = new URL("http://www.google.com/ig/api?weather=10598");
InputSource xml = new InputSource(url.openStream());
XPath xpath = XPathFactory.newInstance().newXPath();
String data = xpath.evaluate("//current_conditions/temp_f/#data", xml);
As for the original question:
First put every statement of your extraction code on a line of its own, this will help you a lot with finding the problems (and line numbers in stacktrace will be a lot more precise):
Element docElem = doc.getDocumentElement();
Document curr_cond = (Document) /*1*/ docElem.getElementsByTagName("current_conditions").item(0);
DocumentBuilderFactory temp_f = (DocumentBuilderFactory) /*2*/ curr_cond.getElementsByTagName("temp_f").item(0);
String newstring = "" + temp_f.getAttribute("data");
At /*1*/ you try to cast a org.w3.dom.Node into an org.w3.dom.Document -- but not every Node is a Document, as can be seen by the ClassCastException here: The returned Node is actually an instance of the org.w3.dom.Element interface, more precisely an instance of class of org.apache.harmony.xml.dom.ElementImpl (part of the Apache Harmony XML parser implementation).
So let's remove the cast and change the declared type of curr_cond to Node:
Element docElem = doc.getDocumentElement();
Node curr_cond = docElem.getElementsByTagName("current_conditions").item(0);
DocumentBuilderFactory temp_f = (DocumentBuilderFactory) /*2*/ curr_cond.getElementsByTagName("temp_f").item(0);
String newstring = "" + temp_f.getAttribute("data");
Now a second problem becomes obvious at /*2*/: The Node interface does not specify a getElementsByTagName() method, that's probably why you did try to cast to Document above. This won't compile and there is no way to get it to.
Why you cast the result to DocumentBuilderFactory is beyond me. Yes, there is a getAttribute() method but both the class name and method javadoc should have made clear that it's definitely not doing want you want.
So my above recommendation holds: Please use XPath, it's the better tool for this task :)
There actually is a way to extract the data using only DOM for your first task (current temperature). It relies on the fact that the temp_f element is unique and is a lot more verbose than the above XPath expression, though:
Element docElem = doc.getDocumentElement();
Node temp_f = docElem.getElementsByTagName("temp_f").item(0);
NamedNodeMap attributes = temp_f.getAttributes();
Node dataAttr = attributes.getNamedItem("data");
String data = dataAttr.getNodeValue();
I am parsing a xml from an url.The url is has mobile IMEI no and searchstring based on my application. i put my xml parsing code in android project it does not work. but if i run as separate java program it is working. please help me.
Log.e("rsport-", "function1");
try{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
factory.setCoalescing(true); // Convert CDATA to Text nodes
factory.setNamespaceAware(false); // No namespaces: this is default
factory.setValidating(false); // Don't validate DTD: also default
DocumentBuilder parser = factory.newDocumentBuilder();
Log.e("rsport-", "function2");
Document document = parser.parse("http://demo.greatinnovus.com/restingspot/search?userid=xxxxxxxxxxxxxxxx&firstname=a&lastname=a");
Log.e("rsport-","function3");
NodeList sections = document.getElementsByTagName("Searchdata");
int numSections = sections.getLength();
for (int i = 0; i < numSections; i++)
{
Element section = (Element) sections.item(i);
if(section.hasChildNodes()==true){
NodeList section1=section.getChildNodes();
for(int j=0;j<section1.getLength();j++){
if(section1.item(j).hasChildNodes()==true) {
for(int k=0;k<section1.item(j).getChildNodes().getLength();k++)
xmlvalue=String.valueOf(section1.item(j).getChildNodes().item(k).getNodeValue()).trim();
arl.add(xmlvalue);
}
}
}
}
}
}
catch(Exception e){}
System.out.println("id"+id+" searchdatacount"+searchdatacount);
System.out.println("---------");
ListIterator<String> litr = arl.listIterator();
while (litr.hasNext()) {
String element = litr.next();
Log.e("rsport-", "elememt");
}
after the Log.e("rsport-", "function2"); does not work.
Refer my blog, i had gave Detailed explanation, http://sankarganesh-info-exchange.blogspot.com/2011/04/parsing-data-from-internet-and-creating.html, and make sure , that you had add the Internet permission in your Manifest file.
If you had gone through Myblog, then you will able to notice that you did the following line as wrong
Document document = parser.parse("http://demo.greatinnovus.com/restingspot/search?userid=xxxxxxxxxxxxxxxx&firstname=a&lastname=a");
use like this
URL url =new URL("http://demo.greatinnovus.com/restingspot/search?userid=xxxxxxxxxxxxxxxx&firstname=a&lastname=a");
Document document= parser.parse(new InputSource(url.openStream()));
I'm using the DOM parser to retrive information from a XML file that looks like this:
<data>
<metData>
<wantedInformation>
</metData>
<metData>
<Information>
</metData>
<metData>
<Information>
</metData>
<data>
The problem is because I don't know how to parse only the first part of <metData>. I don't need the second and the third part, but the parser displays them anyway.
The xml file is from a weather forcast site:
http://www.meteo.si/uploads/probase/www/fproduct/text/sl/fcast_SLOVENIA_MIDDLE_latest.xml
and I need just the following line: <nn_shortText>oblačno</nn_shortText>
Pls take care whether your XML file is well formed or not,
You have to the notice three methods which i had shown below, they are
1. getElementsByTagName - Mention the tag which you want to parse
2.getChildNodes - retervies the child node
3.getNodeValue()- with the help of this method you can access the
value of particular tag
Step 1: Create a Method to parse _Information_Value ,inorder to parse the data of Information tag
String[] infoId=null;
public void parse_Information_Value() throws UnknownHostException{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(this.getInputStream());
org.w3c.dom.Element root = dom.getDocumentElement();
NodeList items = root.getElementsByTagName("metData");
int a=items.getLength();
int k=0;
for (int i = 0; i < items.getLength(); i++) {
Message_category message = new Message_category();
Node item = items.item(i);
NodeList properties = item.getChildNodes();
for (int j = 0; j < properties.getLength(); j++) {
Node property = properties.item(j);
String name = property.getNodeName();
if (name.equalsIgnoreCase("wantedInformation")) {
message.setId(property.getFirstChild()
.getNodeValue());
infoId[k]=property.getFirstChild().getNodeValue();
k++;
}
}
}
} catch (Exception e) { }
}
Depending on the size of your document, you may also want to use at a streaming oriented parser like SAX or Stax, which does not pull the whole document into memory and thus needs less memory than DOM.
Good thing is that SAX is already built into Android, so you can use it right away.
See this link for a usage example.