Android - Reading XML issues - java

I've got an app that consumes a .NET web service which returns an XML string of data. I'm trying to read this XML and insert it into the local SQLite DB but I'm having some trouble. Here's a sample of the xml:
<?xml version="1.0" encoding="utf-8" ?>
<string xmlns="RemoteWebService"><OpenIssues> <Table> <IssueID>15351</IssueID> <IssueSummary>Computer keeps crashing. This continues to be a problem</IssueSummary> <LocationName>West Side</LocationName> <Status>WIP</Status> <CustomerID>89755</CustomerID> <CustomerName>West Side Computers</CustomerName> <CustomerShortName>WSC</CustomerShortName> <Notes /> <STATUS1>Work In Progress</STATUS1> <SubmittedBy>WSC - Tom Johns</SubmittedBy> <EQ_Replaced>true</EQ_Replaced></Table> </OpenIssues></string>
Using DOM, I'm trying to parse the results like so:
private void GetLatestData(String response) throws ParserConfigurationException, SAXException, IOException{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(response)));
//Normalize the document.
doc.getDocumentElement().normalize();
//Get Root Node.
NodeList nodeList = doc.getElementsByTagName("Table");
Node node = nodeList.item(0);
//Get Child Nodes.
for(int i = 0; i < node.getChildNodes().getLength(); i++){
IssueInfo issue = new IssueInfo();
Node tempNode = node.getChildNodes().item(i);
if(tempNode.getNodeName().equalsIgnoreCase("IssueID")){
issue.setIssueNumber(Long.parseLong(tempNode.getTextContent()));
}
if(tempNode.getNodeName().equalsIgnoreCase("IssueSummary")){
issue.setIssueNumber(Long.parseLong(tempNode.getTextContent()));
}
if(issue.getIssueNumber() > 0 && issue.getIssueSummary() != null){
creator = new IssueInfoCreator(this, DBVersion);
creator.open();
creator.InsertIssue(issue.getIssueNumber(), DateFormat.getDateInstance().format(new Date()), issue.getIssueSummary());
creator.close();
}
}
}
When I run it through the debugger, it gets "IssueID" just fine but how can I get it to pickup the next node "IssueSummary" right after that so I can insert the data at once? It seems like I need another loop somewhere, just not too sure where though.

If I understand your question correctly, this is what you may need to do.
Node node = nodeList.item(0);
Returns
<Table>
<IssueID>15351</IssueID>
<IssueSummary>Computer keeps crashing. This continues to be a problem</IssueSummary>
<Notes />
</Table>
node.getChildNodes().getLength();
Returns 3.
IssueInfo issue = new IssueInfo();
// Go through each child and find out node name and populate it.
for(int i = 0; i < node.getChildNodes().getLength(); i++){
Node tempNode = node.getChildNodes().item(i);
if(tempNode.getNodeName().equalsIgnoreCase("IssueID")){
issue.setIssueNumber(Long.parseLong(tempNode.getTextContent()));
}
if(tempNode.getNodeName().equalsIgnoreCase("IssueSummary")){
issue.setIssueNumber(Long.parseLong(tempNode.getTextContent()));
}
}
Move if logic out of the loop.
if(issue.getIssueNumber() > 0 && issue.getIssueSummary() != null){
creator = new IssueInfoCreator(this, DBVersion);
creator.open();
creator.InsertIssue(issue.getIssueNumber(), DateFormat.getDateInstance().format(new Date()), issue.getIssueSummary());
creator.close();
}

Seems like a simple DOM traversing issue.
If you can guarantee the next node is the summary, you could try using the getNextSibling() method for nodes
I modified your code so I could call it without using your classes. This is the code I used:
private static void GetLatestData(String response) {
try{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
/* the following 2 lines help you eliminate whitespace
from your xml DOM tree */
dbf.setValidating(true);
dbf.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = dbf.newDocumentBuilder();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(response)));
//Normalize the document.
doc.getDocumentElement().normalize();
//Get Root Node.
NodeList nodeList = doc.getElementsByTagName("Table");
Node node = nodeList.item(0);
long issueNumber;
String summary;
//Get Child Nodes.
for(int i = 0; i < node.getChildNodes().getLength(); i++){
Node tempNode = node.getChildNodes().item(i);
if(tempNode.getNodeName().equalsIgnoreCase("IssueID")){
issueNumber = (Long.parseLong(tempNode.getTextContent()));
Node summaryNode = tempNode.getNextSibling();
summary = summaryNode.getTextContent();
System.out.println(String.format("Issue # %d, Summary: %s" , issueNumber,summary));
}
}
}catch(Exception exception){
exception.printStackTrace();
}
}
and I call it like this:
GetLatestData("<OpenIssues> " +
"<Table> " +
"<IssueID>15351</IssueID>" +
"<IssueSummary>Computer keeps crashing. This continues to be a problem</IssueSummary> " +
"<Notes />" +
"</Table></OpenIssues> ");
from a simple Java class. It's working all right for me, at least. It prints out:
Issue # 15351, Summary: Computer keeps crashing. This continues to be a problem

