Get the list of values using dom parser in android - java

I have to develop an android application.
Here i have follows following xml format.
<Product>
<product name="viki" productid="111">
<ProductType>
<producttype>Nokia</producttype>
<producttype>Samsung</producttype>
</ProductType>
</product>
</Product>
Here i have to get the producttype for particluar product.so i have wrote the following code:
if(subCategoryChildNode.hasChildNodes()){
// parse 'Subcategory' childs
NodeList productNL = subCategoryChildElmt.getElementsByTagName("product");
if(productNL.getLength() > 0){
ArrayList<Product> productAL = new ArrayList<Product>();
Product productBean = null;
for(int pCnt=0;pCnt<productNL.getLength();pCnt++){
Node productNode = productNL.item(pCnt);
Element productElmt = null;
// parse 'product' tag attributes
if(productNode.hasAttributes()){
productBean = new Product();
productElmt = (Element)productNode;
productBean.setmProductName(productElmt.getAttribute("name"));
}
if(productNode.hasChildNodes()){
NodeList productTypeNL = productElmt.getElementsByTagName("ProductType");
if(productTypeNL.getLength() > 0){
ArrayList<ProductType> ProductTypeAL = new ArrayList<ProductType>();
ProductType productTypeBean = null;
for(int ptCnt=0;ptCnt<productTypeNL.getLength();ptCnt++){
Node productTypeNode = productTypeNL.item(ptCnt);
Element productTypeElmt = null;
if(productTypeNode.hasChildNodes()){
productTypeBean = new ProductType();
productTypeElmt = (Element)productTypeNode;
productTypeBean.setmProductType(XMLfunctions.getValue(productTypeElmt,"producttype"));
System.out.println("Product Types are "+ " "+XMLfunctions.getValue(productTypeElmt,"producttype"));
ProductTypeAL.add(productTypeBean);
}
productBean.setmProductTypes(ProductTypeAL);
}
productAL.add(productBean);
}
}
subCategoryBean.setmProducts(productAL);
}
}
subCategoryAL.add(subCategoryBean);
}
Here am getting the value is nokia alone.but i need to display the value nokia,samsung...if i have to run the app means getting single value.but i need to get the list of all values..
What's wrong in my code .. please check and give me solution fot these ???

