So I have an XML file in the format:
<projectlist>
<project>
<name>test</name>
<type>deploy</type>
<environment>dev</environment>
<server>test01</server>
<server>test02</server>
<server>test03</server>
</project>
</projectlist>
I'm trying to parse this file and build an object that I can populate a JListBox with the names and a radiobutton group with the different servers, however each project consists of a different amount of servers. How do I iterate the nodes/childnodes to build the object with multiple servers. Here is snippets of the code I'm using borrowed from a website and some from me and I'm not very good at coding yet so bear with me please. When I debug it starts to parse & build the object but once it gets to the server names it prints a null pointer exception so I'm doing something totally wrong.
public class XMLParser {
public Project currentProject = new Project();
public void parseXML() throws Exception {
try {
File file = new File("c:\\projectlist.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(file);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("project");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
currentProject.SetAppName(getTagValue("name", eElement));
currentProject.SetType(getTagValue("type", eElement));
currentProject.SetEnvironment(getTagValue("environment", eElement));
currentProject.SetServerName(getTagValue("server", eElement));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getTagValue(String sTag, Element eElement) {
NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
Node nValue = (Node) nlList.item(0);
return nValue.getNodeValue();
}
public final class Project {
protected String AppName = null;
protected String Type = null;
protected List<String> ServerNames = null;
protected String Environment = null;
public void SetAppName(String AppName) {
this.AppName = AppName;
}
public void SetType(String DeployType) {
this.Type = DeployType;
}
public void SetServerName(String ServerName) {
this.ServerNames.add(ServerName);
}
public void SetEnvironment(String Environment) {
this.Environment = Environment;
}
public String getAppName() {
return AppName;
}
public String getType() {
return Type;
}
public List<String> getServerName() {
return ServerNames;
}
public String getEnvironment() {
return Environment;
}
}
Your exception is being caused because you didn't initialize ServerNames in your Project class. Try to initialize it as follows and rerun:
final protected List<String> ServerNames = new ArrayList<String>();
If your xml was created using an xsd schema, you could instead use JAXB to create classes for it, using the xjc tool. That should make your life a bit easier.
Related
public void loadSettings() {
try {
File inputFile = new File("data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("Setting");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nList.item(temp);
NodeList VariableName = eElement.getElementsByTagName("VariableName");
NodeList VariableValue = eElement.getElementsByTagName("VariableValue");
System.out.println(VariableName.item(0).getTextContent());
if (VariableName.item(0).hasChildNodes()) {
}
// txtBookmarkUrl.setText(bookMarkUrl);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I want to make a function that gets second part of the xml in settings elements. I want the function to return a result so that i can assign it to textfield default value when the swing GUI starts. The function should take let's say 'isDecaptcher' variable name and return '0' VariableValue.
<Bookmark>
<Setting>
<VariableName>isDeathbycaptcha</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>isDecaptcher</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>isExpertdecoders</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>ManualCaptcha</VariableName>
<VariableValue>1</VariableValue>
</Setting>
</Bookmark>
public void loadSettings(String variableName) {
try {
File inputFile = new File("data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("Setting");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nList.item(temp);
NodeList VariableName = eElement.getElementsByTagName("VariableName");
NodeList VariableValue = eElement.getElementsByTagName("VariableValue");
if (VariableName.item(0).getTextContent().equalsIgnoreCase(variableName)) {
String txtBookmarkUrlValue = VariableValue.item(0).getLastChild().getTextContent();
System.out.println(txtBookmarkUrlValue);
txtBookmarkUrl.setText(txtBookmarkUrlValue);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This works, But if you have more robust answers you can share.
First of all create an Object wich will represent your settings. The case is to reuse it's values in whole app. I assume that you will use it only once at the beginning and settings will not change. Singleton pattern would fit there.
final class Settings{
private static volatile Settings instance = null;
private boolean _isDeathByCaptcha;
private boolean _manualCaptcha;
...
//getters & setters
public boolean isDeathByCaptcha(){
return _isDeathByCaptcha;
}
public void setIsDeathByCaptcha(boolean isDeathByCaptcha){
this._isDeathByCaptcha = isDeathByCaptcha;
}
private Settings(){}
public static Settings getInstance(){
if(instance == null){
synchronized (Settings.class) {
if (instance == null) {
instance = new Settings();
}
}
}
return instance;
}
}
After that you can call Settings.getInstance().isDeathByCaptcha(); to get your value. Of course you need to set it earlier with setter.
I'm getting hard time in figuring how to write a loop to retrieve values from a given XML document for simplicity I'll give you a sample of the xml file
</solution>
<solution>
<cost>505.9208295302417</cost>
<routes>
<route>
<driverId>noDriver</driverId>
<vehicleId>1_1</vehicleId>
<start>0.0</start>
<act type="service">
<serviceId>5 </serviceId>
<arrTime>109.9819741964403</arrTime>
<endTime>119.9819741964403</endTime>
</act>
<end>229.9639483928806</end>
</route>
<route>
<driverId>noDriver</driverId>
<vehicleId>3_1</vehicleId>
<start>0.0</start>
<act type="service">
<serviceId>4 </serviceId>
<arrTime>109.98190391287031</arrTime>
<endTime>119.98190391287031</endTime>
</act>
<act type="service">
<serviceId>2 </serviceId>
<arrTime>119.98282618841856</arrTime>
<endTime>129.98282618841856</endTime>
</act>
<act type="service">
<serviceId>1 </serviceId>
<arrTime>129.98372097890456</arrTime>
<endTime>139.98372097890456</endTime>
</act>
<act type="service">
<serviceId>3 </serviceId>
<arrTime>139.9846432544528</arrTime>
<endTime>149.9846432544528</endTime>
</act>
<end>259.9668316441239</end>
</route>
</routes>
</solution>
</solutions>
so basically what I've in the code that I'll be showing you is to obtain value from only the node where there is cost = 505.9208295302417, please don't take into account this part of the code, so the next step was to retrieve driverid``, vehicleid and act , I know that there is a missing for loop but I don't know where to put it!! please can someone help. The desired output that i need to have is like for every vehicleid obtain list act values associated with it
java code
public static void main(String[] args) {
try {
int totalVehicle;
totalVehicle = 2;
File fXmlFile = new File("C:/Users/HP/Desktop/solution.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
Double requiredCost = 505.9208295302417;
System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
// NodeList nList = doc.getElementsByTagName("route");
System.out.println("----------------------------");
NodeList nodeList = doc.getElementsByTagName("solution");
for (int i = 0; i < nodeList.getLength(); i++) {
Node solutionNode = nodeList.item(i);
if (solutionNode.getNodeType() == Node.ELEMENT_NODE) {
Element solutionElement = (Element) solutionNode;
Node costNode = solutionElement.getElementsByTagName("cost").item(0);
Node route = solutionElement.getElementsByTagName("routes").item(0);
// if correct cost, proceed to parse further
Double costValue = Double.valueOf(costNode.getTextContent());
if (Double.compare(requiredCost, costValue) == 0) {
System.out.println("working");
// there you go, found the node with the cost 505.9208295302417
// now just parse all the node elements you need here
System.out.println("cost : "
+ solutionElement.getElementsByTagName("cost")
.item(0).getTextContent());
for (int h = 0; h < totalVehicle; h++) {
System.out.println("DriverId : "
+ solutionElement.getElementsByTagName("driverId")
.item(h).getTextContent().toString());
System.out.println("vehicleId : "
+ solutionElement.getElementsByTagName("vehicleId")
.item(h).getTextContent());
NodeList optionList = solutionElement.getElementsByTagName("act");
System.out.println(optionList.getLength());
for (int j = 0; j < optionList.getLength(); ++j)
{
for(int k =0;k<1;++k){
Element option = (Element) optionList.item(j);
String optionText = option.getTextContent();
//address.add(optionText.replaceAll("[^A-Za-z]"," "));
System.out.println("Citizen :"+optionText.replaceAll("[^A-Za-z]"," "));}
;
}
As others have suggested, using xpath would be much easier but if it's an absolute requirement that you loop over all this stuff, break the problem into smaller, more manageable pieces. I thought I'd give it a try and I have a complete, working solution to your problem.
The idea is to break xml up into Java objects and use those objects to do the work you need.
public static void main(String... args) throws SAXException, IOException, ParserConfigurationException {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new File("/home/william/Documents/test.xml"));
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("solution");
for (int i = 0; i < nodeList.getLength(); i++) {
Node solutionNode = nodeList.item(i);
try {
System.out.println(Solution.newInstance(solutionNode).toString());
} catch (Exception e) {
// do something
e.printStackTrace();
}
}
}
Here, your original document parsed the same way you did it but Solution is its own class you can put the logic in:
public class Solution {
private final double cost;
private final Collection<Route> routes;
public static final Solution newInstance(Node solution) throws Exception {
return new Solution(solution);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("solution:");
sb.append(System.lineSeparator());
sb.append("--------");
sb.append(System.lineSeparator());
sb.append("cost:");
sb.append(this.cost);
for (Route route : this.routes) {
sb.append(route.toString());
}
return sb.toString();
}
private Solution(Node solution) throws Exception {
if (solution.getNodeType() == Node.ELEMENT_NODE) {
Element solutionElement = (Element) solution;
this.cost = Double.valueOf(solutionElement.getElementsByTagName("cost").item(0).getTextContent());
this.routes = Routes.get(solutionElement.getElementsByTagName("routes").item(0));
} else {
// TODO something?
this.cost = 0D;
this.routes = Collections.emptyList();
}
}
}
Note that in your main method you have a check on the cost. I've left all class variable getter methods out, add the ones you need if you need to read them from outside the object. So for example in your Solution class add a getCost() method and then in the main method you can check as appropriate: if (solution.getCost() == requiredCost) { ...
Here, based on your requirements, you could add getters to the class members if needed. I've just overridden the toString() method in order to print something you can read.
Routes is a util class to create a collection of Route objects out of the child nodes of the <routes> node.
public class Routes {
private final Collection<Route> items;
public static Collection<Route> get(Node routes) throws Exception {
return new Routes(routes).items;
}
private Routes() {
this.items = new ArrayList<>();
}
private Routes(Node routes) throws Exception {
this.items = new ArrayList<>();
NodeList routesList = routes.getChildNodes();
for (int i = 0; i < routesList.getLength(); i++) {
Node route = routesList.item(i);
if (Node.ELEMENT_NODE == route.getNodeType()) {
items.add(Route.newInstance(route));
} else {
// TODO something?
}
}
}
}
The Acts class has similar logic to the Routes class (same thing but for acts):
public class Acts {
private Collection<Act> items;
public static Collection<Act> get(NodeList acts) throws Exception {
return new Acts(acts).items;
}
private Acts() {
this.items = new ArrayList<>();
}
private Acts(NodeList acts) throws Exception {
this.items = new ArrayList<>();
for (int i = 0; i < acts.getLength(); i++) {
Node act = acts.item(i);
if (Node.ELEMENT_NODE == act.getNodeType()) {
this.items.add(Act.newInstance(act));
} else {
// TODO something?
}
}
}
}
and finally, each individual Act:
public class Act {
private final String service;
private final double arrTime;
private final double endTime;
public static Act newInstance(Node act) throws Exception {
return new Act(act);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Act");
sb.append(System.lineSeparator());
sb.append("arr time");
sb.append(System.lineSeparator());
sb.append(this.arrTime);
sb.append(System.lineSeparator());
sb.append("end time:");
sb.append(System.lineSeparator());
sb.append(this.endTime);
sb.append(System.lineSeparator());
sb.append("service:");
sb.append(System.lineSeparator());
sb.append(this.service);
return sb.toString();
}
private Act(Node act) throws Exception {
Element actElement = (Element) act;
this.service = actElement.getAttribute("service");
this.arrTime = Double.valueOf(actElement.getElementsByTagName("arrTime").item(0).getTextContent());
this.endTime = Double.valueOf(actElement.getElementsByTagName("endTime").item(0).getTextContent());
}
}
I have an xml document to parse which have nested nodes I have tried in my way but unable to get job done as desired.
XML doc is
<Items>
<Item>
<MediumImage>
<URL>http://ecx.images-amazon.com/images/I/51l7DDD1qNL._SL160_.jpg</URL>
<Height Units="pixels">160</Height>
<Width Units="pixels">160</Width>
</MediumImage>
<Title>Fallout 4 Vault Dweller's Survival Guide Collector's Edition: Prima Official Game Guide</Title>
<OfferSummary>
<LowestNewPrice>
<Amount>1952</Amount>
</OfferSummary>
</Item>
.
.
.
</Items>
I have done to fetch Title node values as
private static NodeList fetchTitle(String requestUrl) {
NodeList nodeList = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(requestUrl);
nodeList = doc.getElementsByTagName("Title");
} catch (Exception e) {
System.out.println("Message is " + e.getCause() + "...." + e.getMessage());
throw new RuntimeException(e);
}
return nodeList;
}
and I print as in main() as
titleList = fetchTitle(requestUrl);
for (int i = 0; i < titleList.getLength(); i++) {
Node node = titleList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
// do something with the current element
System.out.println(node.getNodeName());
System.out.println("Signed Title is \"" + node.getTextContent() + "\"");
System.out.println();
}
}
and Amount value from LowestNewPrice Node as
private static NodeList fetchPrice(String requestUrl) {
NodeList nodeList = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(requestUrl);
nodeList = doc.getElementsByTagName("LowestNewPrice");
} catch (Exception e) {
System.out.println("Message is " + e.getCause() + "...." + e.getMessage());
throw new RuntimeException(e);
}
return nodeList;
}
and I print as in main() as
priceList = fetchPrice(requestUrl);
for (int i = 0; i < priceList.getLength(); i++) {
Node node = priceList.item(i).getFirstChild();
if (node.getNodeType() == Node.ELEMENT_NODE) {
// do something with the current element
System.out.println(node.getNodeName());
System.out.println("Signed Price is \"" + node.getTextContent() + "\"");
System.out.println();
}
}
through above code I get all Title values first and then I get Amount values separately, but what I really want is to have a POJO class as
public class Item {
String title;
String price;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
and add values to Item object using setTitle(), setPrice(), and return a List<Item>
any help please.
You might try this solution please.
Parse your data and add to List<Item> as :
public static Document fetchRequiredData(String src) {
Document doc = null;
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser;
try {
parser = dbFactory.newDocumentBuilder();
doc= parser.parse(src);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return doc;
}
public static List<Item> parseItemInfo(Document doc){
List<Item> items = new ArrayList<Item>();
NodeList itemNodeList = doc.getElementsByTagName("Item");
for (int i = 0; i < itemNodeList.getLength(); i++) {
Node titleNode = doc.getElementsByTagName("Title").item(i);
Node priceNode = doc.getElementsByTagName("LowestNewPrice").item(i).getFirstChild();
if (titleNode.getNodeType() == Node.ELEMENT_NODE || priceNode.getNodeType() == Node.ELEMENT_NODE ) {
Item item = new Item();
item.setDesc(titleNode.getTextContent());
item.setPrice(priceNode.getTextContent());
items.add(item);
}
}
return items;
}
now your List is ready to test in main() method as
public static void main(String[] args) {
List<Item> items = parseItemInfo(fetchRequiredData(requestUrl));
System.out.println("Printing List<Item> contents ...");
for (Item item : items) {
System.out.println("Title is " + item.getTitle());
System.out.println("Price is " + item.getPrice());
System.out.println();
}
}
Hope this one helps.
You can achieve that by using JAXBContext. First create Item class.
#XmlRootElement(name = "Items")
#XmlAccessorType(value = XmlAccessType.FIELD)
public class Items
{
#XmlElement(name = "Item")
private List<Item> item;
public void setItem(List<Item> itemList)
{
this.item = itemList;
}
public List<Item> getItem()
{
return this.item;
}
}
#XmlRootElement(name = "Item")
#XmlAccessorType(vallue = XmlAccessType.FIELD)
public class Item
{
#XmlElement(name = "MediumImage")
private MediumImage image;
#XmlElement(name = "Title")
private String title;
#XmlElement(name = "OfferSummary")
private OfferSummary summary;
getters();
setters();
}
#XmlRootElement(name = "MediumImage")
#XmlAccessorType(value = XmlAccessType.FIELD)
public class MediumImage
{
#XmlElement(name = "URL")
private String url;
....
}
#XmlRootElement(name = "OfferSummary")
#XmlAccessorType(value = XmlAccessType.FIELD)
public class OfferSummary
{
#XmlElement(name = "LowestNewPrice")
private LowestNewPrice lowestPrice;
....
}
Then from the main method use marshaller and unmarshaller method.
public static void main(String[] args)
{
File xmlFile = new File("file path");
JAXBContext context = JAXBContext.newInstance(Items.class);
//To get POJO from xml
Unmarshaller unmarshaller = context.createUnmarshaller();
Items items = (Items) unmarshaller.unmarshal(xmlFile);
}
Currently it seems that you're separating the prices and titles into 2 lists, if you want to store an item's price and title into a single Item object, you can do something like this:
public class Item {
public static void main(String[] args) {
ArrayList<Item> items = new ArrayList<Item>();
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File("items.xml"));
NodeList itemElements = doc.getElementsByTagName("Item");
for (int i = 0; i < itemElements.getLength(); i++) {
Node itemElement = itemElements.item(i);
NodeList itemChildren = itemElement.getChildNodes();
Item item = new Item();
for (int j = 0; j < itemChildren.getLength(); j++) {
Node n = itemChildren.item(j);
if (n.getNodeName().equalsIgnoreCase("title")) {
item.setTitle(n.getTextContent());
} else if (n.getNodeName().equalsIgnoreCase("OfferSummary")) {
NodeList offerChildren = n.getChildNodes();
for (int k = 0; k < offerChildren.getLength(); k++) {
Node offerChild = offerChildren.item(k);
if (offerChild.getNodeName().equalsIgnoreCase("LowestNewPrice")) {
item.setPrice(offerChild.getTextContent());
}
}
}
}
items.add(item);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("items: " + items);
}
String title;
String price;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
#Override
public String toString() {
return "Title: " + title + " Price: " + price;
}
}
What this does is to get all the <Item> elements from the XML and loop through them to get the item's title and price.
I want to parse a very long string from an xml file. You can see the xml file here.
If you visit the above file, there is a "description" tag from which I want to parse the string. When there is a short short string, say 3-lines or 4-lines string in the "description" tag, then my parser(Java SAX parser) easily parse the string but, when the string is hundreds of lines then my parser cannot parse the string. You can check my code that I am using for the parsing and please let me know where I am going wrong in this regard. Please help me in this respect I would be very thankful to you for this act of kindness.
Here is the parser GetterSetter class
public class MyGetterSetter
{
private ArrayList<String> description = new ArrayList<String>();
public ArrayList<String> getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description.add(description);
}
}
Here is the parser Handler class
public class MyHandler extends DefaultHandler
{
String elementValue = null;
Boolean elementOn = false;
Boolean item = false;
public static MyGetterSetter data = null;
public static MyGetterSetter getXMLData()
{
return data;
}
public static void setXMLData(MyGetterSetter data)
{
MyHandler.data = data;
}
public void startDocument() throws SAXException
{
data = new MyGetterSetter();
}
public void endDocument() throws SAXException
{
}
public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException
{
elementOn = true;
if (localName.equalsIgnoreCase("item"))
item = true;
}
public void endElement(String namespaceURI, String localName, String qName) throws SAXException
{
elementOn = false;
if(item)
{
if (localName.equalsIgnoreCase("description"))
{
data.setDescription(elementValue);
Log.d("--------DESCRIPTION------", elementValue +" ");
}
else if (localName.equalsIgnoreCase("item")) item = false;
}
}
public void characters(char ch[], int start, int length)
{
if (elementOn)
{
elementValue = new String(ch, start, length);
elementOn = false;
}
}
}
Use the org.w3c.dom package.
public static void main(String[] args) {
try {
URL url = new URL("http://www.aboutsports.co.uk/fixtures/");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(url.openStream());
NodeList list = doc.getElementsByTagName("item"); // get <item> nodes
for (int i = 0; i < list.getLength(); i++) {
Node item = list.item(i);
NodeList descriptions = ((Element)item).getElementsByTagName("description"); // get <description> nodes within an <item>
for (int j = 0; j < descriptions.getLength(); j++) {
Node description = descriptions.item(0);
System.out.println(description.getTextContent()); // print the text content
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
XPath in java is also great for extracting bits from XML documents. Here's an example.
You would use a XPathExpression like /item/description. When you would evaluate it on the XML InputStream, it would return a NodeList like above with all the <description> elements within a <item> element.
If you wanted to do it your way, with a DefaultHandler, you would need to set and unset flags so you can check if you are in the body of a <document> element. The code above probably does something similar internally, hiding it from you. The code is available in java, so why not use it?
Here is my xml code...
<flow>
<TaskID>100</TaskID>
<TaskID>101</TaskID>
<TaskID>102</TaskID>
<TaskID>103</TaskID>
</flow>
I want to know how to get taskID values in a for loop in java. Please help me...
DOM parser solution, fairly simple, no extra libraries required.
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
String input = "<outer>";
input += "<otherstuff><TaskID>123</TaskID></otherstuff>";
input += "<flow>";
input += "<TaskID>100</TaskID>";
input += "<TaskID>101</TaskID>";
input += "<TaskID>102</TaskID>";
input += "<TaskID>103</TaskID>";
input += "</flow>";
input += "</outer>";
Document document = builder.parse(new InputSource(new StringReader(
input)));
NodeList flowList = document.getElementsByTagName("flow");
for (int i = 0; i < flowList.getLength(); i++) {
NodeList childList = flowList.item(i).getChildNodes();
for (int j = 0; j < childList.getLength(); j++) {
Node childNode = childList.item(j);
if ("TaskID".equals(childNode.getNodeName())) {
System.out.println(childList.item(j).getTextContent()
.trim());
}
}
}
}
You'd need to use a FileReader instead if your input came from a file.
Document document = builder.parse(new InputSource(new FileReader(
new File("foo.xml"))));
An alternative to getElementsByTagName() is XPath, a query language for XML, this is particularly useful if you have complicated set of conditions to match.
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//flow/TaskID/text()");
Object result = expr.evaluate(document, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getTextContent());
}
If your XML file is large, like 100s of MB / GB or you're on a low memory platform then consider a SAX parser.
String input = "<flow><TaskID>100</TaskID><TaskID>101</TaskID><TaskID>102</TaskID><TaskID>103</TaskID></flow>";
SAXParser sax = SAXParserFactory.newInstance().newSAXParser();
DefaultHandler handler = new DefaultHandler() {
private StringBuilder buffer = new StringBuilder();
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("TaskID".equals(qName)) {
System.out.println(buffer);
buffer = new StringBuilder();
}
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
buffer.append(ch, start, length);
}
#Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
buffer = new StringBuilder();
}
};
sax.parse(new InputSource(new StringReader(input)), handler);
Here's an example using JDOM, which provides a more pleasant API over existing Java XML parsers:
import java.io.File;
import org.jdom2.*;
import org.jdom2.input.*;
public class Test {
// TODO: More appropriate exception handling :)
public static void main (String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("test.xml"));
Element root = doc.getRootElement();
for (Element element : root.getChildren("TaskID")) {
System.out.println(element.getText());
}
}
}
Of course, this assumes that the XML document is small enough to be loaded into memory.
(Obviously you can use the built-in libraries too, and if you're not doing much XML work then that would be fine - I just find them a bit primitive if you're doing any significant amount of work.)
With xpath Here is more information:
http://www.vogella.com/articles/JavaXML/article.html
I personally use JDOM library for all my XML manipulation.. Below is how I would do it;
String xml = "<flow> " +
"<TaskID>100</TaskID>" +
"<TaskID>101</TaskID>" +
"<TaskID>102</TaskID>" +
"<TaskID>103</TaskID>" +
"</flow>";
org.jdom.Document doc = new SAXBuilder().build(new StringReader(xml));
org.jdom.Element rootElement = doc.getRootElement();
List<Element> eles = rootElement.getChildren("TaskID");
for(Element el : eles)
System.out.println(el.getName()+" : "+el.getValue());
You can get it's documentation here: http://www.jdom.org/
Read Xml Children with SAX
<?xml version="1.0"?>
<Patriarch>
<name>Bill</name>
<wife>
<name>Vi</name>
</wife>
<son>
<name>Bill</name>
</son>
<daughter>
<name>Jeri</name>
<husband>
<name>Mark</name>
</husband>
<son>
<name>Greg</name>
</son>
<son>
<name>Tim</name>
</son>
<son>
<name>Mark</name>
</son>
<son>
<name>Josh</name>
<wife>
<name>Kristine</name>
</wife>
<son>
<name>Blake</name>
</son>
<daughter>
<name>Liah</name>
</daughter>
</son>
</daughter>
</Patriarch>
And Java code:
public class ParseXmlSAX {
public static void main(String[] args) {
new ParseXmlSAX("file.xml");
}
public ParseXmlSAX(final String file) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
String key = null;
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (key == null)
key = "|";
else
key += qName + "|";
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!key.equals("|"))
key = key.substring(0, key.lastIndexOf(qName));
}
public void characters(char ch[], int start, int length) throws SAXException {
String conteudo = new String(ch, start, length).trim();
if (!conteudo.isEmpty()) {
System.out.println(key + " = " + conteudo);
}
}
};
saxParser.parse(this.getClass().getResourceAsStream(file), handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Modifier {
public void modifyXML() {
String strSrcFile = "E:\\projects\\input\\sample.xml";
String strOutputFile = "E:\\projects\\output\\sample.xml";
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(strSrcFile);
Node company = doc.getFirstChild();
System.out.println(company.hasChildNodes());
NodeList nl = company.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// System.out.println("inner node::"+node.getNodeName());
if (node.hasChildNodes()) {
System.out.println("outer node::" + node.getNodeName());
readChildNodes(node);
} else {
}
}
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(strOutputFile));
transformer.transform(source, result);
} catch (Exception ee) {
ee.printStackTrace();
}
// Get the root element
}
public void readChildNodes(Node node)
{
NodeList nl = node.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node innernode = nl.item(i);
//System.out.println("mediam stage node::"+innernode.getNodeName());
if (innernode.hasChildNodes()) {
System.out.println("inner node::"+innernode.getNodeName());
readChildNodes(innernode);
}
else{
System.out.println("node dont have childs node::"+innernode.getNodeName());
}
}
}
public void replaceGraphicCode(Node innernode) {
NamedNodeMap attr = innernode.getAttributes();
Node nodeAttr = attr.getNamedItem("id");
String IDvalue = nodeAttr.getTextContent();
// nodeAttr.setTextContent("2");
}
public void replaceOriginator(Node innernode) {
NamedNodeMap attr = innernode.getAttributes();
Node nodeAttr = attr.getNamedItem("enterpriseCode");
}
public static void main(String[] args) {
Modifier objModifier = new Modifier();
objModifier.modifyXML();
}
}