Android/Java XML Parsing with nodes of same name - java

I need some advice on how to parse XML with Java where there are multiple nodes that have the same tag. For example, if I have an XML file that looks like this:
<?xml version="1.0"?>
<TrackResponse>
<TrackInfo ID="EJ958083578US">
<TrackSummary>Your item was delivered at 8:10 am on June 1 in Wilmington DE 19801.</TrackSummary>
<TrackDetail>May 30 11:07 am NOTICE LEFT WILMINGTON DE 19801.</TrackDetail>
<TrackDetail>May 30 10:08 am ARRIVAL AT UNIT WILMINGTON DE 19850.</TrackDetail>
<TrackDetail>May 29 9:55 am ACCEPT OR PICKUP EDGEWATER NJ 07020.</TrackDetail>
</TrackInfo>
</TrackResponse>
I am able to get the "TrackSummary" but I do not know how to handle the "TrackDetail", since there is more than 1. There could be more than the 3 on that sample XML so I need a way to handle that.
So far I have this code:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xmlResponse));
Document dom = builder.parse(is);
//Get the ROOT: "TrackResponse"
Element docEle = dom.getDocumentElement();
//Get the CHILD: "TrackInfo"
NodeList nl = docEle.getElementsByTagName("TrackInfo");
String summary = "";
//Make sure we found the child node okay
if (nl != null && nl.getLength() > 0)
{
//In the event that there is more then one node, loop
for (int i = 0 ; i < nl.getLength(); i++)
{
summary = getTextValue(docEle,"TrackSummary");
Log.d("SUMMARY", summary);
}
return summary;
}
How would I handle the whole 'multiple TrackDetail nodes' ordeal? I'm new to XML parsing so I am a bit unfamiliar on how to tackle things like this.

You can try like this :
public Map getValue(Element element, String str) {
NodeList n = element.getElementsByTagName(str);
for (int i = 0; i < n.getLength(); i++) {
System.out.println(getElementValue(n.item(i)));
}
return list/MapHere;
}

If you are free to change your implementation then i would suggest you to use implementation given here.
you can collect the trackdetail in string array and when you are in XmlPullParser.END_TAG check for trackinfo tag end and then stop

You can refer below code for that.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(f);
Element root = doc.getDocumentElement();
NodeList nodeList = doc.getElementsByTagName("TrackInfo");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i); // this is node under track info
// do your stuff
}
for more information you can go through below link.
How to parse same name tag in xml using dom parser java?
It may help.

Related

Getting a node from an XML document

I use the worldweatheronline API. The service gives xml in the following form:
<hourly>
<tempC>-3</tempC>
<weatherDesc>rain</weatherDesc>
<precipMM>0.0</precipMM>
</hourly>
<hourly>
<tempC>5</tempC>
<weatherDesc>no</weatherDesc>
<precipMM>0.1</precipMM>
</hourly>
Can I somehow get all the nodes <hourly> in which <tempC>> 0 and <weatherDesc> = rain?
How to exclude from the response the nodes that are not interesting to me <hourly>?
This is quite feasible using XPath.
You can filter a document based on element values, attribute values and other criteria.
Here is a working example that gets the elements according to the first point in the question:
try (InputStream is = Files.newInputStream(Paths.get("C:/temp/test.xml"))) {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document xmlDocument = builder.parse(is);
XPath xPath = XPathFactory.newInstance().newXPath();
// get hourly elements that have tempC child element with value > 0 and weatherDesc child element with value = "rain"
String expression = "//hourly[tempC>0 and weatherDesc=\"rain\"]";
NodeList hours = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < hours.getLength(); i++) {
System.out.println(hours.item(i) + " " + hours.item(i).getTextContent());
}
} catch (Exception e) {
e.printStackTrace();
}
I think you should create xsd from xml and generate JAXB classes.Using those JAXB class you can easily unmarshal the xml and process your logic.

Parsing an XML document to get node values

I have an xml structure as below:
String attributesXML="<entry>
<value>
<List>
<String>Rob</String>
<String>Mark</String>
<String>Peter</String>
<String>John</String>
</List>
</value>
</entry>"
I want to fetch the values Rob,Mark,Peter,John. I can get the nodes starting from entry node(Code below). Problem is i don't know what will be the child node names under entry node. Starting from entry node i need to keep drilling down until I find the values. I have written a method getChildNodeValue() but it doesn't give me the required Output. It does print what i need but it prints some extra stuff as well. I need to return the values as a csv from this method getChildNodeValue().
Getting Entry Node:
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(attributesXML));
Document doc = db.parse(is);
NodeList nodes = doc.getElementsByTagName("entry");
for (int i = 0; i < nodes.getLength(); i++) {
if(nodes.item(i).hasChildNodes()){
getChildNodeValue(nodes.item(i));
}
}
public static void getChildNodeValue(Node node) {
System.out.println("Start Node: "+node.getNodeName());
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
while(currentNode.hasChildNodes()){
System.out.println("Current Node: "+currentNode.getNodeName());
nodeList = currentNode.getChildNodes();
for(int j=0;j<nodeList.getLength();j++){
currentNode = nodeList.item(j);
System.out.println("Node name: "+currentNode.getNodeName());
System.out.println("Node value: "+currentNode.getTextContent());
}
}
}
}
you can simply use XStream library for xml parsing it will parse java object to xml and vice versa.
check out below link
http://x-stream.github.io/tutorial.html

