Marshalling to XML conforming to existing XSD

View: New views
12 Messages — Rating Filter:   Alert me  

Marshalling to XML conforming to existing XSD

by daab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I'm relatively new to xml, marshaling/unmarshaling, castor, and this forum.  I've gone through this tutorial.

I need to marshal a large hashtable of a custom java object onto an XML file.  This XML file must conform to an existing XSD file.  The object's class will be modified to conform to castor API (for set, get functions), but I want to keep changes to a minimum.

I'll later need to unmarshal from the XML file to a collection of my objects, for maintenance.  I know castor has its own mapping file that needs to be created manually.

So what I need help with is, how should I go about creating the mapping file?  Do I need to create the mapping file by looking at the XSD, manually?  Is there a way to automate this?

Is there another approach to my scenario?  I know I can also create classes (or class descriptors [is that the same thing?]) from XSD files using the sourceCodeGen (sp?) tool.  However, I want to try to avoid this approach (of using a generated class as it would be an unnecessarily larger class).  I'll use it if theres no other way.

Thanks.

Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

daab wrote:

> Hi,
>
> I'm relatively new to xml, marshaling/unmarshaling, castor, and this forum.
> I've gone through
> http://www.ibm.com/developerworks/xml/library/x-xjavacastor3/ this tutorial
> .
>
> I need to marshal a large hashtable of a custom java object onto an XML
> file.  This XML file must conform to an existing XSD file.  The object's
> class will be modified to conform to castor API (for set, get functions),
> but I want to keep changes to a minimum.
>
> I'll later need to unmarshal from the XML file to a collection of my
> objects, for maintenance.  I know castor has its own mapping file that needs
> to be created manually.
Yes, if you have existing Java classes and want to use them for XML data
binding (aka unmarshalling from XML and marshalling to XML business).

> So what I need help with is, how should I go about creating the mapping
> file?
Use an XML editor, and add class and field mappings as needed.

> Do I need to create the mapping file by looking at the XSD, manually?
Yes and no. It would be simpler to look at an XML document instance that
conforms to that XML schema, and define your mappings according to this.

> Is there a way to automate this?
There's the MappingTool, but I believe that you won't be able to use it
for your business (due to the Maps).

> Is there another approach to my scenario?  I know I can also create classes
> (or class descriptors [is that the same thing?]) from XSD files using the
> sourceCodeGen (sp?) tool.
Yes.
> However, I want to try to avoid this approach (of
> using a generated class as it would be an unnecessarily larger class).
Larger in what sens, if I may ask ?

> I'll use it if theres no other way.
There's more than one option, and it's your choice. Personally, I'd use
code generation and avoid having to write a (potentially biggish)
mapping file(s), but as already said, that#s my preference.

> class descriptors [is that the same thing?])
No, it's not. When you use the XML code generator to create java sources
from an XML schema, you'll get two sets of classes.

a) entity classes (Java representations of your e.g. <complexType>
definitions)
b) Castor-specific descriptor classes (one for each entity class).

What is a descriptor class ? Let me explain it like this: if you start
with existing Java classes, and you write a mapping file (manually),
Castor will - at start-up time - analyze the mapping file provided and
(internally) convert these classes to descriptor classes.

I hope this explains things a bit more.

Regards
Werner


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Marshalling to XML conforming to existing XSD

by daab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thank you for the clarification.

I am at the point where I want to marshall multiple objects into one XML file.  The root element must be unique, so is there a way to do this with castor?

I have found the following two posts helpful:
1. https://docs.codehaus.org/display/CASTOR/MultipleObjectsTo1XML
"To marshall multiple objects into a single document, you can do the following:

marshaller m = new Marshaller(...);
m.setMarshalAsDocument(false);

and then pass in multiple objects:

m.marshal(obj1);
m.marshal(obj2);

and so on.."


and:


2. http://osdir.com/ml/java.castor.devel/2003-08/msg00321.html
Keith Visco wrote:
Maryanne,

The "obvious" answer is probably your best bet, but you can also do the
following:

PrintWriter pw = new PrintWriter(writer, true);
pw.println("<?xml version=\"1.0\"?>");
pw.println("<myroot>");

Marshaller m = new Marshaller(pw);
m.setMarshalAsDocument(false);
m.marshal(obj1);
m.marshal(obj2);
pw.println("</myroot>");

--Keith

Following the example on IBM's site closely, I now have:
package ibm.xml.castor;

import java.io.*;
import org.exolab.castor.xml.Marshaller;

public class MarshalTester {

