License     Codehaus     OpenEJB     OpenJMS     OpenORB     Tyrex     
 

Main
  Home
  About
  Features
  Download
  Maven 2 support
  API
  DTD & Schemas
  Recent changes
  RSS news feed

Development/Support
  Mailing Lists
  SVN/JIRA
  Contributing
  Support
  Prof. services

Related projects
  Spring ORM support
  Spring XML factories

XML
  Using XML
  XML Mapping
  XML FAQ
  XML HOW-TOs
  Custom Handlers
  Best practice

XML Code Generator
  Code Generator
  Properties
  Custom bindings
  Ant task
  Schema Support
  Example

JDO
  Introduction
  Using JDO
  JDO Config
  Types
  JDO Mapping
  JDO FAQ
  JDO Examples
  JDO HOW-TOs
  Other Features
  JDO sample JAR

Advanced JDO
  Caching
  OQL
  Trans. & Locks
  Design
  KeyGen
  Long Trans.
  Nested Attrs.
  Pooling Examples
  LOBs
  Best practice

More
  Presentations
  The Examples
  3rd Party Tools
  JDO Tests
  XML Tests
  Configuration
  Tips & Tricks
  Full JavaDoc
  CastorWiki
 
 

About
  License
  Contributors
  Marketplace
  Status, Todo
  Changelog
  Library
  Contact
  Project Name

  



How to use XML validation with Castor


Intended Audience
Prerequisites
XML Schema and document instances
Java entities
Mapping file
Java code to test XML validation
References


Intended Audience

Anyone who wants to enable XML validation with Castor XML.

This document helps people to get familiar with the basic concepts and discusses some implementation details.

The example given describes the steps required to enble XML validation with Castor XML.

Prerequisites

None.

The code given are based on examples from the XML Schema Part 0: Primer Second Edition from w3.org.

XML Schema and document instances

The XML Schema instance (po1.xsd) used here looks as follows:

<schema xmlns="http://www.w3.org/2001/XMLSchema"
        xmlns:po="http://www.example.com/PO1"
        targetNamespace="http://www.example.com/PO1"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">

   <element name="purchaseOrder" type="po:PurchaseOrderType"/>
   <element name="comment" type="string"/>

   <complexType name="PurchaseOrderType">
      <sequence>
         <element name="shipTo" type="po:USAddress"/>
         <element name="billTo" type="po:USAddress"/>
         <element ref="po:comment" minOccurs="0"/>
         <!-- etc. -->
      </sequence>
      <!-- etc. -->
   </complexType>

   <complexType name="USAddress">
      <sequence>
         <element name="name" type="string"/>
         <element name="street" type="string"/>
         <!-- etc. -->
      </sequence>
   </complexType>

   <!-- etc. -->
</schema>

Surprisingly, the schema isn't complete, so the example XML document invalid-po1.xml is actually invalid.

<?xml version="1.0"?>
<apo:purchaseOrder
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.example.com/PO1 po1.xsd"
   xmlns:apo="http://www.example.com/PO1" 
   orderDate="1999-10-20">

   <apo:shipTo country="US">
      <apo:name>Alice Smith</apo:name>
      <apo:street>123 Maple Street</apo:street>
      <!-- etc. -->
   </apo:shipTo>

   <apo:billTo country="US">
      <apo:name>Robert Smith</apo:name>
      <apo:street>8 Oak Avenue</apo:street>
      <!-- etc. -->
   </apo:billTo>

   <apo:comment>Hurry, my lawn is going wild</apo:comment>

   <!-- etc. -->
</apo:purchaseOrder>