Parse XML node by node and check for leaf node

I used XPath expression //*[count(./*) = 0] to find the leaf nodes in an XML. But instead of using the expression, I wanted to parse the XML, node by node and check if it is a leaf node or not. How can I accomplish this? My XML is a dynamic one.
Using the following java code you can parse the xml and use docEle.hasChildNodes() to check it a leaf node or not.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse("file.xml");
Element docEle = dom.getDocumentElement();
NodeList nl = docEle.getChildNodes();
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
Element el = (Element) nl.item(i);
el.getTextContent().trim();
}
}
}
}

Building DOM document from xml string gives me a null document

I'm trying to use the DOM library to parse a string in xml format. For some reason my document contains nulls and I run into issues trying to parse it. The string variable 'response' is not null and I am able to see the string when in debug mode.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(response));
Document doc = builder.parse(is);
NodeList nodes = doc.getElementsByTagName("BatchFile");;
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
NodeList batchItem = element.getChildNodes();
String uri = batchItem.item(0).getNodeValue();
String id = batchItem.item(1).getNodeValue();
String fqName = batchItem.item(2).getNodeValue();
}
Highlighting over the line Document doc = builder.parse(is); after it has run shows the result of [#document: null].
Edit: I've managed to not got an empty doc now but the string values are still null (at end of code). How would I get the value of something like this
<GetBatchFilesResult>
<BatchFile>
<Uri>uri</Uri>
<ID>id</ID>
<FQName>file.zip</FQName>
</BatchFile>
</GetBatchFilesResult>
You can also use getTextContent(). getNodeValue will return null for elements. Besides, you'd better use getElementsByTagName, since white spaces are also treated as one of the child nodes.
Element element = (Element) nodes.item(i);
String uri = element.getElementsByTagName("Uri").item(0).getTextContent();
String id = element.getElementsByTagName("ID").item(0).getTextContent();
String fqName = element.getElementsByTagName("FQName").item(0).getTextContent();
Check Node API document to see what type of nodes will return null for getNodeValue.
I found the solution. Seems stupid that you have to do it this way to get a value from a node.
Element element = (Element) nodes.item(i);
NodeList batchItem = element.getChildNodes();
Element uri = (Element) batchItem.item(0);
Element id = (Element) batchItem.item(1);
Element fqName = (Element) batchItem.item(2);
NodeList test = uri.getChildNodes();
NodeList test1 = id.getChildNodes();
NodeList test2 = fqName.getChildNodes();
String strURI= test.item(0).getNodeValue();
String strID= test1.item(0).getNodeValue();
String strFQName= test2.item(0).getNodeValue();

import from xml into jtable

I have written a code that can save data into xml. NOW I want to use that stored xml and import its data in a table I have in the form. the problem is: the code is with no error but the table is not field with the xml data :(
here is my code:
private void jPanel4ComponentShown(java.awt.event.ComponentEvent evt) {
// TODO add your handling code here:
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
try{
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("D:\\test.xml");
Element root = doc.getDocumentElement();
NodeList nodelist1 = root.getElementsByTagName("FrameDefinitionSection");
String[] st= new String[4];
for(int i=0;i<nodelist1.getLength();i++)
{
Node node=nodelist1.item(i);
st[0]= node.getChildNodes().item(1).getTextContent();
st[1]= node.getChildNodes().item(3).getTextContent();
st[2]= node.getChildNodes().item(5).getTextContent();
st[3]= node.getChildNodes().item(7).getTextContent();
((DefaultTableModel) jTable1.getModel()).addRow(st);
}
}
catch(Exception ex)
{
System.out.print("error");
}
}
and here is my xml file :
the table should show the nodes in this xml into fields of table but it does not work ! :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<FrameDefinitionSection>
<FrameNameAndElements>
<FrameName>here is the frame's name</FrameName>
<FrameElements>its element</FrameElements>
</FrameNameAndElements>
<FrameDefinition>
<Definition>the definition of the frame</Definition>
</FrameDefinition>
<FrameExampleSentences>
<ExampleSentences>its example as well</ExampleSentences>
</FrameExampleSentences>
</FrameDefinitionSection>
You search for nodes FrameDefinitionSection-Tags under the Root-Node, but you have to search for FrameNameAndElements-Tags
getElementsByTagName will find sub-sub-sub-tags too.
You better use this:
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("D:\\test.xml");
Element root = doc.getDocumentElement();
NodeList nodelist1 =
root.getChildNodes();
String[] st = new String[4];
for (int i = 0; i < nodelist1.getLength(); i++)
{
Node node = nodelist1.item(i);
if (node.getNodeType() == node.ENTITY_NODE) {
st[0] = node.getChildNodes().item(1).getTextContent();
st[1] = node.getChildNodes().item(3).getTextContent();
st[2] = node.getChildNodes().item(5).getTextContent();
st[3] = node.getChildNodes().item(7).getTextContent();
((DefaultTableModel) jTable1.getModel()).addRow(st);
}
}
if you write like following, nodelist1 is null.
NodeList nodelist1 = root.getElementsByTagName("FrameDefinitionSection");
So you need to change like this ,
NodeList nodelist1 = doc.getElementsByTagName("FrameDefinitionSection");

Categories

Resources