*smacks forehead*
issue will never have more than one value set, as it's created anew for each child node.
Just swap the two lines to create issue only once:
IssueInfo issue = new IssueInfo();
for(int i = 0; i < node.getChildNodes().getLength(); i++){
...
You should probably move the final if outside the for too, so it's not executed more than once.
AND you'll need to actually set the summary in the second if not. You're setting the 'issue number' twice.

Finally found the resolution to this with the help of my coworker and some digging around. It should be noted that we changed the WebService that returned a string from DataSet.GetXml() to an XmlDocument.InnerXml. This removed the spaces in between the nodes and then we were able to move forward from there. Here's the final code we used:
public void GetLatestData(SoapPrimitive xml)throws ParserConfigurationException, SAXException, IOException{
//get the factory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//Using factory get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc;
//parse using builder to get DOM representation of the XML file
InputSource is = new InputSource(new StringReader(xml.toString()));
doc = db.parse(is);
//Clear out Issues table first.
creator = new IssueInfoCreator(this, DBVersion);
creator.open();
creator.ClearIssueTable();
creator.close();
NodeList nodes = doc.getElementsByTagName("Table");
for(int i = 0; i < nodes.getLength(); i++) {
IssueInfo issue = new IssueInfo();
Element e = (Element)nodes.item(i);
issue.setIssueNumber(Long.parseLong(XMLfunctions.getValue(e, "IssueID")));
issue.setIssueSummary(XMLfunctions.getValue(e, "IssueSummary"));
issue.setDateReceived(DateFormat.format("MM/dd/yyyy hh:mm:ss", System.currentTimeMillis()).toString());
if(issue.getIssueNumber() > 0 && issue.getIssueSummary() != null){
creator = new IssueInfoCreator(this, DBVersion);
creator.open();
creator.InsertIssue(issue.getIssueNumber(), issue.getDateReceived(), issue.getIssueSummary());
creator.close();
}
}
}
And here is the getValue method of the XMLfuntions class:
public static String getValue(Element item, String str) {
NodeList n = item.getElementsByTagName(str);
return XMLfunctions.getElementValue(n.item(0));
}
public final static String getElementValue( Node elem ) {
Node kid;
if( elem != null){
if (elem.hasChildNodes()){
for( kid = elem.getFirstChild(); kid != null; kid = kid.getNextSibling() ){
if( kid.getNodeType() == Node.TEXT_NODE ){
return kid.getNodeValue();
}
}
}
}
return "";
}
Definately not taking credit for this, I found it here:
Programmer XR and modified it to my needs.
Hopefully this will help other people out!

Related

how to get specific tag content inside parant tag from id in xml using java?

I have an XML file as below. I want to get its specific child tag from the parent tag using java.
<?xml version="1.0"?>
<class>
<question id="scores">
<ans>12</ans>
<ans>32</ans>
<ans>44</ans>
</question>
<question id="ratings">
<ans>10</ans>
<ans>22</ans>
<ans>45</ans>
<ans>100</ans>
</question>
<default>
Sorry wrong
</default>
</class>
i want the function to be like this
String function(String id)
it will return the ans tag randomly
i.e if I give input id=scores, the program will look in the XML tag for scores as id and get length()of its children, in this case, 3, then retun randomly like 32 or 44 or 12.if id is not present, return default.
my code so far
public class ChatBot {
private String filepath="E:\\myfile.xml";
private File file;
private Document doc;
public ChatBot() throws SAXException, IOException, ParserConfigurationException {
file = new File("E:\\myfile.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(file);
}
String Function(String id){
// This part
return null;
}
}
As suggested by #LMC (because of org.w3c.dom.Document.getElementById() not recognizing arbitrary id attributes as IDs for getElementById() or as a browser would, mostly for HTML semantics/format), maybe:
String Function(String id) throws XPathExpressionException {
XPath xPath = XPathFactory.newInstance().newXPath();
// Be aware: id inserted without any escaping!
NodeList parents = (NodeList)xPath.evaluate("/class/question[#id='" + id + "']", doc, XPathConstants.NODESET);
if (parents.getLength() < 1) {
return null;
} else if (parents.getLength() > 1) {
// Huh, duplicates?
}
Element parent = (Element)parents.item(0);
NodeList children = parent.getChildNodes();
List<Element> answers = new ArrayList<Element>();
for (int i = 0, max = children.getLength(); i < max; i++) {
if (children.item(i).getNodeType() != Node.ELEMENT_NODE) {
continue;
}
if (children.item(i).getNodeName().equals("ans") != true) {
// Huh?
continue;
}
answers.add((Element)children.item(i));
}
if (answers.size() <= 0) {
return null;
}
int selection = (int)(Math.random() * answers.size());
return answers.get(selection).getTextContent();
}

node.getNodeType is not working as expected in case of ELEMENT_NODE

I am trying to fetch all the elemnt type node only , and then i have some specific operation to do , but the node.getNodeType is not working as expected in case of ELEMENT_NODE - it is going in if block for all child node
Sample xml -
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.002.001.05">
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId>00990119071512383635</MsgId>
<CreDtTm>2019-07-15T12:38:36.304+05:30</CreDtTm>
<InitgPty>
<Nm>appSend</Nm>
</InitgPty>
</GrpHdr>
....
here is my code - what I want to do is for elements like MsgId i want to do something and for GrpHdr i want do some different operation
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringComments(true);
dbf.setValidating(true);
dbf.setNamespaceAware(true);
dbf.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File(fileName));
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("*");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
node.normalize();
if( node.getNodeType() == Node.ELEMENT_NODE ){
// do operation for only elements
}else{
// do other operation for non elements
}
}
}catch (Exception e){
}
Does anybody have faced similar issue ,
Thank you in advance
well , the following isn't a good workaround - but this is how i fixed it
Elements - will have just one child always.
So i tweaked it with below code -
if( node.getChildNodes().getLength() != 1 ){
// do operation for only non - elements
}else{
// do other operation for elements
}
I would say this is just a work around, not a good solution

