Monday, January 26, 2009

XML schema validation with Dom4j

Hi folks, today I´m feeling geeky!!

First and foremost, if you don´t know what and XML schemas or XML documents are, you´d better listen to my music clicking on the youtube video on your right. For the rest of you, a bit obvious, Dom4j is a Java API, so........

Ok, let´s get started.

Dom4j is a Java API that makes XML manipulation sweet, and easier than with pure DOM or SAX. Besides it let you use XPATH to travers XML documents. Dom4j includes its own XML parser, but this in not able to validate document agains schemas. For that purpose we will use Xerces.

In order to develop our example we will define a very little schema and and two XML documents usign that schema, one will be valid, and the other won´t.

I´m using Java 5, and ignore if this would work with Java 1.4, let me know if you discover something. I will assume you have downloaded the following APIs:

  • Latest dom4j (1.6.1 at the time or writting this).
  • Latest Xerces (1.4.4 at the time of writting this).
I´ll use Eclipse througout the whole example, so let´s kick off:

  • Create a Java project. Call it XmlValidation
  • Add the following libraries to the buid path (Project -> Properties -> Java Build Path -> Libraries -> Add external jars)
    • dom4j-1.6.1.jar
    • xerces.jar
  • Add an XML schema called SongSchema.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="SongSchema" xmlns:album="SongSchema"
elementFormDefault="qualified">

<xsd:element name="album">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="song" type="album:song" />
<xsd:element name="comment" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>

<xsd:complexType name="song">
<xsd:sequence>
<xsd:element name="title" type="album:nonemptystring" />
<xsd:element name="author" type="album:nonemptystring" />
<xsd:element name="minutes" type="album:time" />
<xsd:element name="seconds" type="album:time" />
</xsd:sequence>
</xsd:complexType>


<xsd:simpleType name="time">
<xsd:restriction base="xsd:positiveInteger">
<xsd:pattern value='[0-6]?[0-9]'/>
</xsd:restriction>
</xsd:simpleType>

<xsd:simpleType name="nonemptystring">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[\w\W]+"></xsd:pattern>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>


  • Now we create our actual XML file, called MySongs.xml:

<?xml version="1.0" encoding="UTF-8"?>
<album xmlns="SongSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="SongSchema SongSchema.xsd">
<song>
<title>Oceano de sal</title>
<author>Julio Delgado</author>
<minutes>39</minutes>
<seconds>7</seconds>
</song>
<comment>Very Good Song,ideed.</comment>
</album>


  • We are nearly there!!!
  • Create the validator class, called Validator, in the Validator.java file:

package com.julio.xml;

import java.io.File;
// dom4j import
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class Validator {
private File file;
private Document doc;
private SAXReader reader;
private handler h;

public Validator(){
reader = new SAXReader(true);
h = new handler();
// Lets configure the reader for full validation
// set the validation feature to true to report validation errors
try {
reader.setFeature("http://xml.org/sax/features/validation", true);
// set the validation/schema feature to true to report validation errors against a schema
reader.setFeature("http://apache.org/xml/features/validation/schema", true);

// set the validation/schema-full-checking feature to true to enable full schema, grammar-constraint checking
reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
reader.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
//reader.setFeature("http://apache.org/xml/features/validation-error-as-fatal", true);
reader.setErrorHandler(h);
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


};
public Validator(String fileName)
{
this();
file = new File(fileName);
try {
doc = reader.read(file);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

// If everything went fine up to this point, now we have
// an XML document in memory and can try to validate.
}
public void setFile(File file) {
this.file = file;
}

public boolean validateXml(){
try {
h.setHasErrors(false);
doc = reader.read(file);
} catch (DocumentException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
//e.printStackTrace();
return false;
}
return !h.getHasErrors();
}


class handler implements ErrorHandler{

private boolean hasErrors;

public handler()
{
hasErrors = false;
}

public boolean getHasErrors()
{
return hasErrors;
}

public void setHasErrors(boolean b)
{
this.hasErrors = b;
}

@Override
public void error(SAXParseException exception) throws SAXException {
System.out.println("Line: " + exception.getLineNumber() + ") " +
exception.getMessage());
hasErrors = true;
}

@Override
public void fatalError(SAXParseException exception) throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void warning(SAXParseException exception) throws SAXException {
// TODO Auto-generated method stub

}

}

}




This code is doing 2 main things:
  1. Configure the parser in the Validator constructor. This include it´s behavior and a class to handle errors and warnings during parsing.
  2. Define a class to handle errors. This is needed because otherwise the applicacion would rise and exception with the first error found, and we couldn´t get a list of all the errors present on the Xml file.
  • Finally the class that nails everything together, XmlTest, in the file XmlTest.java:

package com.julio.test;

import java.io.File;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

public class XmlTest {

// Entry point
public static void main(String args[])
{
System.out.println("XmlTest.main()");
XmlTest test = new XmlTest();
test.printWellcomeScreen();
SAXReader reader = new SAXReader();
Document doc = null;
try {
doc = reader.read(new File("xml/Program.xml"));
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(doc != null)
{
System.out.println(doc.toString());
if(doc.getRootElement().getName() == "program")
{
System.out.println("program\n");
System.out.println(doc.getRootElement().attributeValue("buid"));
}
}
}


private void printWellcomeScreen()
{
System.out.println("WELLCOME!!!\n");
}

}



  • Now just compile and execute. Try different values in the Xml file, and you´ll see how well the validation works.

Enjoy!!!!

Saturday, January 17, 2009

XBOX 360

I've bought myself an XBOX 360 last week. After playing a couple of hours with PGR4 I connected the console to the Internet. The process was amazingly easy, I just plugged one edge the network cable to the console the other to the router, and ........ there we go, my XBOX 360 was happily downloading updates and videos from the Internet.

So far I've been playing PGR4, Orange Box (A total must have), GTA4, and ........ Kung Fu Panda, I'm sorry but this game is really fun.

Bye.

Limerick information

If you ask an Irish about Limerick, you'll see that look..., that smile on the face. "You mean Stab City?" you'll hear. Limerick is known in Ireland as a city with high crime rates, lots of knackers, horses and some gang activities.

For some historical reasons unknown to me, there are two rival gangs developing all kind of underground activities. This gangs usually kill members of the rival one but, unfortunately, every so often Innocent people get caught in the middle, badly wounded or even killed.

My impression of the city is different, radically different. Once in the city ,quickly you get the feeling of a middle size one, with some big office buildings, lots of cars, and some big industrial areas. Certainly the city is not as nice as Galway is. But its size is also a good thing since the commercial offer is much bigger.

Then you discover the vibrant University of Limerick, its huge campus with its marvelous sports facilities. The offices of the company I work for are in the middle of the campus, in the International Science Center at the National Technology Park.

Also Limerick is a much more international city, somehow people is more open minded, though I'm not saying that people in Galway are not open minded, but here they are more.

In terms of weather, it seems to be a combination of continental weather, with colder winters and hotter summers than Galway, and a little bit less rainy. This last point is yet to be confirmed.

So far I'm happy here. There are two things that I really miss, Salthill's promenade, and the ability to go everywhere with my bike.

Bye.

Tuesday, January 13, 2009

Back to life

After a couple of month of craziness and overwhelming stress, I´m back. Today he have had the Internet connexion installed at home, at my new home in Limerick, Ireland. You´ll hear from me soon, promise.

Byeeeeeeeeeeeee.