The reason you're getting only one <producttype> (Nokia) instead of the complete list because you're looping over the length of <ProductType> nodes thinking you're looping over the <producttype> ones.
So, you need another inner loop to cover all the child product type nodes like
for(int ptCnt=0; ptCnt < productTypeNL.getLength(); ptCnt++) {
Node productTypeNode = productTypeNL.item(ptCnt);
if(productTypeNode.hasChildNodes()){
NodeList childProductTypeNL = productTypeNode.getChildNodes();
System.out.print("Product Types are: ");
for (int cptCnt=0; cptCnt < childProductTypeNL.getLength(); cptCnt++) {
productTypeBean = new ProductType();
productTypeBean.setmProductType (
childProductTypeNL.item(cptCnt).getTextContent());
System.out.print(productTypeBean.getmProductType() + ", ");
ProductTypeAL.add(productTypeBean);
}
}
productBean.setmProductTypes(ProductTypeAL);
}
I've directly used the Node.getChildNodes() and Node.getTextContexnt() methods, instead of type casting to Element first and using its methods or the XMLfunctions utility class.
I also recommend using different names for child nodes instead of relying on using a different case to avoid such problems in future. A simple way to avoid name collision (when you're not able to come up with a different name) is to simply use a plural like <ProductTypes> for the parent tag.
However, a better approach when you need to parse deep within a DOM tree is to use an XPath to directly get the list of nodes you're interested in. I'm not entirely sure what the program does but just to give you an example an XPath like
String xpath = "//product[#name=\"viki\"]/ProductType/producttype";
would give you the NodeList for <producttype> nodes directly.

I'd say one of the problem of your code (might be others), is that you declare your productTypeBean and productTypeElmt before your for loop, and since it's not required after, it isn't needed.
if(subCategoryChildNode.hasChildNodes()){
// parse 'Subcategory' childs
NodeList productNL = subCategoryChildElmt.getElementsByTagName("product");
if(productNL.getLength() > 0){
ArrayList<Product> productAL = new ArrayList<Product>();
Product productBean = null;
for(int pCnt=0;pCnt<productNL.getLength();pCnt++){
Node productNode = productNL.item(pCnt);
Element productElmt = null;
// parse 'product' tag attributes
if(productNode.hasAttributes()){
productBean = new Product();
productElmt = (Element)productNode;
productBean.setmProductName(productElmt.getAttribute("name"));
}
if(productNode.hasChildNodes()){
NodeList productTypeNL = productElmt.getElementsByTagName("ProductType");
if(productTypeNL.getLength() > 0){
ArrayList<ProductType> ProductTypeAL = new ArrayList<ProductType>();
for(int ptCnt=0;ptCnt<productTypeNL.getLength();ptCnt++){
Node productTypeNode = productTypeNL.item(ptCnt);
if(productTypeNode.hasChildNodes()){
ProductType productTypeBean = new ProductType();
Element productTypeElmt = (Element)productTypeNode;
productTypeBean.setmProductType(XMLfunctions.getValue(productTypeElmt,"producttype"));
System.out.println("Product Types are "+ " "+XMLfunctions.getValue(productTypeElmt,"producttype"));
ProductTypeAL.add(productTypeBean);
}
productBean.setmProductTypes(ProductTypeAL);
}
productAL.add(productBean);
}
}
subCategoryBean.setmProducts(productAL);
}
}
subCategoryAL.add(subCategoryBean);
}

Related

Java: Get sum of child node values in a nested xml file

I need to make a program which outputs the price of a specific element in an xml file.
The xml file looks like this:
<list name="root">
<book name="B1" price="30" isbn="123"/>
<list name="L1">
<book name="B2" price="20" isbn="234"/>
<list name="L2">
<cd name="C1" price="15"/>
<cd name="C2" price="5"/>
<book name="B3" price="10" isbn="345"/>
</list>
<cd name="C3" price="15"/>
<book name="B4" price="60" isbn="456"/>
</list>
</list>
My program should output something like this:
getPrice(B1) = 30;
getPrice(L1) = B2+L2+C3+B4 = 125 ...
My idea is to store the names and values in a hashmap, and then get the values from it. But, I have troubles getting the price for the nested lists. The program should work for different xml files as well. Only the types (cd, book and list) will be the same.
Here is my code so far:
public class ManageList implements Assignment7 {
private HashMap<String, Double> data = new HashMap<String, Double>();
#Override
public void loadXml(File input) throws Exception {
// given in the readme
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// get filename => absolute path
String filename = input.getAbsolutePath();
Document doc = db.parse(new File(filename));
// Normalize the XML Structure
doc.getDocumentElement().normalize();
// get the root element from XML document
// Element root = doc.getDocumentElement();
// ####################################
// acces elements and their attributes and store it in a hashmap
// ####################################
NodeList nl = doc.getElementsByTagName("*");
storeNodes(nl);
//System.out.println(Arrays.asList(data));
}
#Override
public Optional<Double> getPrice(String item) {
return null;
}
public void storeNodes(NodeList nl) {
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
int type = n.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element e = (Element) n;
if (e.getTagName() == "book" || e.getTagName() == "cd") {
data.put(e.getAttribute("name"), Double.parseDouble(e.getAttribute("price")));
}
if (e.getTagName() == "list" && n.hasChildNodes()) {
String name = e.getAttribute("name");
//here i get a NumberFormatException
//data.put(name, Double.parseDouble(e.getAttribute("price")));
//just to show output
data.put(name, 0.0);
}
storeNodes(n.getChildNodes());
}
}
}
Hashmap output:
[{B2=20.0, C3=15.0, B3=10.0, B4=60.0, L1=0.0, L2=0.0, root=0.0, C1=15.0, B1=30.0, C2=5.0}]
How can I get the values for the nested Lists?
Thank you!
Since list contains sub attributes, looping from nList.getLength()-1 to 0 will avoid so many problems.
For list we need values(prices) of sub attributes book and cd. So looping from last to first will help us in storing the values of sub attributes in data as a prior step.
Now, For us to get total price of list, we iterate all over NodeList of books and cd.
we sum up all the values which makes the price of the list.
Below is the code if (e.getTagName() == "list" && n.hasChildNodes(),
NodeList books = e.getElementsByTagName("book");
NodeList cd = e.getElementsByTagName("cd");
System.out.println(books.getLength());
System.out.println(cd.getLength());
double listPrice = 0;
for(int i=0;i<books.getLength();i++) {
Node t = books.item(i);
Element e1 = (Element)t;
/**This can be reduced if we loop from nList.getLength()-1 to 0, Since the data already exists in data.
//if (!data.containsKey(e1.getAttribute("name"))){
// data.put(e1.getAttribute("name"),Double.parseDouble(e1.getAttribute("price")));
//
//}
*/
listPrice += Double.parseDouble(e1.getAttribute("price"));
}
for(int i=0;i<cd.getLength();i++){
Node t = cd.item(i);
Element e1 = (Element)t;
listPrice += Double.parseDouble(e1.getAttribute("price"));
}
for any doubts - comment.
Thanks.

Combine 2 array lists of objects that have null values

I'm trying to concatenate 2 array lists of objects into one but i can't figure out how to do it. I've tried with addAll and add but those methods won't really do what i want.
Basically, i have one array list with values like this:
SearchResult1 [title=null, url=null, price=19 690 EUR]
And another one with values like this:
SearchResult2 [title=Ford Car, url=http://www.something.com, price=null]
How can i combine those 2 arrays into one with values like this:
SearchResult3 [title=Ford Car, url=http://www.something.com, price=19 690 EUR]
This is the code so far:
public List searchMethod() {
try {
final String query = "ford";
final Document page = Jsoup.connect("link" + URLEncoder.encode(query, "UTF-8")).userAgent(USER_AGENT).get();
List<SearchResult> resultList1 = new ArrayList<SearchResult>();
List<SearchResult> resultList2 = new ArrayList<SearchResult>();
List<SearchResult> resultList3 = new ArrayList<SearchResult>();
for(Element searchResult : page.select(".offer-price")) {
String price = searchResult.text();
resultList1.add(new SearchResult(price));
}
for(Element searchResult : page.select(".offer-title__link")) {
String title = searchResult.text();
String url = searchResult.attr("href");
resultList2.add(new SearchResult(title, url));
}
resultList3.addAll(resultList1);
resultList3.addAll(resultList2);
return resultList3;
}catch(Exception e) {
e.printStackTrace();
}
return Collections.emptyList();
}
The values that i put in those arrays are extracted from a web page
Thanks for helping!
From the comment, you have said that you just want to correlate/merge the objects from both lists by each index.
You can simply loop through the list, constructing a new SearchResult (assuming you have getters for the fields)
for(int i = 0; i < resultList1.size(); i++) {
resultList3.add(new SearchResult(resultList1.get(i).getPrice(),
resultList2.get(i).getTitle(),
resultList2.get(i).getUrl()));
}
You may have to change the order of the passed arguments to the SearchResult constructor taking price, title and url as you haven't shown it.
why don't you do it in one shot?
List<SearchResult> resultList1 = new ArrayList<SearchResult>();
for(Element searchResult : page.select(".offer-title__link")) {
String title = searchResult.text();
String url = searchResult.attr("href");
resultList1.add(new SearchResult(title, url));
}
int index = 0;
for(Element searchResult : page.select(".offer-price")) {
String price = searchResult.text();
//since you have already assumed
//that price will come in the same order and title and url.
resultList1.get(index++).setPrice(price);
}
return resultList1;

Represent Null values as blank in xml with java

My Excel data values are:
Name EmployeeId Address Phone
Rony FBL123 Dhaka 12333333
Azam FBL321 Dhaka 67778888
Rony Chandpur 099776655
Azam 9988
Here is my code to read a list of data values including null values:
And convert data into xml:
try {
DocumentBuilderFactory dFact = DocumentBuilderFactory.newInstance();
DocumentBuilder build = dFact.newDocumentBuilder();
Document doc = build.newDocument();
Element root = doc.createElement("dataroot");
doc.appendChild(root);
Element Details = doc.createElement("DATA");
root.appendChild(Details);
for(int i=0; i<list.size()-2; i +=3 ) {
Element name = doc.createElement("Name");
name.appendChild(doc.createTextNode(String.valueOf(list.get(i))));
Details.appendChild(name);
Element id = doc.createElement("Empid");
id.appendChild(doc.createTextNode(String.valueOf(list.get(i+1))));
Details.appendChild(id);
Element ad = doc.createElement("Add");
ad.appendChild(doc.createTextNode(String.valueOf(list.get(i+2))));
Details.appendChild(ad);
Element mo = doc.createElement("Mobile");
mo.appendChild(doc.createTextNode(String.valueOf(list.get(i+3))));
Details.appendChild(mo);
}
Here where i need to check the data is null or not and how to handle it.
You should ideally be doing this where you add the element in your list using add(). This part of code snippet is however NOT on your post above.
Assuming list is defined as ArrayList<String> and val is of String type, you can do something like:
if (val == null) {
list.add("");
}
else {
list.add(val);
}

Has XMLUnit an Output of XPathes with Namespaces?

For my Java program im using XMLUnit 1.5, wich compares two XML-Files (with Namespaces). But the XPathes, I get, do not contain any Namespaces. How I can tell XMLUnit todo that? Is that possible?
Here is my code:
control = new FileReader(file1);
test = new FileReader(file2);
list = new ArrayList<Unterschied>();
Diff diff;
diff = new Diff(control, test);
diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
if (diff.similar())
{
MessageDialog.openInformation(null, "Info", "Similar");
}
else if (!diff.similar())
{
DetailedDiff detDiff = new DetailedDiff(diff);
detDiff.overrieElementQualifier(new ElementNameAndAttributeQualifier());
#SuppressWarnings("unchecked")
List<Object> differences = detDiff.getAllDifferences();
for (Object object : differences)
{
Difference difference = (Difference) object;
if (!difference.isRecoverable() && !difference.getDescription().contains("number of child nodes"))
{
controlXPath = difference.getControlNodeDetail().getXpathLocation(); // without Namespaces!
controlValue = difference.getControlNodeDetail().getValue();
testXPath = difference.getTestNodeDetail().getXpathLocation(); // without Namespaces!
testValue = difference.getTestNodeDetail().getValue();
list.add(new Unterschied(controlOrt, controlWert, testOrt, testWert));
}
}
Later in my program I evaluating these XPathes for getting the correct position of this node. With these position I select the appropriate text in the editor, so that the user can see the Difference.
My code for evaluating:
public void evaluateXPath(String xp, Node node) {
XPath newXPath = new XPathFactoryImpl().newXPath();
XPathExpression xpExp = newXPath.compile(xpath);
NodeList nodeList = (NodeList) xpExp.evaluate(node, XPathConstants.NODESET);
int length = nodeList.getLength();
for (int i=0; i < length; i++) {
IDOMNode iDOMnode = (IDOMNode) nodeList.item(i);
textEditor.selectAndReveal(iDOMnode.getStartOffset(), iDOMnode.getEndOffset()-iDOMnode.getStartOffset());
}
}
Thanks for your help and sorry for my bad english! ;)
No, XMLUnit 1.x will only return plain XPath without any namespace indication at all.
XMLUnit 2.x (under development) will return XPaths using prefixes for namespaces that can be configured per NS-URI.

XML Parsing using DOM

I have an XML with the following data...
<movies total="3">
<movie cover="9_pro.jpg" Title="A Very " MovieDuration="1.29" showtime="2:50 PM" theatre="UV3"/>
<movie cover="5_pro.jpg" Title="Par" MovieDuration="1.24" showtime=" 12:00 PM" theatre="University Village 3"/>
<movie cover="8_pro.jpg" Title="PinBts" MovieDuration="1.30" showtime="9:20 PM" theatre="University Village 3"/>
</movies>
I want to parse this using JDOM parser in a servlet...I have used the following code so far:
try
{
doc=builder.build(url);
Element root = doc.getRootElement();
List children = root.getChildren();
out.println(root);
for (int i = 0; i < children.size(); i++)
{
Element movieAtt = doc.getRootElement().getChild("movie");
//out.println(movieAtt.getAttributeValue( "cover" ));
out.println(movieAtt.getAttributeValue( "Title" ));
//out.println(movieAtt.getAttributeValue( "MovieDuration" ));
//out.println(movieAtt.getAttributeValue( "showtime" ));
//out.println(movieAtt.getAttributeValue( "theatre" ));
}
}
However my code returns values for the first child element of root repetitively 3 times. I assume this is because i have all 3 child name as "movie" only.
So i want to distinguish these, and make the count to next movie child with attributes like Title="par" etc..
Been figuring out this since so long but could not find. Help would be really appreciable
Your's is not working because even though you are looping 3 times, you are always fetching the same (first) node through:
Element movieAtt = doc.getRootElement().getChild("movie");
Try this:
(untested)
Element root = doc.getRootElement();
List children = root.getChildren();
out.println(root);
if (children != null)
{
for (Element child : children)
{
out.println(child.getAttributeValue( "Title" ));
}
}
The best way is to get the attribute from the children list instead of asking for movieAtt again.
I have never used JDOM but my pseudocode would be as follows:
for (int i = 0; i < children.size(); i++) {
Element e = children.get(i);
String title = e.getAttributeValue("Title");
}

Categories