XML - Extract One tag Value

I have to extract tag value from an xml Document that contains a single tag like below:
<error>Permission denied</error>
i have tried:
String xmlRecords = "<error>Permission denied</error>"
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlRecords));
Document doc = db.parse(is);
Node nodes = doc.getFirstChild();
String = nodes.getNodeValue();
but it dont works.
How can i do it ?
Use doc.getDocumentElement().getTextContent() to get the string Permission denied.
With DOM it´s util to know the structure of the XML document, and which node level are you looking for.
After get Document, you can use document.getElementsByTagName("root") to look for the root or father tags, and get the childs as a list to look for the item. Something like this:
NodeList listresults = document.getElementsByTagName('father/root element string');
NodeList nl = listresults.item(0).getChildNodes();
// Recorremos los nodos
for (int temp = 0; temp < nl.getLength(); temp++) {
Node node = nl.item(temp);
// Check if it is a node
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if(element.getNodeName().equals("error")){
// check the element
}
}
}
I hope this helps you.
just try following code.
String value = nodes.getTextContent();
You have to construct the string if you are using the above approach. You will get the string values of the tag name and content using the functions.
Tag name = nodes.getTextContent()
tag value = nodes.getLocalName()
I guess this is what you want
Element element = document.getDocumentElement();
NodeList errorTagList = element.getElementsByTagName("error");
if (errorTagList != null && errorTagList.getLength() > 0) {
NodeList errorTagSubList = errorTagList.item(0).getChildNodes();
if (errorTagSubList != null && errorTagSubList.getLength() > 0) {
String value = errorTagSubList.item(0).getNodeValue();
}
}

navigating hierarchy of xml input file

