Java-Web:Exercises - Creating XML from Java

From Juneday education
Jump to: navigation, search

Work in progress

This chapter is a work in progress. Remove this section when the page is production-ready.

Introduction

This exercise is about creating an XML document from Java. The goal is for you to read data from a database (using JDBC), create a list of Java objects, and loop through the list and create the XML document.

Objective

You will be given a database and some Java classes to read from the database and create objects. Your task is to write a program (a class with a main method) which will get the objects, loop through them and create an XML document containing the data from the objects.

The database contains data for a CV with job experiences. You should get a list of JobExperience object references, loop through the list and create an XML document containing the same data.

The database

The database is provided for you and is an SQLite database with the following table schema:

CREATE TABLE job_experience(
  exp_id integer primary key not null,
  employer text,
  title text,
  start_date datetime,
  end_date datetime,
  description text
);

In this simple exercise, we don't focus on good database design, so we haven't normalized the data, nor have we created any constraints for e.g. the start_date or end_date columns. You are encouraged to re-design the table when you are done with the exercise if you have time over and want to practice more database stuff. But that's a task you will have to solve on your own. The focus on this exercise is to create an XML document from Java objects.

The data

The database contains rows like the following:

sqlite> .mode column
sqlite> .width 6 10 20 20 20 30
sqlite> .headers on
sqlite> SELECT * FROM job_experience;
exp_id  employer    title                 start_date            end_date              description                   
------  ----------  --------------------  --------------------  --------------------  ------------------------------
1       Yrgo        Java teacher          2017-01-01 00:00:00   2017-06-30 00:00:00   Teacher for a Java course     
2       ITHS        Database teacher      2016-01-01 00:00:00   2016-02-28 00:00:00   Teacher for a Database course
-- ... etc etc

The expected XML format

The XML document your program should produce should, given the above data, have the following structure:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<CV>
  <JOB>
    <EMPLOYER end="2017-06-30 00:00:00" start="2017-01-01 00:00:00">Yrgo</EMPLOYER>
    <TITLE>Java teacher</TITLE>
    <DESCRIPTION>Teacher for a Java course</DESCRIPTION>
  </JOB>
  <JOB>
    <EMPLOYER end="2016-02-28 00:00:00" start="2016-01-01 00:00:00">ITHS</EMPLOYER>
    <TITLE>Database teacher</TITLE>
    <DESCRIPTION>Teacher for a Database course</DESCRIPTION>
  </JOB>
</CV>

Files and directory layout

Your directory structure should look like this (when you have fetched the files for the exercise):

.
|-- CreateCV.java
|-- cv_database_dump.sql
|-- cv.db
|-- org
|   `-- yrgo
|       |-- database
|       |   `-- Database.java
|       |-- domain
|       |   `-- JobExperience.java
|       `-- util
|           `-- CVFetcher.java
`-- sqlite.jar

Task 1 - Fetch the files needed to get started

Clone our github repository here or download the files from this web page using a browser. The files for these exercises here are found in the directory java-web/java-xml/creating-xml/ Verify that you have the same directory structure as shown below. You should do this in a fresh, newly created directory for this exercise. You will work from "." (the current directory signified by the dot in the tree above).

Expand using link to the right to see a hint.

Using git:

$ git clone https://github.com/progund/java-web.git
$ cd java-web/java-xml/creating-xml/

Using the zip file from DownGit:

$ mv ~/Downloads/creating-xml.zip .
$ unzip creating-xml.zip 
Archive:  creating-xml.zip
   creating: creating-xml/
   creating: creating-xml/suggested-solution/
   creating: creating-xml/suggested-solution/org/
   creating: creating-xml/suggested-solution/org/yrgo/
   creating: creating-xml/suggested-solution/org/yrgo/util/
 extracting: creating-xml/suggested-solution/org/yrgo/util/CVFetcher.java  
 extracting: creating-xml/sqlite.jar  
   creating: creating-xml/suggested-solution/org/yrgo/domain/
 extracting: creating-xml/suggested-solution/org/yrgo/domain/JobExperience.java  
   creating: creating-xml/suggested-solution/org/yrgo/database/
 extracting: creating-xml/suggested-solution/org/yrgo/database/Database.java  
 extracting: creating-xml/suggested-solution/CreateCV.java  
   creating: creating-xml/org/
   creating: creating-xml/org/yrgo/
   creating: creating-xml/org/yrgo/util/
 extracting: creating-xml/org/yrgo/util/CVFetcher.java  
   creating: creating-xml/org/yrgo/domain/
 extracting: creating-xml/org/yrgo/domain/JobExperience.java  
   creating: creating-xml/org/yrgo/database/
 extracting: creating-xml/org/yrgo/database/Database.java  
 extracting: creating-xml/CV.xml     
 extracting: creating-xml/README.txt  
 extracting: creating-xml/cv_database_dump.sql  
 extracting: creating-xml/cv.db      
 extracting: creating-xml/CreateCV.java  
