Thanks for previous replies.
I am parsing XML file using java(SAXParser), i am not sure how to parse the attribute value(meta data) using attribute value. I given two main categoy
<category name="XYZ" /> <category name="ABC"/>
'
<subcategory name="" loc="C://program files" link="www.sample.com" parentnode="XYZ"/>
<subcategory name="" loc="C://program files" link="http://" parentnode="ABC"/>`
In sub category i have linked the main category with parentnode attribute. my question is i want to get all the attribute which is only contains particular parent attribute. (Ex)i want all attribute which is only resides in parent attribute "ABC". is this possible to get a value.
Does the code below is solution for your problem?
XML
<?xml version="1.0"?>
<categories>
<category name="ABC">
<subcategory name="123"
loc="C://program files"
link="www.sample.com"
parentnode="ABC"/>
<subcategory name="456"
loc="C://program files"
link="http://"
parentnode="ABC"/>
</category>
<category name="XYZ">
<subcategory name="123"
loc="C://program files"
link="www.sample.com"
parentnode="XYZ"/>
<subcategory name="456"
loc="C://program files"
link="http://abc.com"
parentnode="XYZ"/>
</category>
</categories>
JAVA
package com.stackoverflow;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Question6855476 {
private static final String CFG_XML_PATH = "D:\\sample\\path\\question6855476.xml";
private static final String searchArg = "ABC";
public static void main(String[] args) {
List locList = getLocsByCategoryName(searchArg);
List linkList = getLinksByCategoryName(searchArg);
printCollection(locList,"LOC");
printCollection(linkList,"LINKS");
}
private static void printCollection(List locList, String string) {
System.out.println();
System.out.println("### Collection: "+string+"\n");
if(locList.isEmpty()) {
System.out.println("\tNo items. Collection is empty.");
} else {
for(Object obj: locList) {
System.out.println("\t"+obj);
}
}
}
private static List getLocsByCategoryName(String catName) {
if(null==catName||catName.length()<=0) {
System.out.println("ERROR: catName is null/blank");
return Collections.EMPTY_LIST;
} else {
return getSubcatAttrValuesByAttrName("loc", catName);
}
}
private static List getLinksByCategoryName(String catName) {
if(null==catName||catName.length()<=0) {
System.out.println("ERROR: catName is null/blank");
return Collections.EMPTY_LIST;
} else {
return getSubcatAttrValuesByAttrName("link", catName);
}
}
private static List<Object> getSubcatAttrValuesByAttrName(String attrName, String catName) {
List<Object> list = new ArrayList<Object>();
if(null==attrName||attrName.length()<=0) {
System.out.println("ERROR: attrName is null/blank");
} else {
try {
File file = new File(CFG_XML_PATH);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
NodeList catLst = doc.getElementsByTagName("category");
for (int i = 0; i < catLst.getLength(); i++) {
Node cat = catLst.item(i);
NamedNodeMap catAttrMap = cat.getAttributes();
Node catAttr = catAttrMap.getNamedItem("name");
if(catName.equals(catAttr.getNodeValue())){ // CLUE!!!
NodeList subcatLst = cat.getChildNodes();
for (int j = 0; j < subcatLst.getLength(); j++) {
Node subcat = subcatLst.item(j);
NamedNodeMap subcatAttrMap = subcat.getAttributes();
if(subcatAttrMap!=null) {
Node subcatAttr = subcatAttrMap.getNamedItem(attrName);
list.add(subcatAttr.getNodeValue());
}
}
}
}
} catch (Exception e) { // FIXME
e.printStackTrace();
}
}
return list;
}
}
I've based on this article
I am assuming you mean you want to get all the attributes of subcategory elements with parentnode attribute value equals to "ABC"? So you want to get the attributes (name="" loc="C://program files" link="http://" parentnode="ABC") in the example you gave?
The basic parsing code should look like this:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
MySAXHandler handler = new MySAXHandler();
handler.setDesireParentNodeAttributeValue("ABC");
parser.parse(xmlInputStream, handler);
/*
*this list contains all the attributes of the subcategory element that has
* parentnode attribute equals to "ABC"
*/
List<Attributes> whatIWant = handler.getDesireAttributes();
//do whatever you wnat with "whatIWant"
....
public class MySAXHandler extends DefaultHandler2
{
private String desirePrentNodeAttributeValue;
private List<Attributes> desireAttributes = new ArrayList<Attributes>();
public void setDesireParentNodeAttributeValue(String val)
{
this.desirePrentNodeAttributeValue = val;
}
public List<Attributes> getDesireAttributes()
{
return desireAttributes;
}
public void startElement(String uri,
String localName,
String qName,
Attributes attributes)
throws SAXException
{
if ("subcategory".equals(localName)
&& attributes
.getValue("parentnode")
.equals(this.desirePrentNodeAttributeValue))
{
desireAttributes.add(attributes);
}
}
}
Once you've parsed you XML you could wander through the data to find what you need, but a better approach may be to use XPath to query the XML.
There some tutorial material here
Related
This is an academic assignment and we are given an extremely large XML file with hundreds of entries like these. For each item we are supposed to list the Manager's ID, the Person's ID of the last person to add an item to the list, and the current number of items. I have read and reread the Oracle DOM API and various Node APIs. We are using JAVA and I cannot for the life of me figure out how to search various 'fields' of each item_list node. Below is an example of the data we are given.
<item_list id="item_list01">
<numitems_intial>5</numitems_initial>
<item>
<date_added>1/1/2014</date_added>
<added_by person="person01" />
</item>
<item>
<date_added>1/6/2014</date_added>
<added_by person="person05" />
</item>
<numitems_current>7</numitems_current>
<manager person="person48" />
</item_list>
<item_list id="item_list02">
<numitems_intial>5</numitems_initial>
<item>
<date_added>1/15/2014</date_added>
<added_by person="person05" />
</item>
<item>
<date_added>1/1/2014</date_added>
<added_by person="person09" />
</item>
<item>
<date_added>1/9/2014</date_added>
<added_by person="person45" />
</item>
<numitems_current>7</numitems_current>
<manager person="person38" />
</item_list>
I've tried doing something similar to:
NodeList nodes = queryDoc.getElementsByTagName("item_list");
for(int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if(node != null) {
System.out.println(node.manager);
}
}
And messing around with this code for a while, but I would like to know how to retrieve data from various fields in each node.
If you are trying to read person attribute of manager tag, you can do it as shown below -
import java.io.IOException;
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.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Test{
public static void main (String[] args)
{
Test test = new Test();
test.readXML();
}
private void readXML()
{
Document doc = null;
try
{
doc = parseXML("/home/abc/Test.xml");
}
catch (ParserConfigurationException e)
{
e.printStackTrace();
}
catch (SAXException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
if(doc != null)
{
NodeList nList = doc.getElementsByTagName("item_list");
for (int i = 0; i < nList.getLength(); i++)
{
Node nNode = nList.item(i);
Element eElement = (Element) nNode;
Element cElement = (Element) eElement.getElementsByTagName("manager").item(0);
System.out.println("Manager ID : " + cElement.getAttribute("person"));
}
}
}
private Document parseXML(String filePath) throws ParserConfigurationException, SAXException, IOException
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(filePath);
doc.getDocumentElement().normalize();
return doc;
}
}
Or, using xml you might need to edit the initial content. I suggest the following approach
import java.io.IOException;
import java.io.StringWriter;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
public class ReadXML {
public static void main(String[] args) {
try {
Document doc = getDocument("/home/abc/Test.xml");
System.out.println(getString(getNodeByName(doc,"item_list01")));
} catch (TransformerException | ParserConfigurationException | IOException | SAXException e) {
// Log e.printStackTrace();
}
}
private static Document getDocument(String filePath) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
return docBuilder.parse(filePath);
}
private static String getString(Node node) throws TransformerException {
StringWriter sw = new StringWriter();
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
return sw.toString();
}
public static Node getNodeByName(Document doc, String nodeName) {
Node node = null;
for (int i = 0; i < doc.getDocumentElement().getChildNodes().getLength(); i++) {
if (!getTagName(doc, i).equals("#text")) {
for (int j = 0; j < getNodeName(doc, i).getChildNodes().getLength(); j++) {
if (getNodeName(doc, i, j).equalsIgnoreCase("item_list") && getNodeAttributes(doc,i,j).equalsIgnoreCase(nodeName)) {
node = getNodeName(doc, i);
}
}
}
}
return node;
}
private static String getTagName(Document doc, int i) {
return getNodeName(doc, i).getNodeName();
}
private static Node getNodeName(Document doc, int i) {
return (doc.getDocumentElement().getChildNodes().item(i));
}
private static String getNodeName(Document doc, int i, int j) {
return getNodeName(doc, i).getChildNodes().item(j).getNodeName();
}
private static String getNodeAttributes(Document doc, int i, int j) {
if(getNodeName(doc, i).getChildNodes().item(j).hasAttributes()){
return getNodeName(doc, i).getChildNodes().item(j).getAttributes().item(0).getNodeValue();
}
return "";
}
}
I have to read and write to and from an XML file. What is the easiest way to read and write XML files using Java?
Here is a quick DOM example that shows how to read and write a simple xml file with its dtd:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE roles SYSTEM "roles.dtd">
<roles>
<role1>User</role1>
<role2>Author</role2>
<role3>Admin</role3>
<role4/>
</roles>
and the dtd:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT roles (role1,role2,role3,role4)>
<!ELEMENT role1 (#PCDATA)>
<!ELEMENT role2 (#PCDATA)>
<!ELEMENT role3 (#PCDATA)>
<!ELEMENT role4 (#PCDATA)>
First import these:
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.w3c.dom.*;
Here are a few variables you will need:
private String role1 = null;
private String role2 = null;
private String role3 = null;
private String role4 = null;
private ArrayList<String> rolev;
Here is a reader (String xml is the name of your xml file):
public boolean readXML(String xml) {
rolev = new ArrayList<String>();
Document dom;
// Make an instance of the DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// use the factory to take an instance of the document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// parse using the builder to get the DOM mapping of the
// XML file
dom = db.parse(xml);
Element doc = dom.getDocumentElement();
role1 = getTextValue(role1, doc, "role1");
if (role1 != null) {
if (!role1.isEmpty())
rolev.add(role1);
}
role2 = getTextValue(role2, doc, "role2");
if (role2 != null) {
if (!role2.isEmpty())
rolev.add(role2);
}
role3 = getTextValue(role3, doc, "role3");
if (role3 != null) {
if (!role3.isEmpty())
rolev.add(role3);
}
role4 = getTextValue(role4, doc, "role4");
if ( role4 != null) {
if (!role4.isEmpty())
rolev.add(role4);
}
return true;
} catch (ParserConfigurationException pce) {
System.out.println(pce.getMessage());
} catch (SAXException se) {
System.out.println(se.getMessage());
} catch (IOException ioe) {
System.err.println(ioe.getMessage());
}
return false;
}
And here a writer:
public void saveToXML(String xml) {
Document dom;
Element e = null;
// instance of a DocumentBuilderFactory
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// use factory to get an instance of document builder
DocumentBuilder db = dbf.newDocumentBuilder();
// create instance of DOM
dom = db.newDocument();
// create the root element
Element rootEle = dom.createElement("roles");
// create data elements and place them under root
e = dom.createElement("role1");
e.appendChild(dom.createTextNode(role1));
rootEle.appendChild(e);
e = dom.createElement("role2");
e.appendChild(dom.createTextNode(role2));
rootEle.appendChild(e);
e = dom.createElement("role3");
e.appendChild(dom.createTextNode(role3));
rootEle.appendChild(e);
e = dom.createElement("role4");
e.appendChild(dom.createTextNode(role4));
rootEle.appendChild(e);
dom.appendChild(rootEle);
try {
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.setOutputProperty(OutputKeys.METHOD, "xml");
tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tr.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "roles.dtd");
tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
// send DOM to file
tr.transform(new DOMSource(dom),
new StreamResult(new FileOutputStream(xml)));
} catch (TransformerException te) {
System.out.println(te.getMessage());
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
} catch (ParserConfigurationException pce) {
System.out.println("UsersXML: Error trying to instantiate DocumentBuilder " + pce);
}
}
getTextValue is here:
private String getTextValue(String def, Element doc, String tag) {
String value = def;
NodeList nl;
nl = doc.getElementsByTagName(tag);
if (nl.getLength() > 0 && nl.item(0).hasChildNodes()) {
value = nl.item(0).getFirstChild().getNodeValue();
}
return value;
}
Add a few accessors and mutators and you are done!
Writing XML using JAXB (Java Architecture for XML Binding):
http://www.mkyong.com/java/jaxb-hello-world-example/
package com.mkyong.core;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Customer {
String name;
int age;
int id;
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
#XmlElement
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
#XmlAttribute
public void setId(int id) {
this.id = id;
}
}
package com.mkyong.core;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JAXBExample {
public static void main(String[] args) {
Customer customer = new Customer();
customer.setId(100);
customer.setName("mkyong");
customer.setAge(29);
try {
File file = new File("C:\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(customer, file);
jaxbMarshaller.marshal(customer, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
The above answer only deal with DOM parser (that normally reads the entire file in memory and parse it, what for a big file is a problem), you could use a SAX parser that uses less memory and is faster (anyway that depends on your code).
SAX parser callback some functions when it find a start of element, end of element, attribute, text between elements, etc, so it can parse the document and at the same time you
get what you need.
Some example code:
http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
The answers only cover DOM / SAX and a copy paste implementation of a JAXB example.
However, one big area of when you are using XML is missing. In many projects / programs there is a need to store / retrieve some basic data structures. Your program has already a classes for your nice and shiny business objects / data structures, you just want a comfortable way to convert this data to a XML structure so you can do more magic on it (store, load, send, manipulate with XSLT).
This is where XStream shines. You simply annotate the classes holding your data, or if you do not want to change those classes, you configure a XStream instance for marshalling (objects -> xml) or unmarshalling (xml -> objects).
Internally XStream uses reflection, the readObject and readResolve methods of standard Java object serialization.
You get a good and speedy tutorial here:
To give a short overview of how it works, I also provide some sample code which marshalls and unmarshalls a data structure.
The marshalling / unmarshalling happens all in the main method, the rest is just code to generate some test objects and populate some data to them.
It is super simple to configure the xStream instance and marshalling / unmarshalling is done with one line of code each.
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.XStream;
public class XStreamIsGreat {
public static void main(String[] args) {
XStream xStream = new XStream();
xStream.alias("good", Good.class);
xStream.alias("pRoDuCeR", Producer.class);
xStream.alias("customer", Customer.class);
Producer a = new Producer("Apple");
Producer s = new Producer("Samsung");
Customer c = new Customer("Someone").add(new Good("S4", 10, new BigDecimal(600), s))
.add(new Good("S4 mini", 5, new BigDecimal(450), s)).add(new Good("I5S", 3, new BigDecimal(875), a));
String xml = xStream.toXML(c); // objects -> xml
System.out.println("Marshalled:\n" + xml);
Customer unmarshalledCustomer = (Customer)xStream.fromXML(xml); // xml -> objects
}
static class Good {
Producer producer;
String name;
int quantity;
BigDecimal price;
Good(String name, int quantity, BigDecimal price, Producer p) {
this.producer = p;
this.name = name;
this.quantity = quantity;
this.price = price;
}
}
static class Producer {
String name;
public Producer(String name) {
this.name = name;
}
}
static class Customer {
String name;
public Customer(String name) {
this.name = name;
}
List<Good> stock = new ArrayList<Good>();
Customer add(Good g) {
stock.add(g);
return this;
}
}
}
Ok, already having DOM, JaxB and XStream in the list of answers, there is still a complete different way to read and write XML: Data projection You can decouple the XML structure and the Java structure by using a library that provides read and writeable views to the XML Data as Java interfaces. From the tutorials:
Given some real world XML:
<weatherdata>
<weather
...
degreetype="F"
lat="50.5520210266113" lon="6.24060010910034"
searchlocation="Monschau, Stadt Aachen, NW, Germany"
... >
<current ... skytext="Clear" temperature="46"/>
</weather>
</weatherdata>
With data projection you can define a projection interface:
public interface WeatherData {
#XBRead("/weatherdata/weather/#searchlocation")
String getLocation();
#XBRead("/weatherdata/weather/current/#temperature")
int getTemperature();
#XBRead("/weatherdata/weather/#degreetype")
String getDegreeType();
#XBRead("/weatherdata/weather/current/#skytext")
String getSkytext();
/**
* This would be our "sub projection". A structure grouping two attribute
* values in one object.
*/
interface Coordinates {
#XBRead("#lon")
double getLongitude();
#XBRead("#lat")
double getLatitude();
}
#XBRead("/weatherdata/weather")
Coordinates getCoordinates();
}
And use instances of this interface just like POJOs:
private void printWeatherData(String location) throws IOException {
final String BaseURL = "http://weather.service.msn.com/find.aspx?outputview=search&weasearchstr=";
// We let the projector fetch the data for us
WeatherData weatherData = new XBProjector().io().url(BaseURL + location).read(WeatherData.class);
// Print some values
System.out.println("The weather in " + weatherData.getLocation() + ":");
System.out.println(weatherData.getSkytext());
System.out.println("Temperature: " + weatherData.getTemperature() + "°"
+ weatherData.getDegreeType());
// Access our sub projection
Coordinates coordinates = weatherData.getCoordinates();
System.out.println("The place is located at " + coordinates.getLatitude() + ","
+ coordinates.getLongitude());
}
This works even for creating XML, the XPath expressions can be writable.
SAX parser is working differently with a DOM parser, it neither load any XML document into memory nor create any object representation of the XML document. Instead, the SAX parser use callback function org.xml.sax.helpers.DefaultHandler to informs clients of the XML document structure.
SAX Parser is faster and uses less memory than DOM parser.
See following SAX callback methods :
startDocument() and endDocument() – Method called at the start and end of an XML document.
startElement() and endElement() – Method called at the start and end of a document element.
characters() – Method called with the text contents in between the start and end tags of an XML document element.
XML file
Create a simple XML file.
<?xml version="1.0"?>
<company>
<staff>
<firstname>yong</firstname>
<lastname>mook kim</lastname>
<nickname>mkyong</nickname>
<salary>100000</salary>
</staff>
<staff>
<firstname>low</firstname>
<lastname>yin fong</lastname>
<nickname>fong fong</nickname>
<salary>200000</salary>
</staff>
</company>
XML parser:
Java file Use SAX parser to parse the XML file.
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ReadXMLFile {
public static void main(String argv[]) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
boolean bfname = false;
boolean blname = false;
boolean bnname = false;
boolean bsalary = false;
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
System.out.println("Start Element :" + qName);
if (qName.equalsIgnoreCase("FIRSTNAME")) {
bfname = true;
}
if (qName.equalsIgnoreCase("LASTNAME")) {
blname = true;
}
if (qName.equalsIgnoreCase("NICKNAME")) {
bnname = true;
}
if (qName.equalsIgnoreCase("SALARY")) {
bsalary = true;
}
}
public void endElement(String uri, String localName,
String qName) throws SAXException {
System.out.println("End Element :" + qName);
}
public void characters(char ch[], int start, int length) throws SAXException {
if (bfname) {
System.out.println("First Name : " + new String(ch, start, length));
bfname = false;
}
if (blname) {
System.out.println("Last Name : " + new String(ch, start, length));
blname = false;
}
if (bnname) {
System.out.println("Nick Name : " + new String(ch, start, length));
bnname = false;
}
if (bsalary) {
System.out.println("Salary : " + new String(ch, start, length));
bsalary = false;
}
}
};
saxParser.parse("c:\\file.xml", handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Result
Start Element :company
Start Element :staff
Start Element :firstname
First Name : yong
End Element :firstname
Start Element :lastname
Last Name : mook kim
End Element :lastname
Start Element :nickname
Nick Name : mkyong
End Element :nickname
and so on...
Source(MyKong) - http://www.mkyong.com/java/how-to-read-xml-file-in-java-sax-parser/
I'm making a Java application that displays X3D models and I'm creating an XML parser for it. The Java code that I have for it is
package domparserexample.java;
import java.io.IOException;
import java.util.Iterator;
import javax.lang.model.element.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DomParserExampleJava {
private void parseXmlFile() throws IOException, ParserConfigurationException{
//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("employees.xml");
}catch(SAXException se) {
se.printStackTrace();
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
private void parseDocument(){
//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);
}
}
}
/**
* I take an employee element and read the values in, create
* an Employee object and return it
*/
private Employee getEmployee(Element empEl) {
//for each <employee> element get text or int values of
//name ,id, age and name
String name = getTextValue(empEl,"Name");
int id = getIntValue(empEl,"Id");
int age = getIntValue(empEl,"Age");
String type = empEl.getAttribute("type");
//Create a new Employee with the value read from the xml nodes
Employee e = new Employee(name,id,age,type);
return e;
}
private String getTextValue(Element ele, String tagName) {
String textVal = null;
NodeList nl = ele.getElementsByTagName(tagName);
if(nl != null && nl.getLength() > 0) {
Element el = (Element)nl.item(0);
textVal = el.getFirstChild().getNodeValue();
}
return textVal;
}
private int getIntValue(Element ele, String tagName) {
//in production application you would catch the exception
return Integer.parseInt(getTextValue(ele,tagName));
}
private void printData(){
System.out.println("No of Employees '" + myEmpls.size() + "'.");
Iterator it = myEmpls.iterator();
while(it.hasNext()) {
System.out.println(it.next().toString());
}
}
}
And the XML code is:
<?xml version="1.0" encoding="UTF-8"?>
<Personnel>
<Employee type="permanent">
<Name>Seagull</Name>
<Id>3674</Id>
<Age>34</Age>
</Employee>
<Employee type="contract">
<Name>Robin</Name>
<Id>3675</Id>
<Age>25</Age>
</Employee>
<Employee type="permanent">
<Name>Crow</Name>
<Id>3676</Id>
<Age>28</Age>
</Employee>
</Personnel>
However, I'm getting some errors on lines 49, 76, 93, and 96 in the DomParserExample.java file and I don't know why it's happening. All the errors say that they cannot find symbol and symbol: method getElemantsByTagName(String), symbol: method getAttribute(String), symbol: method getElementByTagName(String), and symbol: method getFirstChild().
For me it is working with the following code. I made some changes to your code.
DomParserExampleJava.java
package domparserexample.java;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
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.SAXException;
public class DomParserExampleJava {
private List<Employee> myEmpls = new ArrayList<Employee>();
public static void main(String[] args) throws IOException, ParserConfigurationException {
DomParserExampleJava domParser = new DomParserExampleJava();
domParser.parseXmlFile();
}
private void parseXmlFile() throws IOException, ParserConfigurationException {
// 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("employees.xml");
parseDocument(dom);
printData();
} catch (SAXException se) {
se.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
private void parseDocument(Document dom) {
// 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);
}
}
}
/**
* I take an employee element and read the values in, create an Employee object and return it
*/
private Employee getEmployee(Element empEl) {
// for each <employee> element get text or int values of
// name ,id, age and name
String name = getTextValue(empEl, "Name");
int id = getIntValue(empEl, "Id");
int age = getIntValue(empEl, "Age");
String type = empEl.getAttribute("type");
// Create a new Employee with the value read from the xml nodes
Employee e = new Employee(name, id, age, type);
return e;
}
private String getTextValue(Element ele, String tagName) {
String textVal = null;
NodeList nl = ele.getElementsByTagName(tagName);
if (nl != null && nl.getLength() > 0) {
Element el = (Element) nl.item(0);
textVal = el.getFirstChild().getNodeValue();
}
return textVal;
}
private int getIntValue(Element ele, String tagName) {
// in production application you would catch the exception
return Integer.parseInt(getTextValue(ele, tagName));
}
private void printData() {
System.out.println("No of Employees '" + myEmpls.size() + "'.");
Iterator<Employee> it = myEmpls.iterator();
while (it.hasNext()) {
System.out.println(it.next().toString());
}
}
}
Employee.java
package domparserexample.java;
public class Employee {
private String name;
private int id;
private int age;
private String type;
public Employee(String name, int id, int age, String type) {
this.name = name;
this.id = id;
this.age = age;
this.type = type;
}
public String toString() {
return id + ": " + name + ", age: " + age + ", type: " + type;
}
}
employees.xml
In your example <?xml version="1.0" encoding="UTF-8"?> appears a second time in the middle of the XML document. This lead to an error.
<?xml version="1.0" encoding="UTF-8"?>
<Personnel>
<Employee type="permanent">
<Name>Seagull</Name>
<Id>3674</Id>
<Age>34</Age>
</Employee>
<Employee type="contract">
<Name>Robin</Name>
<Id>3675</Id>
<Age>25</Age>
</Employee>
<Employee type="permanent">
<Name>Crow</Name>
<Id>3676</Id>
<Age>28</Age>
</Employee>
</Personnel>
If I execute the Java file it returns:
No of Employees '3'.
3674: Seagull, age: 34, type: permanent
3675: Robin, age: 25, type: contract
3676: Crow, age: 28, type: permanent
You are using the wrong ELementclass:
import javax.lang.model.element.Element;
is wrong, use:
import org.w3c.dom.Element;
That should work.
I'm using SAX (Simple API for XML) to parse an XML document. I'm getting output for all the tags the file have, but i want it to show the tags in parent child hierarchy.
For Example:
This is my output
<dblp>
<www>
<author>
</author><title>
</title><url>
</url><year>
</year></www><inproceedings>
<month>
</month><pages>
</pages><booktitle>
</booktitle><note>
</note><cdrom>
</cdrom></inproceedings><article>
<journal>
</journal><volume>
</volume></article><ee>
</ee><book>
<publisher>
</publisher><isbn>
</isbn></book><incollection>
<crossref>
</crossref></incollection><editor>
</editor><series>
</series></dblp>
But i want it to display the output like this (it displays the children with extra spacing (that's how i want it to be))
<dblp>
<www>
<author>
</author>
<title>
</title>
<url>
</url>
<year>
</year>
</www>
<inproceedings>
<month>
</month>
<pages>
</pages>
<booktitle>
</booktitle>
<note>
</note>
<cdrom>
</cdrom>
</inproceedings>
<article>
<journal>
</journal>
<volume>
</volume>
</article>
<ee>
</ee>
<book>
<publisher>
</publisher>
<isbn>
</isbn>
</book>
<incollection>
<crossref>
</crossref>
</incollection>
<editor>
</editor>
<series>
</series>
</dblp>
But i can't figure out how can i detect that parser is parsing a parent tag or a children.
here is my code:
package com.teamincredibles.sax;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class Parser extends DefaultHandler {
public void getXml() {
try {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
final MySet openingTagList = new MySet();
final MySet closingTagList = new MySet();
DefaultHandler defaultHandler = new DefaultHandler() {
public void startDocument() throws SAXException {
System.out.println("Starting Parsing...\n");
}
public void endDocument() throws SAXException {
System.out.print("\n\nDone Parsing!");
}
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (!openingTagList.contains(qName)) {
openingTagList.add(qName);
System.out.print("<" + qName + ">\n");
}
}
public void characters(char ch[], int start, int length)
throws SAXException {
/*for(int i=start; i<(start+length);i++){
System.out.print(ch[i]);
}*/
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (!closingTagList.contains(qName)) {
closingTagList.add(qName);
System.out.print("</" + qName + ">");
}
}
};
saxParser.parse("xml/sample.xml", defaultHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
Parser readXml = new Parser();
readXml.getXml();
}
}
You can consider a StAX implementation:
package be.duo.stax;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public class StaxExample {
public void getXml() {
InputStream is = null;
try {
is = new FileInputStream("c:\\dev\\sample.xml");
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory.createXMLStreamReader(is);
parse(reader, 0);
} catch(Exception ex) {
System.out.println(ex.getMessage());
} finally {
if(is != null) {
try {
is.close();
} catch(IOException ioe) {
System.out.println(ioe.getMessage());
}
}
}
}
private void parse(XMLStreamReader reader, int depth) throws XMLStreamException {
while(true) {
if(reader.hasNext()) {
switch(reader.next()) {
case XMLStreamConstants.START_ELEMENT:
writeBeginTag(reader.getLocalName(), depth);
parse(reader, depth+1);
break;
case XMLStreamConstants.END_ELEMENT:
writeEndTag(reader.getLocalName(), depth-1);
return;
}
}
}
}
private void writeBeginTag(String tag, int depth) {
for(int i = 0; i < depth; i++) {
System.out.print(" ");
}
System.out.println("<" + tag + ">");
}
private void writeEndTag(String tag, int depth) {
for(int i = 0; i < depth; i++) {
System.out.print(" ");
}
System.out.println("</" + tag + ">");
}
public static void main(String[] args) {
StaxExample app = new StaxExample();
app.getXml();
}
}
There is an idiom for StAX with a loop like this for every tag in the XML:
private MyTagObject parseMyTag(XMLStreamReader reader, String myTag) throws XMLStreamException {
MyTagObject myTagObject = new MyTagObject();
while (true) {
switch (reader.next()) {
case XMLStreamConstants.START_ELEMENT:
String localName = reader.getLocalName();
if(localName.equals("myOtherTag1")) {
myTagObject.setMyOtherTag1(parseMyOtherTag1(reader, localName));
} else if(localName.equals("myOtherTag2")) {
myTagObject.setMyOtherTag2(parseMyOtherTag2(reader, localName));
}
// and so on
break;
case XMLStreamConstants.END_ELEMENT:
if(reader.getLocalName().equals(myTag) {
return myTagObject;
}
break;
}
}
well what have you tried? you should use a transformer found here: How to pretty print XML from Java?
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
Almost any useful SAX application needs to maintain a stack. When startElement is called, you push information to the stack, when endElement is called, you pop the stack. Exactly what you put on the stack depends on the application; it's often the element name. For your application, you don't actually need a full stack, you only need to know its depth. You could get by with maintaining this using depth++ in startElement and depth-- in endElement(). Then you just output depth spaces before the element name.
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().