How do I list the element names at a given level in an xml schema hierarchy? The code I have below is listing all element names at every level of the hierarchy, with no concept of nesting.
Here is my xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="CDA.xsl"?>
<SomeDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:something">
<title>some title</title>
<languageCode code="en-US"/>
<versionNumber value="1"/>
<recordTarget>
<someRole>
<id extension="998991"/>
<addr use="HP">
<streetAddressLine>1357 Amber Drive</streetAddressLine>
<city>Beaverton</city>
<state>OR</state>
<postalCode>97867</postalCode>
<country>US</country>
</addr>
<telecom value="tel:(816)276-6909" use="HP"/>
</someRole>
</recordTarget>
</SomeDocument>
Here is my java method for importing and iterating the xml file:
public static void parseFile() {
//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("D:\\mypath\\somefile.xml");
//get the root element
Element docEle = dom.getDocumentElement();
//get a nodelist of elements
NodeList nl = docEle.getElementsByTagName("*");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("node.getNodeName() is: "+node.getNodeName());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
The output of the above program is:
title
languageCode
versionNumber
recordTarget
someRole
id
addr
streetAddressLine
city
state
postalCode
country
telecom
Instead, I would like to output the following:
title
languageCode
versionNumber
recordTarget
It would be nice to then be able to list the children of recordTarget as someRole, and then to list the children of someRole as id, addr, and telecom. And so on, but at my discretion in the code. How can I change my code to get the output that I want?
You're getting all nodes with this line:
NodeList nl = docEle.getElementsByTagName("*");
Change it to
NodeList nl = docEle.getChildNodes();
to get all of its children. Your print statement will then give you the output you're looking for.
Then, when you iterate through your NodeList, you can choose to call the same method on each Node you create:
NodeList children = node.getChildNodes();
If you want to print an XML-like structure, perhaps a recursive method that prints all child nodes is what you are looking for.
You could re-write the parseFile (I'd rather call it parseChildrenElementNames) method to take an input String that specifies the element name for which you want to print out its children element names:
public static void parseChildrenElementNames(String parentElementName) {
// 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("D:\\mypath\\somefile.xml");
// get the root element
NodeList elementsByTagName = dom.getElementsByTagName(parentElementName);
if(elementsByTagName != null) {
Node parentElement = elementsByTagName.item(0);
// get a nodelist of elements
NodeList nl = parentElement.getChildNodes();
if (nl != null) {
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("node.getNodeName() is: "
+ node.getNodeName());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
However, this will only consider the first element that matches the specified name.
For example, to get the list of elements under the first node named someRole, you would call parseChildrenElementNames("someRole"); which would print out:
node.getNodeName() is: id
node.getNodeName() is: addr
node.getNodeName() is: telecom

how to get attribute of given node?

I am trying to write DOM XML parsing.
My Xml file
<?xml version="1.0"?>
<BLAH>
<AgentNm type="citi1">
<accName>accName1</accName>
<accType>accType1</accType>
<someThing>someThing1</someThing>
<amt>100000</amt>
</AgentNm>
<AgentNm type="citi2">
<accName>accName2</accName>
<accType>accType2</accType>
<someThing>someThing2</someThing>
<amt>200000</amt>
</AgentNm>
</BLAH>
And i tried following java code
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse (new File("c:\\file.xml"));
// normalize text representation
doc.getDocumentElement ().normalize ();
System.out.println ("Root element of the doc is " +doc.getDocumentElement().getNodeName());
NodeList agentNm = doc.getElementsByTagName("AgentNm");
int totalAgentNm = agentNm.getLength();
System.out.println("Total no of Agents : " + totalAgentNm);
for(int s=0; s<agentNm.getLength() ; s++){
Node firstPersonNode = agentNm.item(s);
if(firstPersonNode.getNodeType() == Node.ELEMENT_NODE){
Element firstPersonElement = (Element)firstPersonNode;
PrintNodeElem(firstPersonElement,"type");
}//end of if clause
}//end of for loop with s var
static void PrintNodeElem(Element nodeElem,String elem){
NodeList someThingList = nodeElem.getElementsByTagName(elem);
Element ageElement = (Element)someThingList.item(0);
NodeList textAgeList = ageElement.getChildNodes();
System.out.println(elem+" : " +((Node)textAgeList.item(0)).getNodeValue().trim());
}
But, when i tried to execute above method,
i am getting null pointer exception.
can any one explain me, how to fix this.
if you want an attribute of a given node, I would suggest XPath. It is much easier.
http://onjava.com/onjava/2005/01/12/xpath.html

Categories