$ cd creating-xml/

The XML file you should create, should be named CV.xml and it's OK if you write it to the current directory. That means that in the CreateCV.java application, you give the file the relative path CV.xml.

You will work with the file CreateCV.java, which we have created for you, but you will have to read the other files in order to understand how to solve the problem - get a List<yrgo.domain.JobExperience> from org.yrgo.util.CVFetcher, and convert it into an XML document to be written to the current directory.

Task 2 - Read and understand the code provided

Your application in CreateCV.java will need to get hold of a List<yrgo.domain.JobExperiece>. You can get this from a org.yrgo.util.CVFetcher object. Study this class and figure out how to use it.

If you want, to, you can also study how the org.yrgo.database.Database code works - it uses JDBC in order to get the data out of the database. That's also the reason for why you need to run your program with the flag -cp .:sqlite.jar (if anyone is running Windows, you should use -cp ".;sqlite.jar" - a semicolon instead of the standard colon). But the JDBC part is not essential for understanding this exercise.

You can also enter the database and add more data (more rows to the job_experience table). Study the database schema above and figure out how to add more job experiences.

In the CreateCV.java, we have provided the necessary import statements for you. You should make sure that you understand why we need the ones importing from org.yrgo.

We have also got you started by creating the Document for you.

You can run the program as-is to get an idea of what is left for you to do:

$ javac CreateCV.java && java -cp .:sqlite.jar CreateCV && cat CV.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<CV/>

The application creates an XML document with an empty root element called CV.

Your task during the exercise, is to add child nodes to the CV root element.

Task 3

Create the org.yrgo.util.CVFetcher object and get the list of JobExperiece from it. Start by printing the whole list to system out.

Expand using link to the right to see a hint.

CVFetcher fetcher = new CVFetcher();
System.out.println(fetcher); // Remove this printout when you see that it works!

Task 4

Create a loop around each org.yrgo.domain.JobExperience in the list you get from the fetcher. Use the for-each syntax, so that you inside the loop have a reference to one of the JobExperience objects.

Start by printing the JobExperience out on a separate line, so that you know that you are doing the loop right:

Expand using link to the right to see a hint.

      for(JobExperience job : new CVFetcher().getJobs()){
        System.out.println("Found a job! " + job);
      }

Or, in two steps:

      CVFetcher fetcher = new CVFetcher();
      for(JobExperience job : fetcher.getJobs()){
        System.out.println("Found a job! " + job);
      }

When you are sure it works, remove the printout from the loop and instead create a child element called JOB.

Expand using link to the right to see a hint.

        Element jobElement = doc.createElement("JOB");

Create three child elements to the JOB element:

  • EMPLOYER
  • TITLE
  • DESCRIPTION

For each one of the elements EMPLOYER, TITLE and DESCRIPTION add a textNode with the text ("test").

Then add the EMPLOYER, TITLE and DESCRIPTION to the JOB element, and add JOB to the rootElement. Note that no data is added to the elements, yet, we just want to see if we can create the XML document structure.

Expand using link to the right to see a hint.

      for(JobExperience job : new CVFetcher().getJobs()){
        Element jobElement = doc.createElement("JOB");
        Element employer = doc.createElement("EMPLOYER");
        employer.appendChild(doc.createTextNode("test"));
        Element title = doc.createElement("TITLE");
        title.appendChild(doc.createTextNode("test"));
        Element description = doc.createElement("DESCRIPTION");
        description.appendChild(doc.createTextNode("test"));
        jobElement.appendChild(employer);
        jobElement.appendChild(title);
        jobElement.appendChild(description);
        rootElement.appendChild(jobElement);
      }

Compile and run the program again and confirm that you got a dummy XML document.

Expand using link to the right to see a hint.

It should look something like this:

$ javac CreateCV.java && java -cp .:sqlite.jar CreateCV && cat CV.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<CV>
  <JOB>
    <EMPLOYER>test</EMPLOYER>
    <TITLE>test</TITLE>
    <DESCRIPTION>test</DESCRIPTION>
  </JOB>
  <JOB>
    <EMPLOYER>test</EMPLOYER>
    <TITLE>test</TITLE>
    <DESCRIPTION>test</DESCRIPTION>
  </JOB>
  <JOB>
    <EMPLOYER>test</EMPLOYER>
    <TITLE>test</TITLE>
    <DESCRIPTION>test</DESCRIPTION>
  </JOB>
</CV>

Task 5 - Add real data to the elements

Now that you see that you can create a document with dummy data, let's add real data to the elements.

First, add two attributes to the EMPLOYER element. Use the method setAttribute(String attrName, String attrValue) method to set the attribute start with the value you get from the JobExperience method designed for this (look at the class to find out which method). Do the same for a second attribute end (with another method call, of course).

Expand using link to the right to see a hint.