I then corrected the errors (removed the attributes that they didn't bother to define in their schema) and created valid-po1.xml

<?xml version="1.0"?>
<apo:purchaseOrder
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.example.com/PO1 po1.xsd"
   xmlns:apo="http://www.example.com/PO1">

   <apo:shipTo>
      <apo:name>Alice Smith</apo:name>
      <apo:street>123 Maple Street</apo:street>
      <!-- etc. -->
   </apo:shipTo>

   <apo:billTo>
      <apo:name>Robert Smith</apo:name>
      <apo:street>8 Oak Avenue</apo:street>
      <!-- etc. -->
   </apo:billTo>

   <apo:comment>Hurry, my lawn is going wild</apo:comment>

   <!-- etc. -->
</apo:purchaseOrder>

Java entities

Now, to bring Castor into the mix, I created two Java classes, PurchaseOrder and Address.

public class PurchaseOrder {
   public Address shipTo;
   public Address billTo;
   public String comment;
}

public class Address {
   public String name;
   public String street;
}
        

Mapping file

And created a mapping file from the xml to the Java classes.

<?xml version="1.0"?>
<mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://castor.exolab.org/"
         xmlns:apo="http://www.example.com/PO1"
         xsi:schemaLocation="http://castor.exolab.org/ mapping.xsd">

   <class name="PurchaseOrder">
      <map-to xml="purchaseOrder" ns-uri="http://www.example.com/PO1"/>
      <field name="shipTo" type="Address" direct="true">
         <bind-xml name="apo:shipTo" />
      </field>
      <field name="billTo" type="Address" direct="true">
         <bind-xml name="apo:billTo" />
      </field>
      <field name="comment" type="string" direct="true">
        <bind-xml name="apo:comment" />
      </field>
   </class>

   <class name="Address">
      <field name="name" type="string" direct="true">
         <bind-xml name="apo:name" />
      </field>
      <field name="street" type="string" direct="true">
         <bind-xml name="apo:street" />
      </field>
   </class>

</mapping>

Note that the mapping file refers to mapping.xsd, which can be found in the Castor JAR file, as the schema for the Castor namespace. I'm also using relative paths for all the schemas, so the xml files and the schemas must all reside in current working directory (the directory from which you call java).

Now for Castor to do validation, the correct castor.properties file must be in the current working directory.

org.exolab.castor.indent=true
org.exolab.castor.parser.namespaces=true
org.exolab.castor.sax.features=http://xml.org/sax/features/validation,\
  http://apache.org/xml/features/validation/schema,\
  http://apache.org/xml/features/validation/schema-full-checking
        

The indent property is just to make the output XML easy to read, and because I'm using Xerces, the apache.org properties come into the mix. Other XML parsers will probably have different flags that need to be set.

Java code to test XML validation

Finally, I created a driver class to run Castor:

import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;

public class ValidationDriver {

   public static void main( String[] args ) {
      String filename = args[0];

      try {
         Mapping myMap = new Mapping();
         myMap.loadMapping( "po1Map.xml" );

         Unmarshaller um1 = new Unmarshaller( myMap );
         PurchaseOrder po1 =
         (PurchaseOrder)um1.unmarshal(new FileReader(filename));

         StringWriter myWriter = new StringWriter();
         Marshaller m1 = new Marshaller( myWriter );
         m1.setMapping( myMap );
         m1.setNamespaceMapping("", "http://www.example.com/PO1");
         m1.setSchemaLocation("http://www.example.com/PO1 po1.xsd");
         m1.marshal( po1 );

         System.out.println( "Castor Output:" );
         System.out.println( myWriter.getBuffer().toString() );
         System.out.println( "" );

         StringReader myReader =
            new StringReader(myWriter.getBuffer().toString());
         PurchaseOrder po2 =
            (PurchaseOrder)um1.unmarshal( myReader );

         System.out.println( "Comment from reconstructed class:" );
         System.out.println( po2.comment );
      }
      catch( IOException e ) {
         e.printStackTrace();
      }
      catch( MarshalException e ) {
         e.printStackTrace();
      }
      catch( ValidationException e ) {
         e.printStackTrace();
      }
      catch( MappingException e ) {
         e.printStackTrace();
      }    
   }
}
        

With Castor, Xerces, and Commons-Logging in the classpath, one can run this ValidationDriver and pass in an xml filename (valid-po1.xml or invalid-po1.xml). The invalid file will print out an exception stack trace that is due to a Xerces validation error. The valid xml should produce the roundtrip xml (that's xml->Java->xml), and the comment from the purchase order from the Java object (after it has gone xml->Java->xml->Java). Note that the xml is being validated against the schema each time it is going from xml->Java (though with this example there is no validation going from Java->xml). The extra round trips might seem excesive, but they helped me work out some kinks in my mapping file when I had to do this the first time.

References

-Apache Xerces
-Apache Xerces features
 
   
  
   
 


Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.