9

I am currently working on a xml project. So far, I have successfully link my xml to my java class using Dom Parser. I have the code provide below. What I am struggling with is updating my startdate's month by one so something like this 2/1/2013, 3/1/2013... will change in the xml file accordingly. I have the method call updateDate at the bottom, but the xml file won't update it's value when I call it. Help will be appreciated

data.xml before

<?xml version="1.0" encoding="UTF-8">
<data>
    <username>hello123</username>
    <startdate>01/01/2011</startdate>
    <enddate>06/01/2013</enddate>
</data>

desire data.xml after

<?xml version="1.0" encoding="UTF-8">
<data>
    <username>hello123</username>
    <startdate>02/01/2011</startdate> <--- This will change 
    <enddate>06/01/2013</enddate>
</data>

main.java

public class main {

    public static void main(String[] args) {

        Calendar cal2 = null;

            String username = null;
            String startdate = null;
            String enddate = null;
            String date = null;
            String date_end = null;

            try {   

                File data = new File("data.xml");
                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                Document doc = dBuilder.parse(data);
                doc.getDocumentElement().normalize();
                for (int i = 0; i < nodes.getLength(); i++) {
                    Node node = nodes.item(i);         
                    if (node.getNodeType() == Node.ELEMENT_NODE) {     
                        Element element = (Element) node;
                        username = getValue("username", element);
                        startdate = getValue("startdate", element);
                        enddate = getValue("enddate", element);
                    }
                }  

                date = startdate;

                //end date
                Date date_end = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(enddate);
                Calendar end_date_cal = Calendar.getInstance();  
                end_date_cal.setTime(date_end);  

                // initial date
                Date date_int = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH).parse(date);
                cal2 = Calendar.getInstance();  
                cal2.setTime(date_int); 

                //call the method 
                updateDate(cal2);

                TransformerFactory transformerFactory = TransformerFactory.newInstance();
                Transformer transformer = transformerFactory.newTransformer();
                DOMSource source = new DOMSource(doc);
                StreamResult result = new StreamResult(new File("data.xml"));
                transformer.transform(source, result);

                System.out.println("Update Successfully");

            }

        } catch (Exception ex) {    
            log.error(ex.getMessage());     
            ex.printStackTrace();         
        }
    }

    private static void updateDate(Calendar cal2){

        cal2.add(Calendar.MONTH, 1);

        //need to push it back to the calendar
    }


    private static String getValue(String tag, Element element) {  
        NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();   
        Node node = (Node) nodes.item(0);   
        return node.getNodeValue();   
    }

    private static void setValue(String tag, Element element , String input) {  
        NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();   
        Node node = (Node) nodes.item(0); 
        node.setTextContent(input);
    }

}
3
  • As far as I can tell, you never update the DOM. I would at least expect a call to setNodeValue() somewhere. Commented Aug 3, 2015 at 6:00
  • @RobbyCornelissen, sorry about that, I forgot to include it. I have updated my code now Commented Aug 3, 2015 at 6:04
  • You have a setValue method, but you're never calling it. Commented Aug 3, 2015 at 6:05

1 Answer 1

11

Java 8's Time API

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("M/d/yyyy");
LocalDate ld = LocalDate.parse("2/1/2013", formatter);
System.out.println("From " + formatter.format(ld));
ld = ld.plusMonths(1);
System.out.println("To " + formatter.format(ld));

Which prints

From 2/1/2013
To 3/1/2013

BUT, you never apply the value back to the XML document. As I tried to demonstrate in your previous question, you need to change the textContent of the node...

node.setTextContent(formatter.format(ld))

which is why I suggested using xPath instead of walking the document content

For example...

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

public class UpdateXML {

    public static void main(String[] args) {

        try {
            DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
            DocumentBuilder b = f.newDocumentBuilder();
            Document doc = b.parse(new File("Data.xml"));

            XPath xPath = XPathFactory.newInstance().newXPath();
            Node startDateNode = (Node) xPath.compile("/data/startdate").evaluate(doc, XPathConstants.NODE);
            startDateNode.setTextContent(addMonthTo(startDateNode.getTextContent()));

            xPath = XPathFactory.newInstance().newXPath();
            Node endDateNode = (Node) xPath.compile("/data/enddate").evaluate(doc, XPathConstants.NODE);
            endDateNode.setTextContent(addMonthTo(endDateNode.getTextContent()));

            Transformer tf = TransformerFactory.newInstance().newTransformer();
            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty(OutputKeys.METHOD, "xml");
            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            DOMSource domSource = new DOMSource(doc);
            StreamResult sr = new StreamResult(new File("AData.xml"));
            tf.transform(domSource, sr);
        } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | DOMException | TransformerFactoryConfigurationError | IllegalArgumentException | TransformerException exp) {
            exp.printStackTrace();
        }
    }

    public static String addMonthTo(String value) {

        String patterns[] = {"M/d/yyyy", "M/dd/yyyy", "MM/d/yyyy", "MM/dd/yyyy"};

        LocalDate ld = null;
        for (String pattern : patterns) {
            try {
                ld = LocalDate.parse(value, DateTimeFormatter.ofPattern(pattern));
                break;
            } catch (DateTimeParseException exp) {
            }
        }

        if (ld == null) {
            throw new DateTimeParseException("Could not parse " + value + " with available patterns", value, -1);
        }

        ld = ld.plusMonths(1);
        return DateTimeFormatter.ofPattern("MM/dd/yyyy").format(ld);

    }

}

Which took...

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
  <username>admin</username>
  <password>12345</password>
  <interval>1</interval>
  <timeout>90</timeout>
  <startdate>1/1/2013</startdate>
  <enddate>06/01/2013</enddate>
  <ttime>1110</ttime>
</data>

And outputted...

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
  <username>admin</username>
  <password>12345</password>
  <interval>1</interval>
  <timeout>90</timeout>
  <startdate>02/01/2013</startdate>
  <enddate>07/01/2013</enddate>
  <ttime>1110</ttime>
</data>

i want the startdate 6 months earlier then the enddate

Java 8

String endDateValue = "07/01/2013";

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
LocalDate endDate = LocalDate.parse(endDateValue, formatter);
LocalDate startDate = endDate.minusMonths(6);

String startDateValue = formatter.format(startDate);

Calendar

I'd prefer Joda-Time, but

String endDateValue = "07/01/2013";
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
Date endDate = sdf.parse(endDateValue);

Calendar cal = Calendar.getInstance();
cal.setTime(endDate);
cal.add(Calendar.MONTH, -6);

Date startDate = cal.getTime();
String startDateVaue = sdf.format(startDate);
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, I will give it a try, I guess the reason I can't use the dateTimeFormatter before is because I am using java 1.6
Then use Joda-Time, Calendar is a ... mess
Which value is the anchor? Do you want the endDate 6 months after the startDate or the startDate 6 months earlier then the endDate?
Sorry, deleted my question by accident, i want the startdate 6 months earlier then the enddate
Thanks a lot!! I just keep messing up with which value I should use.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.