I'm having a little trouble parsing a string of xml called responseText in android. The xml is fully valid and has the following structure:
<plan>
<entry>
<name>john</name>
<address>uk</address>
</entry>
<entry>
<name>joe</name>
<address>usa</address>
</entry>
</plan>
The code I am using to parse the String is as follows:
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(responseText));
Document doc = db.parse(is);
NodeList nodes = doc.getElementsByTagName("entry");
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
NodeList name = ((Document) element)
.getElementsByTagName("name");
Element line = (Element) name.item(0);
Toast.makeText(Containers.this,
getCharacterDataFromElement(line), Toast.LENGTH_SHORT)
.show();
NodeList title = ((Document) element)
.getElementsByTagName("address");
line = (Element) title.item(0);
Toast.makeText(Containers.this,
getCharacterDataFromElement(line), Toast.LENGTH_SHORT)
.show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getCharacterDataFromElement(Element e) {
Node child = ((Node) e).getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
return "?";
}
I'm just using simple toasts to print the xml data to screen. However, i get an IOexception when I enter the for loop. Any idea what is wrong?
Are you importing the types from the correct packages? Something like
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import android.sax.Element; // Wrong Element class
Change the last import to
import org.w3c.dom.Element;
and try again.
I don't see anything that could cause an IOException inside the loop.
However, are you sure you can just go and cast an Element into a Document? At any rate you shouldn't need to anyways, since Element also has the getElementsByTagName method.
Try adding an xml declaration at the start of your string.
Related
I have an XML that uses Map* , see below. I want to assign some values to an array (usrHoey).
example.
Assign "String_2" to Variable kode
Assign 2 to Variable prosentsats
How do I accomplish this in java using XPath. See below java code, area to look at is "// usrHoey ************************* ". The previous variable "ankomstDato" work fine.
XML file(xyx.xml)
<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
<string key="ankomstDato">2020-08-03T09:24:40.486</string>
<map key="historikk">
<array key="usrHoey">
<map>
<string key="kode">string</string>
<number key="prosentsats">0</number>
</map>
</array>
</map>
</map>
Java code that is working well will other simple Nodes.
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
//** */
public class SolutionXML2XmlFormat {
//Create Public Variables to store data
//**
public static String ankomstDato_value; //1
//+++
public void Xml2JavaObject(String TheXMLPath){
//read the xml(TheXMLPath) and store values in variables
//This is just an example
ankomstDato_value = "2021-08-03T09:24:40.486";
//Call method to write values
Write2XMLfile();
}
//Modify the existing values in Api_XML_Format.xml
//*
public void Write2XMLfile(){
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
try {
String filepath = "src/main/java/no/difi/oauth2/utils/xyz.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filepath);
// 1. ankomstDato
Node ankomstDato = (Node) xpath.evaluate("(/map/string[#key='ankomstDato'])[1]", doc, XPathConstants.NODE);
ankomstDato.setTextContent(ankomstDato_value );
// End ankomstDato
// usrHoey **************************
NodeList arrayElements_4 = (NodeList) xpath.evaluate("/map/map/array[#key='usrHoey']/*", doc, XPathConstants.NODESET);
for (int i = 0; i < arrayElements_4.getLength(); i++) {
Node el = arrayElements_4.item(i);
el.setTextContent(pmAnmerkningListe_value[i]);
System.out.println("\n \n");
System.out.println("array element: tag='" + el.getNodeName() + "' text='"
+ el.getTextContent() + "'");
}
// usrHoey
//********** */
//End of historikk
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filepath));
transformer.transform(source, result);
System.out.println("Done Updating The xyz.xml");
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
} catch (XPathExpressionException xee) {
xee.printStackTrace();
}
}
}
This is how I did it, it might not be the correct method but it worked for me. I still stand to be corrected by anyone with a better method.
//11. usrHoey **************************
Node usrHoey = (Node) xpath.evaluate("/map/map/array[#key='usrHoey']/*", doc, XPathConstants.NODE);
if(null != usrHoey) {
NodeList nodeList = usrHoey.getChildNodes();
for (int i = 0;null!=nodeList && i < nodeList.getLength(); i++) {
Node nod = nodeList.item(i);
System.out.println("\n");
if(nod.getNodeType() == Node.ELEMENT_NODE){
NodeList arrayElements_11 = (NodeList) xpath.evaluate("/map/map/array[#key='usrHoey']/*", doc, XPathConstants.NODESET);
for (int j = 0; j < arrayElements_11.getLength(); j++) {
//11. Kode
Node kode = (Node) xpath.evaluate("(/map/map/array/map/string[#key='kode'])[1]", doc, XPathConstants.NODE);
kode.setTextContent(usrHoey_kode_value[j]);
// end kode
//12. prosentsats
Node prosentsats = (Node) xpath.evaluate("(/map/map/array/map/string[#key='prosentsats'])[1]", doc, XPathConstants.NODE);
prosentsats.setTextContent(usrHoey_prosentsats_value[j]);
// end prosentsats
}
}
}
}
// usrHoey
I have created an XML parser to retrieve the information from an XML file to java, and then I am trying to store these data into an ArrayList in order to use the ArrayList for my methods.
It seems to work fine when I print it. However, I got a method called getAllRoutes for some reason it returns the wrong number of routes
Please move
routes.add(r);
inside
if (c.getNodeName().equals("Route")) {
Let me know if this helps Khaled.
Try this:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.List;
import java.util.ArrayList;
class Main {
public static Iterable<Node> iterable(final NodeList nodeList) {
return () -> new Iterator<Node>() {
private int index = 0;
#Override
public boolean hasNext() {
return index < nodeList.getLength();
}
#Override
public Node next() {
if (!hasNext())
throw new NoSuchElementException();
return nodeList.item(index++);
}
};
}
private static List<String> evaluateXPath(Document document, String xpathExpression)
{
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
List<String> values = new ArrayList<>();
try
{
// Create XPathExpression object
XPathExpression expr = xpath.compile(xpathExpression);
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
values.add(nodes.item(i).getNodeValue());
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return values;
}
public static void main(String[] args) throws Exception {
//Build DOM
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("data.xml");
//Create XPath
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
String xpathRoot = "//Routes/Route";
XPathExpression expr = xpath.compile(xpathRoot);
int i = 0;
for (Node n : iterable((NodeList) expr.evaluate(doc, XPathConstants.NODESET))) {
i++;
String xpe2 = String.format("%s[%d]/%s/text()", xpathRoot, i, "FlightNumber");
System.out.println("FxPe: " + xpe2);
System.out.println("Flight Number: " + evaluateXPath(doc, xpe2).get(0));
for (Node n2 : iterable(n.getChildNodes())) {
System.out.println(n2.getTextContent());
}
}
}
}
See it in action here
Useful links:
1: Iterate through NodeList
2: XPath CheatSheet
3: Java XPath Example a and b
4: NodeList Java docs
5: Node Java docs
And I would say. I your code:
Route r = new Route(); should be inside if statement
if (c.getNodeName().equals("Route"))
The commented out add is in the right place - the other place is wrong.
I have to parse a String containing XML tags like the one hard coded below so that I can get values of all the tags separately. Here when I am using
NodeList node = doc.getElementsByTagName("event");
It is returning value as "ajain1AnkitJain24-04-199223:09.08"
I want to retrieve value for each tag and store it separately in different variables.
Like for eg in this scenario I want to Store Value as :
String UID = ajain1
String FirstName = Ankit
String LastName = Jain
Date date = "24-04-1992 23:09.08"
Here is the Sample code I am working on.
package test;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class Demo {
public static void main(String[] args) {
String xmldata = "<event><class></class><data><UID><![CDATA[ajain1]]></UID><FIRSTNAME><![CDATA[Ankit]]></FIRSTNAME><LASTNAME><![CDATA[Jain]]></LASTNAME><DATE><![CDATA[24-04-1992]]></DATE><TIME><![CDATA[23:09.08]]></TIME></data></event>";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
try {
db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmldata));
try {
Document doc = db.parse(is);
//String message = doc.getDocumentElement().getTextContent();
//System.out.println(message);
NodeList node = doc.getElementsByTagName("event");
} catch (SAXException e) {
// handle SAXException
} catch (IOException e) {
// handle IOException
}
} catch (ParserConfigurationException e1) {
// handle ParserConfigurationException
}
// TODO Auto-generated method stub
}
}
Thanks and let me know if you require any more information.
A NodeList already is a list containing all requested nodes, but I have to admit, I find its implementation highly questionable. It's basically a node containing the requested nodes as children. Its implementation has very much nothing in common with other list implementations - it doesn't even implement the List interface. I don't exactly know how to handle [!CDATA], but to loop through all event tags you'd have to do something like this:
NodeList eventList = doc.getElementsByTagName("event");
for(int i = 0; i < eventList.getLength(); i++) {
Element eventElement = (Element) eventList.item(i);
// do some stuff with it
}
From this element, you can also use getElementsByTagName to get the information needed about first name and so on. And yes, it's likely to end up with many nested loops...
I am working on a project using Java and JavaFX. i do impliment a methode to allow user to change between language. But i feel that it can be slow somehow.
I use an XML file to store all texts in it.
I creat the function "readXML" to read a called text from the XML.
I use this function so many times to complete the strings in the
scene.
I think that this is wrong because i read that reading from an XML file repeatedly and successively can slow my application. also the XML file is getting bigger and bigger while adding other scenes. that why i need help in this.
I still working on the project and my codes work right fine rigth now but it show a little slowing in every scene change (between 500ms and 1500ms depending on strings). i am afraid that this little time become bigger on next steps.
Here is the class ReadXMLFile.class that contain readXML:
package modele;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import java.io.File;
/**
* Créer par Malek Boubakri le 27/07/2015 à 20:37.
*/
public class ReadXMLFile {
public static String readXML(String name,int lang) {
String res = "";
try {
File fXmlFile = new File("res/files/strings.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("lang");
Node nNode = nList.item(lang);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
res=eElement.getElementsByTagName(name).item(0).getTextContent();
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
and this is how i use it:
....
lbl_elev_opt1.setText(ReadXMLFile.readXML("lbl_elev_list",SettingDialer.langID));
lbl_elev_opt2.setText(ReadXMLFile.readXML("lbl_elev_edit",SettingDialer.langID));
lbl_elev_opt3.setText(ReadXMLFile.readXML("lbl_elev_add",SettingDialer.langID));
lbl_elev_opt4.setText(ReadXMLFile.readXML("lbl_elev_del",SettingDialer.langID));
lbl_ens_opt1.setText(ReadXMLFile.readXML("lbl_ens_list",SettingDialer.langID));
lbl_ens_opt2.setText(ReadXMLFile.readXML("lbl_ens_edit",SettingDialer.langID));
lbl_ens_opt3.setText(ReadXMLFile.readXML("lbl_ens_class",SettingDialer.langID));
lbl_ens_opt4.setText(ReadXMLFile.readXML("lbl_ens_exam",SettingDialer.langID));
lbl_cal_opt1.setText(ReadXMLFile.readXML("lbl_cal_in",SettingDialer.langID));
lbl_cal_opt2.setText(ReadXMLFile.readXML("lbl_cal_add",SettingDialer.langID));
lbl_cal_opt3.setText(ReadXMLFile.readXML("lbl_cal_edit",SettingDialer.langID));
lbl_arch_opt1.setText(ReadXMLFile.readXML("lbl_arch_rech",SettingDialer.langID));
lbl_arch_opt2.setText(ReadXMLFile.readXML("lbl_arch_add",SettingDialer.langID));
lbl_arch_opt3.setText(ReadXMLFile.readXML("lbl_arch_edit",SettingDialer.langID));
lbl_doc_opt1.setText(ReadXMLFile.readXML("lbl_doc_off",SettingDialer.langID));
lbl_doc_opt2.setText(ReadXMLFile.readXML("lbl_doc_dip",SettingDialer.langID));
lbl_doc_opt3.setText(ReadXMLFile.readXML("lbl_doc_aut",SettingDialer.langID));
at lease 100 other uses....
Please if anything is blur just comment! waiting for your help..and thanks..
(Sorry for my bad, strange english)
That's because you are reading and parsing the whole xml file everytime you need to access a node from it.
So to fix this I moved the block in readXML method that reads same file whatever parameter it takes under init method. So you read xml file and initialize Document for once and use same Document instance for repeating calls without reading same file over and over again. You can just replace your code with below without any changes in other classes.
public class ReadXMLFile {
private static boolean _initialized = false;
private static Document _doc;
public static void init() {
if(_initialized) {
return;
}
try {
File fXmlFile = new File("res/files/strings.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
_doc = dBuilder.parse(fXmlFile);
_doc.getDocumentElement().normalize();
_initialized = true;
} catch (Exception e) {
e.printStackTrace();
}
}
public static String readXML(String name, int lang) {
if(!_initialized) {
init();
}
String res = "";
try {
NodeList nList = _doc.getElementsByTagName("lang");
Node nNode = nList.item(lang);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
res=eElement.getElementsByTagName(name).item(0).getTextContent();
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
I'm going through a tutorial on how to parse an xml document with java and encountering a problem. I am getting the error "dom cannot be resolved" I know it has something to do with the way I am declaring the variables and being out of scope but I can't figure out how to fix it.
Any help would be greatly appreciated, I will post the relevant parts below:
package com.xmlparse;
import java.io.IOException;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import com.entities.Employee;
public class XmlParser
{
private void parseXmlFile(){
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
Document dom = db.parse("test.xml");
} catch(ParserConfigurationException pce) {
pce.printStackTrace();
} catch(SAXException se) {
se.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
private void parseDocument() {
Document dom = db.parse("test.xml");
//get the root element
Element docEle = dom.getDocumentElement();
//get a nodelist of elements
NodeList nl = docEle.getElementsByTagName("Employee");
if(nl != null && nl.getLength() > 0) {
for(int i = 0 ; i < nl.getLength(); i++) {
//get the employee element
Element el = (Element)nl.item(i);
//get the Employee object
Employee e = getEmployee(el);
//add it to list
myEmpls.add(e);
}
}
}
As you are using DocumentBuilder db in different methods, you could declare db as a class member variable:
private DocumentBuilder db;
and initialize like so in parseXmlFile:
db = dbf.newDocumentBuilder();
You could change method signature like below and when call to it pass the created document builder instance.
private void parseDocument(DocumentBuilder db)