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.
Related
I'm dealing with the problem with passing parameteres to web-service.
I have created web-service which works OK for the case fromLanguage = "eng"
But, when I test service through Glassfish console and send fromLanguage = "bos" I don't get appropriate result.
package pckgTranslator;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
#Path("/MyRestService/{wordToTranslate},{fromLanguage},{toLanguage}")
public class clsTranslate {
#GET
public String doGet(#PathParam("wordToTranslate") String wordToTranslate,
#PathParam("fromLanguage") String fromLanguage, #PathParam("toLanguage") String toLanguage)
throws Exception{
Translator translator = new Translator();
return translator.getTranslation(wordToTranslate,fromLanguage, toLanguage);
}
}
This is XML fajl which I try to parse:
<?xml version="1.0" encoding="utf-8" ?>
<gloss>
<word id="001">
<eng>ball</eng>
<bos>lopta</bos>
</word>
<word id="002">
<eng>house</eng>
<bos>kuca</bos>
</word>
<word id="003">
<eng>game</eng>
<bos>igra</bos>
</word>
</gloss>
And this is the class which I'm using for parsing XML.
package pckgTranslator;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class Translator {
String translation = null;
String getTranslation(String wordForTransl, String fromLanguage, String toLanguage)
throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
//fromLanguage = "eng";
//toLanguage = "bos";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream is = Translator.class.getResourceAsStream("/resource/glossary.xml");
Document doc = builder.parse(new InputSource(is));
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
//XPathExpression expr = null; //xpath.compile("//word[eng='house']/bos/text()");
XPathExpression expr = xpath.compile("//word['" + wordForTransl + "'='" + wordForTransl + "']/bos/text()");
if (fromLanguage == "eng") {
expr = xpath.compile("//word[eng='" + wordForTransl + "']/bos/text()");
} else if (fromLanguage == "bos") {
expr = xpath.compile("//word[bos='" + wordForTransl + "']/eng/text()");
}
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
//System.out.println(nodes.item(i).getNodeValue());
translation = nodes.item(i).getNodeValue();
}
//return nodes.item(i).getNodeValue();
if (translation != null) {
return translation;
} else {
return "We are sorry, there is no translation for this word!";
}
}
}
It seems to me that something is wrong with the parameters fromLanguage and toLanguage, but I can't realize what exactly.
Thanks in advance.
As I mentioned in the comment, you have hardcoded fromLanguage and toLanguage variables to eng and bos at the beginning of getTranslation() method. Due to this, the fromLanguage and 'toLangugaevalues passed togetTranslation()` method are lost.
Secondly, instead of separating #PathParm by , separate those by /. It will look like:
#Path("/MyRestService/{wordToTranslate}/{fromLanguage}/{toLanguage}")
#GET
public String doGet(#PathParam("wordToTranslate") String wordToTranslate,
#PathParam("fromLanguage") String fromLanguage, #PathParam("toLanguage") String toLanguage) throws Exception
Invocation: curl -X GET http://localhost:8080/MyRestService/x/y/z
Alternatively use #QueryParam. In that case your path would be:
#Path("/MyRestService")
public String doGet(#QueryParam("wordToTranslate") String wordToTranslate,
#QueryParam("fromLanguage") String fromLanguage, #QueryParam("toLanguage") String toLanguage) throws Exception
Invocation: curl -X GET http://localhost:8080/MyRestService?wordToTranslate=x&fromLanguage=y&toLanguage=z
Remove or comment the below lines in getTranslation() method:
fromLanguage = "eng";
toLanguage = "bos";
Note: To fix your issue the above solution is sufficient. However, to make you code better please see the below suggestions.
In addition to the above I see two more issues:
You are storing translated value in translation instance variable. In case you are using the same Translator object (singleton instance) and the current translation fails, getTranslation() will return the previously translated value.
Why are you initializing expr with the below?
XPathExpression expr = xpath.compile("//word['" + wordForTransl + "'='" + wordForTransl + "']/bos/text()");
Lastly, every time you are calling getTranslation() the XML is being parsed. Instead, parse it once in init() method and then use it in getTranslation() method.
I have modified your Translator class based on the above points:
package org.openapex.samples.misc.parse.xml;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.io.InputStream;
public class ParseXMLAndTranslate {
public static void main(String[] args) throws Exception{
Translator translator = new Translator();
translator.init();
System.out.println(translator.getTranslation("house","eng", "bos"));
System.out.println(translator.getTranslation("igra","bos", "eng"));
}
private static class Translator {
//String translation = null;
private Document doc;
public void init() throws ParserConfigurationException, SAXException, IOException{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream is = Translator.class.getResourceAsStream("/resource/glossary.xml");
this.doc = builder.parse(new InputSource(is));
}
String getTranslation(String wordForTransl, String fromLanguage, String toLanguage)
throws XPathExpressionException {
//fromLanguage = "eng";
//toLanguage = "bos";
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
//XPathExpression expr = null; //xpath.compile("//word[eng='house']/bos/text()");
//XPathExpression expr = xpath.compile("//word['" + wordForTransl + "'='" + wordForTransl + "']/bos/text()");
XPathExpression expr = null;
if (fromLanguage == "eng") {
expr = xpath.compile("//word[eng='" + wordForTransl + "']/bos/text()");
} else if (fromLanguage == "bos") {
expr = xpath.compile("//word[bos='" + wordForTransl + "']/eng/text()");
}
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
String translation = null;
/*for (int i = 0; i < nodes.getLength(); i++) {
//System.out.println(nodes.item(i).getNodeValue());
translation = nodes.item(i).getNodeValue();
}*/
if(nodes.getLength() > 0){
translation = nodes.item(0).getNodeValue();
}
//return nodes.item(i).getNodeValue();
if (translation != null) {
return translation;
} else {
return "We are sorry, there is no translation for this word!";
}
}
}
}
Here is the output:
kuca
game
I'm building a simple currency converter which needs to sue online rates. I found the following API from the European Central Bank to use:
http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml
My problem is im struggling to implement it. Here is what i have so far after using a bunch of different sources to try and get this code together.
try{
URL url = new URL("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(url.openStream()));
doc.getDocumentElement().normalize();
NodeList nodeList1 = doc.getElementsByTagName("Cube");
for(int i = 0; i < nodeList1.getLength(); i++){
Node node = nodeList1.item(i);
}
}
catch(Exception e){
}
So what i thought is that this code would take down all the nodes which tart with "Cube", and contain the rates.
Anyone have an easier wya to pull down the rates from the API into an array in the order they appear on the XML as that's all I'm trying to do
Thanks
XPath is one way to answer this, since you just want to extract information from the XML and not change the XML. The structure of the XML suggests that you're looking for nodes that are Cube nodes, that are child of Cube which is also a child of Cube -- Cube nested three times, so extract nodes with an XPath compiled using this String: "//Cube/Cube/Cube". This looks for nodes that have Cube nested 3 times located anywhere (the //) in the Document:
XPathExpression expr = xpath.compile("//Cube/Cube/Cube");
Then check the nodes for a "currency" attribute. If they have this, then they also have a "rate" attribute, and then extract this information.
NamedNodeMap attribs = node.getAttributes();
if (attribs.getLength() > 0) {
Node currencyAttrib = attribs.getNamedItem(CURRENCY);
if (currencyAttrib != null) {
String currencyTxt = currencyAttrib.getNodeValue();
String rateTxt = attribs.getNamedItem(RATE).getNodeValue();
// ...
}
}
Where CURRENCY = "currency" and RATE = "rate"
For example:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class TestXPath {
private static final String CURRENCY = "currency";
private static final String CUBE_NODE = "//Cube/Cube/Cube";
private static final String RATE = "rate";
public static void main(String[] args) {
List<CurrencyRate> currRateList = new ArrayList<>();
DocumentBuilderFactory builderFactory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = builderFactory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
Document document = null;
String spec = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
try {
URL url = new URL(spec);
InputStream is = url.openStream();
document = builder.parse(is);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
String xPathString = CUBE_NODE;
XPathExpression expr = xpath.compile(xPathString);
NodeList nl = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
NamedNodeMap attribs = node.getAttributes();
if (attribs.getLength() > 0) {
Node currencyAttrib = attribs.getNamedItem(CURRENCY);
if (currencyAttrib != null) {
String currencyTxt = currencyAttrib.getNodeValue();
String rateTxt = attribs.getNamedItem(RATE).getNodeValue();
currRateList.add(new CurrencyRate(currencyTxt, rateTxt));
}
}
}
} catch (SAXException | IOException | XPathExpressionException e) {
e.printStackTrace();
}
for (CurrencyRate currencyRate : currRateList) {
System.out.println(currencyRate);
}
}
}
public class CurrencyRate {
private String currency;
private String rate; // ?double
public CurrencyRate(String currency, String rate) {
super();
this.currency = currency;
this.rate = rate;
}
public String getCurrency() {
return currency;
}
public String getRate() {
return rate;
}
#Override
public String toString() {
return "CurrencyRate [currency=" + currency + ", rate=" + rate + "]";
}
// equals, hashCode,....
}
XML parsing with Child not value parsing
import java.io.File;
import java.io.FileInputStream;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList;
public class XPathEvaluator {
/*
* ServiceGroup serviceGroup = new ServiceGroup(); List<Service>
* requiredServices = new ArrayList<Service>(); List<Service>
* recommandedServices = new ArrayList<Service>(); Service service = new
* Service();
*/
public void evaluateDocument(File xmlDocument) {
try {
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();
String requiredServicesExpression = "/Envelope/Header";
InputSource requiredServicesInputSource = new InputSource(
new FileInputStream(xmlDocument));
DTMNodeList requiredServicesNodes = (DTMNodeList) xPath.evaluate(
requiredServicesExpression, requiredServicesInputSource,
XPathConstants.NODESET);
System.out.println(requiredServicesNodes.getLength());
NodeList requiredNodeList = (NodeList) requiredServicesNodes;
for (int i = 0; i < requiredNodeList.getLength(); i++) {
Node node = requiredNodeList.item(i);
System.out.println(node.getChildNodes());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv) {
XPathEvaluator evaluator = new XPathEvaluator();
File xmlDocument = new File("d://eva.xml");
evaluator.evaluateDocument(xmlDocument);
}
}
my xml is following in this i am try to parse header information
<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
<Header>
<User id="MAKRISH"/>
<Request-Id id="1"/>
<Type name="Response"/>
<Application-Source name="vss" version="1.0"/>
<Application-Destination name="test" />
<Outgo-Timestamp date="2012-08-24" time="14:50:00"/>
<DealerCode>08301</DealerCode>
<Market>00000</Market>
</Header>
</Envelope>
i am not able to get Header child how can i get them it is giving me null on getchildNodes method. i have check for many solution but get any thing.
The following parsing is done with DOM as per tagging , i hope this should help you to solve
{
try{
File file = new File("xmlfile");
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(file);
Element root = document.getDocumentElement();
root.normalize();
printNode(root, 0);
} catch (Exception e) {
}
}
public static void printNode(Node node, int depth) {
if (node.getNodeType() == Node.TEXT_NODE) {
System.out.printf("%s%n", node.getNodeValue());
} else {
NamedNodeMap attributes = node.getAttributes();
if ((attributes == null) || (attributes.getLength() == 0)) {
System.out.printf("%s%n", node.getNodeName());
} else {
System.out.printf("%s ", node.getNodeName());
printAttributes(attributes);
}
}
NodeList children = node.getChildNodes();
for(int i=0; i<children.getLength(); i++) {
Node childNode = children.item(i);
printNode(childNode, depth+1);
}
}
private static void printAttributes(NamedNodeMap attributes) {
for(int i=0; i<attributes.getLength(); i++)
{
Node attribute = attributes.item(i);
System.out.printf(" %s=\"%s\"", attribute.getNodeName(),
attribute.getNodeValue());
}
}
}
The accepted answer to this related question has a good example of parsing xml using xpath.
I've debugged into your code, and the getChildNodes call is in fact not returning null, but it has got a confusing toString().
Following code is written to fetch the data from the xml file. I think it does fetch but in the object form. Why is that ?
package newpackage;
import java.io.File;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.util.LinkedList;
public class xmlParser {
private DocumentBuilder db;
private DocumentBuilderFactory dbf;
private Document dom;
private LinkedList list = new LinkedList();
public static void main(String args[]) {
xmlParser o = new xmlParser();
o.parseXML();
o.parseDocument();
o.print();
}
public void parseXML() { // getting a document builder
try {
dbf = DocumentBuilderFactory.newInstance();
db = dbf.newDocumentBuilder();
dom = db.parse(new File("Details.xml"));
} catch(Exception exc) {
exc.printStackTrace();
}
}
public void parseDocument() { // get a list of student elements
Element docEle = dom.getDocumentElement();
NodeList nl = docEle.getElementsByTagName("Details");
if(nl != null && nl.getLength() > 0) {
for(int i=0;i<nl.getLength();i++) {
Element el = (Element)nl.item(i);
Details details = new Details();
details = details.getDetail(el);
list.add(details);
}
}
}
public void print() {
// list.iterator();
// while(!list.isEmpty()) {
// System.out.println(list.pop().toString());
// }
Iterator it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next().toString());
}
}
}
Output :
newpackage.Details#1ac3c08
newpackage.Details#9971ad
newpackage.Details#1f630dc
newpackage.Details#1c5c1
Why do i get the output in the object form even after applying toString ?
When you want readable output, you have to override the toString() method in your newpackage.Details class ;)
Why do i get the output in the object form even after applying toString ?
Because you didn't override toString() method for that Details class
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.