    public static void main(String[] args) {
        try {
            BufferedWriter theBufferedFileWriter = new BufferedWriter(new FileWriter("cds.xml"));
            StringWriter theStringWriter = new StringWriter();

            //1st CD object
            CD cd1 = new CD("CD 1", "Artist 1");
            cd1.addTrack("Track 1");
            cd1.addTrack("Track 2");

            //Marshall to our StringWriter
            //Default is setMarshalAsDocument == true to set header
            Marshaller m = new Marshaller();
            m.setWriter(theStringWriter);
            m.marshal(cd1);

            //Prepare marshaller for appending more objects
            m.setMarshalAsDocument(false);
           
            //2nd CD object
            CD cd2 = new CD("myCd", "myArtist");
            cd2.addTrack("traack 1");
            cd2.addTrack("traack 2");

            //Marshall 2nd CD to our StringWriter
            m.marshal(cd2);

            //Write StringWriter buffer to file
            theBufferedFileWriter.write(theStringWriter.toString());

            theBufferedFileWriter.close();
            theStringWriter.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
            e.printStackTrace(System.err);
        }
    }
}
CD class is Listing 2 on: http://www.ibm.com/developerworks/xml/library/x-xjavacastor1/

So my concern is, if I simply set setMarshalAsDocument = false from the beginning and set the header and root element manually, wouldn't that give an error during unmarshalling because I'd need to change my class and mapping to reflect the new root element?  I can perhaps see why this isn't implemented in castor; it would require the class to be changed upon unmarshalling... and to what type of sequence?

So I guess the only way is to specify another class that holds a sequence of my base CD class and then marshall that.  For big files, this might become a memory problem though.  Any suggestions on if I can avoid this problem?

Re: Marshalling to XML conforming to existing XSD

by daab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

So does this fully answer your previous question ?

Werner

daab wrote:
> Ok, I just found http://www.castor.org/how-to-map-a-hashtable.html ...
> :blush:

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Marshalling to XML conforming to existing XSD

by daab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I tried to follow that tutorial.  Here is the structure of the project I am using:


Here are the files in the package in the structure:
Item.java
Items.java
Main.java

I added a non-empty constructor to the Item class and an empty one to Items class.
I also changed the package part of the class name tags in the mapping.xml file for both classes.

Note, mapping.xml,
I think that the following:
  <field name="Itemlist" collection="hashtable"> <bind-xml name="MyItem">
should read as:
  <field name="Itemlist" collection="hashtable"> <bind-xml name="itemlist">
      as that is the name of the item in the items class, no?

The program runs but doesn't output properly.  Here is what I get:
  <?xml version="1.0" encoding="UTF-8" ?>
  <hashtable empty="false" />

So I think the problem is in reading the mapper.xml file.

If you see my Main.java, you'll see I tried it a couple of ways, with a suggested way commented out.  I was getting nullpointerexception with that method.  Here is my file directory setup where mapping.xml resides:

I played around with the getResource and getResourceAsStream with no avail.

Any suggestions?

Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

before asking any furthr questions, can I please ask you to read the
recently published article series about Castor XML on developerWorks ?
You'll find links to these articles on the main page of Castor in the
news section.

Regards
Werner

daab wrote:

> I tried to follow that tutorial.  Here is the structure of the project I am
> using:
> http://www.nabble.com/file/p18659784/structure.jpg 
>
> Here are the files in the package in the structure:
> http://www.nabble.com/file/p18659784/Item.java Item.java
> http://www.nabble.com/file/p18659784/Items.java Items.java
> http://www.nabble.com/file/p18659784/Main.java Main.java
>
> I added a non-empty constructor to the Item class and an empty one to Items
> class.
> I also changed the package part of the class name tags in the mapping.xml
> file for both classes.
>
> Note, mapping.xml,
> I think that the following:
>   <field name="Itemlist" collection="hashtable"> <bind-xml name="MyItem">
> should read as:
>   <field name="Itemlist" collection="hashtable"> <bind-xml name="itemlist">
>       as that is the name of the item in the items class, no?
>
> The program runs but doesn't output properly.  Here is what I get:
>   <?xml version="1.0" encoding="UTF-8" ?>
>   <hashtable empty="false" />
>
> So I think the problem is in reading the mapper.xml file.
>
> If you see my Main.java, you'll see I tried it a couple of ways, with a
> suggested way commented out.  I was getting nullpointerexception with that
> method.  Here is my file directory setup where mapping.xml resides:
> http://www.nabble.com/file/p18659784/structure2.jpg 
> I played around with the getResource and getResourceAsStream with no avail.
>
> Any suggestions?

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Marshalling to XML conforming to existing XSD