If your for-each loop uses a JobExperience loop variable called job, and the EMPLOYER element is in a variable called employer, this is how you can set the attributes:

        employer.setAttribute("end",   job.end());
        employer.setAttribute("start", job.start());

Next, add the textNode to EMPLOYER but this time, add the real data using the JobExperience loop variable and an appropriate instance method (look at the class to see which method should be used).

For the elements TITLE and DESCRIPTION, do the same thing. Note that only the EMPLOYER element has attributes. All of them have textNode data, though.

Expand using link to the right to see a hint.

      for(JobExperience job : fetcher.getJobs()){
        Element jobElement = doc.createElement("JOB");
        Element employer   = doc.createElement("EMPLOYER");
        employer.setAttribute("end",   job.end());
        employer.setAttribute("start", job.start());
        employer.appendChild(doc.createTextNode(job.employer()));
        jobElement.appendChild(employer);
        Element title = doc.createElement("TITLE");
        title.appendChild(doc.createTextNode(job.title()));
        jobElement.appendChild(title);
        Element description = doc.createElement("DESCRIPTION");
        description.appendChild(doc.createTextNode(job.description()));
        jobElement.appendChild(description);
        rootElement.appendChild(jobElement);
      }

Task 6 - optional

Add data (rows of data) to the database table job_experience. You can enter the database shell interactively from the terminal using sqlite3 cv.db

Expand using link to the right to see a hint.

sqlite> insert into  job_experience(employer, title, start_date, end_date, description)
        values('Some employer Inc',
               'Fancy job title',
               datetime('1971-11-24'),
               datetime('2017-01-31'),
               'Working for the man'
         );

Run the application again and verify that the new rows are converted to elements in the XML document.

Task 7 - Summary

In this exercise, we have tried to show you that data often comes from somewhere in an application. In this case, the data comes from a database with CV entries in the form of rows of Job Experiece data - where a person for whom we want to create a CV has worked, when, with what title and a description of each job.

In a Java application, this data is read via JDBC and converted to some kind of "domain object" - the domain we are modelling is entries for a Curriculum Vitae (CV), more specifically job experieces. So we have a corresponding class org.yrgo.domain.JobExperience. The class is for Java objects representing a job experience.

Since the application aims to collect all the job experiences from the database, we need a list of JobExperience references. For this, there is a utility class called org.yrgo.util.CVFetcher. It talks to the database (via a third class) and creates a List<JobExperience> so that your application can get such a list easily from the main method.

Getting a list of the job experiences allows you to iterate over that list (using a for-each loop) and do something with each job experience object referred to from the list.

What you are doing, is to create an XML document with a root node called CV. Then you use the loop to add child nodes to the root node. Each child node is called <JOB>. And each <JOB> element has three child nodes, EMPLOYER, TITLE, DESCRIPTION.

Since you are looping over a list of job experience objects, you can ask each object for the appropriate data to add as the text node content of each element. What we hope to have shown you, is not only where the data comes from (a database via JDBC) but also that it is worth creating objects with convenient methods for accessing the data. The final loop for creating all the child nodes for the XML document becomes somehing like this:

CVFetcher fetcher = new CVFetcher();
for(JobExperience job : fetcher.getJobs()){
  Element jobElement = doc.createElement("JOB");
  Element employer   = doc.createElement("EMPLOYER");
  employer.setAttribute("end",   job.end());
  employer.setAttribute("start", job.start());
  employer.appendChild(doc.createTextNode(job.employer()));
  jobElement.appendChild(employer);
  Element title = doc.createElement("TITLE");
  title.appendChild(doc.createTextNode(job.title()));
  jobElement.appendChild(title);
  Element description = doc.createElement("DESCRIPTION");
  description.appendChild(doc.createTextNode(job.description()));
  jobElement.appendChild(description);
  rootElement.appendChild(jobElement);
}

We hope that this conveys a convenient way to handle data in a Java application. Even if the XML syntax is a handful, getting the actual data is rather convenient. We have also hidden the fact that the data comes via JDBC from a database, by using objects of higher-level abstractions. We have the CVFetcher object which we ask for a list of JobExperience references. In this way, we can - by understanding how the JobExperience class is written - use instance variables to get the actual data as Java Strings.

An example of that is:

  Element title = doc.createElement("TITLE");
  title.appendChild(doc.createTextNode(job.title()));

The TITLE element is added a child element, created by asking the document (doc) to create a text node. The text value for the text node comes from the JobExperience referenced by job and the instance method title().

This is an example of using abstractions in the form of objects.

We have a Java object for a whole job experience. If we need to ask the object for the title of the job, we use a reference to the object and call the instance method: job.title() .

We hope that you learned a little about creating XML documents but also a little about how you could structure a very small application like this, to separate the low-level stuff like database access from the real work - getting a list of some data and creating an XML from it.

Navigation

Up next: Introduction to JSON!

« PreviousBook TOCNext »