|  |  |  | License Codehaus OpenEJB OpenJMS OpenORB Tyrex

Old releases
General
Release 1.3
Release 1.3rc1
Release 1.2

Main
Home
About
Features
Download
Dependencies
Reference guide
Publications
JavaDoc
Maven 2 support
Maven 2 archetypes
DTD & Schemas
Recent HTML changes
News Archive
RSS news feed
Project Wiki

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

Related projects
Spring ORM support
Spring XML factories
WS frameworks

XML
XML

XML Code Generator
XML Code Generator

JDO
Introduction
First steps
Using JDO
JDO Config
Types
JDO Mapping
JDO FAQ
JDO Examples
JDO HOW-TOs
Tips & Tricks
Other Features
JDO sample JAR

Tools
Schema generator

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

DDL Generator
Using DDL Generator
Properties
Ant task
Type Mapping

More
The Examples
3rd Party Tools
JDO Tests
XML Tests
Configuration

About
License
User stories
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

<notice> Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved. </notice>
<notice> 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. </notice>