by daab () :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

I have read those articles before coming to the mailing list.  They do not cover marshalling multiple objects, or sequences of objects to a single file.  I have tried to follow the instructions on marshalling a hashtable of objects on the castor page with the process and results in my last post on the 25th.  I have tried googling this and found a couple of approaches, which again don't work (the set write as document to false won't add the initial header, and you need a root element anyway).  I am hoping *someone* has gotten multiple objects onto an xml file with castor?

I also tried the direct="true" for fields and changed the names to the variable names and changed the variables to public... still with no results.  There is also an error in my code where I am adding to the hashtable.  It should read:
            itemlist.put(item1.getId(), item1);
            itemlist.put(item2.getId(), item2);

Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

can you define the term 'multiple objects' for us ?

Werner

daab wrote:
> Hi,
>
> I have read those articles before coming to the mailing list.  They do not
> cover marshalling multiple objects, or sequences of objects to a single
> file.  I have tried to follow the instructions on marshalling a hashtable of
> objects on the castor page with the process and results in my last post on
> the 25th.  I have tried googling this and found a couple of approaches,
> which I report on again in my last post on the 25th.  I am hoping *someone*
> has gotten multiple objects onto an xml file with castor? :-(

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi

daab wrote:
> Thank you for the clarification.
>
> I am at the point where I want to marshall multiple objects into one XML
> file.
How do these objects relate to each other ? Are they part of e.g. an
inheritance hierarchy ? Will each of those objects be mapped ?

> The root element must be unique, so is there a way to do this with
> castor?
>
> I have found the following two posts helpful:
> 1. https://docs.codehaus.org/display/CASTOR/MultipleObjectsTo1XML
> "To marshall multiple objects into a single document, you can do the
> following:
>
> marshaller m = new Marshaller(...);
> m.setMarshalAsDocument(false);
>
> and then pass in multiple objects:
>
> m.marshal(obj1);
> m.marshal(obj2);
>
> and so on.."
>
>
> and:
>
>
> 2. http://osdir.com/ml/java.castor.devel/2003-08/msg00321.html
>
> Keith Visco wrote:
>> Maryanne,
>>
>> The "obvious" answer is probably your best bet, but you can also do the
>> following:
>>
>> PrintWriter pw = new PrintWriter(writer, true);
>> pw.println("<?xml version=\"1.0\"?>");
>> pw.println("<myroot>");
>>
>> Marshaller m = new Marshaller(pw);
>> m.setMarshalAsDocument(false);
>> m.marshal(obj1);
>> m.marshal(obj2);
>> pw.println("</myroot>");
>>
>> --Keith
>>
>
>
> Following the example on IBM's site closely, I now have:
> package ibm.xml.castor;
>
> import java.io.*;
> import org.exolab.castor.xml.Marshaller;
>
> public class MarshalTester {
>
>     public static void main(String[] args) {
>         try {
>             BufferedWriter theBufferedFileWriter = new BufferedWriter(new
> FileWriter("cds.xml"));
>             StringWriter theStringWriter = new StringWriter();
>
>             //1st CD object
>             CD cd1 = new CD("CD 1", "Artist 1");
>             cd1.addTrack("Track 1");
>             cd1.addTrack("Track 2");
>
>             //Marshall to our StringWriter
>             //Default is setMarshalAsDocument == true to set header
>             Marshaller m = new Marshaller();
>             m.setWriter(theStringWriter);
>             m.marshal(cd1);
>
>             //Prepare marshaller for appending more objects
>             m.setMarshalAsDocument(false);
>            
>             //2nd CD object
>             CD cd2 = new CD("myCd", "myArtist");
>             cd2.addTrack("traack 1");
>             cd2.addTrack("traack 2");
>
>             //Marshall 2nd CD to our StringWriter
>             m.marshal(cd2);
>
>             //Write StringWriter buffer to file
>             theBufferedFileWriter.write(theStringWriter.toString());
>
>             theBufferedFileWriter.close();
>             theStringWriter.close();
>         } catch (Exception e) {
>             System.err.println(e.getMessage());
>             e.printStackTrace(System.err);
>         }
>     }
> }
> CD class is Listing 2 on:
> http://www.ibm.com/developerworks/xml/library/x-xjavacastor1/
>
> So my concern is, if I simply set setMarshalAsDocument = false from the
> beginning and set the header and root element manually, wouldn't that give
> an error during unmarshalling because I'd need to change my class and
> mapping to reflect the new root element?  I can perhaps see why this isn't
> implemented in castor; it would require the class to be changed upon
> unmarshalling... and to what type of sequence?
>
> So I guess the only way is to specify another class that holds a sequence of
> my base CD class and then marshall that.  For big files, this might become a
> memory problem though.  Any suggestions on if I can avoid this problem?

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Marshalling to XML conforming to existing XSD

by daab :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Werner Guttmann wrote:
How do these objects relate to each other ? Are they part of e.g. an
inheritance hierarchy ? Will each of those objects be mapped ?
Originally, they weren't part of a hierarchy.  What I ended up trying was the example on the castor homepage where a hashtable of objects was wrapped inside a class and that that class would be written.  I couldn't get this to work though.

Werner Guttmann wrote:
Hi,

can you define the term 'multiple objects' for us ?

Werner
I mean a sequence of objects.  They have a list of authors within the book object they marshal, so I suppose technically they cover it.  In this case, I'd want to do multiple books.

In the end what has worked for me is:
http://www.castor.org/how-to-map-a-list-at-root.html
The setRootElement method is very useful.  This is what I am doing now:
    try {
        //Create list from hashtable
        List myObjectList = new LinkedList();
        Enumeration keySetNumeration = myObjectTable.keys();
        while(keySetNumeration.hasMoreElements()) {
            myObjectList.add(myObjectTable.get(keySetNumeration.nextElement()));
        }
       
        //Preparing writer
        BufferedWriter theBufferedFileWriter = new BufferedWriter(new FileWriter("output.xml"));
        StringWriter theStringWriter = new StringWriter();

        //Preparing marshaller
        Marshaller m = new Marshaller();
        Mapping mapping = new Mapping();
        mapping.loadMapping("mapping.xml");
        m.setMapping(mapping);
        m.setWriter(theStringWriter);
        m.setRootElement("rootObject");
        m.marshal(myObjectList);

        //Writing XML file
        theBufferedFileWriter.write(theStringWriter.toString());
        theBufferedFileWriter.close();
        theStringWriter.close();
    } catch (Exception e) {
        System.err.println(e.getMessage());
        e.printStackTrace(System.err);
    }

So my problem is solved for now :)

Re: Marshalling to XML conforming to existing XSD

by Werner Guttmann :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

daab wrote:
>
> Werner Guttmann wrote:
>> How do these objects relate to each other ? Are they part of e.g. an
>> inheritance hierarchy ? Will each of those objects be mapped ?
>>
> Originally, they weren't part of a hierarchy.
But they are now, correct ?

> What I ended up trying was
> the example on the castor homepage where a hashtable of objects was wrapped
> inside a class and that that class would be written.  I couldn't get this to
> work though.
Why not ? Have you seen the HOW-To that shows you how to map a Map of
objects to XML ? This is a recipe that has been tried before it has been
written.

>
>
> Werner Guttmann wrote:
>> Hi,
>>
>> can you define the term 'multiple objects' for us ?
>>
>> Werner
>>
> I mean a sequence of objects.  They have a list of authors within the book
> object they marshal, so I suppose technically they cover it.  In this case,
> I'd want to do multiple books.
>
> In the end what has worked for me is:
> http://www.castor.org/how-to-map-a-list-at-root.html
> The setRootElement method is very useful.  This is what I am doing now:
>     try {
>         //Create list from hashtable
>         List myObjectList = new LinkedList();
>         Enumeration keySetNumeration = myObjectTable.keys();
>         while(keySetNumeration.hasMoreElements()) {
>            
> myObjectList.add(myObjectTable.get(keySetNumeration.nextElement()));
>         }
>        
>         //Preparing writer
>         BufferedWriter theBufferedFileWriter = new BufferedWriter(new
> FileWriter("output.xml"));
>         StringWriter theStringWriter = new StringWriter();
>
>         //Preparing marshaller
>         Marshaller m = new Marshaller();
>         Mapping mapping = new Mapping();
>         mapping.loadMapping("mapping.xml");
>         m.setMapping(mapping);
>         m.setWriter(theStringWriter);
>         m.setRootElement("rootObject");
>         m.marshal(myObjectList);
>
>         //Writing XML file
>         theBufferedFileWriter.write(theStringWriter.toString());
>         theBufferedFileWriter.close();
>         theStringWriter.close();
>     } catch (Exception e) {
>         System.err.println(e.getMessage());
>         e.printStackTrace(System.err);
>     }
>
> So my problem is solved for now :)
Okay.
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email