I'm trying to map a POJO to XML using Castor.
Let's say I have a Order that has a collection of Items... is there any way of achieving an xml like the following:
<order>
...order attributes
<items>
<item> ..item attributes </item>
<item> ..other item </item>
</items>
</order>
I could make something similar but without the <items> node. This wouldn't be a problem in other case but my XML must adhere to a strict XSD schema so I need to do it like that.
Thanks!
I though of a kind of "workaround" that would involve creating a new java object (that would be the node) that would only contain the list of items... can anyone think of a better approach? there's a 100 rep bounty open since now!
You can use the location attribute of the bind-xml lement
http://castor.codehaus.org/1.2/xml-mapping.html#6.-Location-attribute
Example from the docs:
<class name="Foo">
<field name="bar" type="Bar">
<bind-xml name="bar" location="abc"/>
</field>
</class>
Produces the following XML:
<foo>;
<abc>
<bar>...</bar>
</abc>
</foo>
The other answer doesn't use the collection attribute which I think is probably what you're ultimately needing.
Something like this might work when included in your mapping for the Order object:
<field name="items" type="item" collection="arraylist" >
<bind-xml name="items" node="element"/>
</field>
Related
SITUATION:
I use beanIO 2.1.0 to read a csv-file into different kind of objects.
This is my csv-File. A list of animals (color, type, number of legs).
In my list are also animals without a type (last row).
brown;cat;4
white;dog;4
brown;dog;4
black;;8
I want to read the csv-file into different animal-objects.
If the type is 'cat' it should be a cat-object. The same with dog.
If the type isn't cat or dog, e.g. empty or an unknown animal-type, then it should be an animal-object.
Here the belonging beanIO-mapping:
<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">
<stream name="animalFile" format="csv" >
<parser>
<property name="delimiter" value=";"/>
</parser>
<record name="animal" class="zoo.Cat">
<field name="color" />
<field name="type" rid="true" literal="cat"/>
<field name="legs"/>
</record>
<record name="animal" class="zoo.Dog">
<field name="color" />
<field name="type" rid="true" literal="dog"/>
<field name="legs"/>
</record>
<record name="animal" class="zoo.Animal" >
<field name="color" />
<field name="type"/>
<field name="legs"/>
</record>
</stream>
</beanio>
My program reads the csv-file, parses it with beanIO and calls the toString-method of the parsed objects.
This is the output. It looks fine:
CAT: brown;cat;4
DOG: white;dog;4
DOG: brown;dog;4
ANIMAL: black;;8
PROBLEM:
Now I just change the order of the animals in the csv-file.
In the second row is the unknown animal-type:
brown;cat;4
black;;8
white;dog;4
brown;dog;4
This ist the new output!
When the first unknown animal is found, then all the following rows are also unknown animals.
CAT: brown;cat;4
ANIMAL: black;;8
ANIMAL: white;dog;4
ANIMAL: brown;dog;4
QUESTION:
Is it a bug in beanIO or can I configure it in the beanIO-mapping?
EDIT: Updated answer after comments from OP.
This is not a bug in BeanIO. You have two options to identify a record with. First, you have the literal attribute as you used it so far. Secondly you can also use a regular expression (regex) to identify records with.
You want to match an Animal object when the type field is not cat or dog, or as you stated when it is an empty string/object.
Your type field definition could be one of two for the Animal record.
<field name="type" rid="true" regex="\s*" />
Here it will match whenever the type field contains spaces as defined by the java regular expressions.
OR
<field name="type" rid="true" regex=""^(?:(?!\b(cat|dog)\b).)*$" />
This will match any record where the type field doesn't contain the words cat or dog.
Try it with this Animal record:
<record name="animal" class="zoo.Animal" >
<field name="color" />
<field name="type" rid="true" regex=""^(?:(?!\b(cat|dog)\b).)*$" />
<field name="legs"/>
</record>
Off-topic. Technically you are not reading a CSV file because then your delimiter must be a comma. Instead, you have a delimited format which uses a semi-colon (;) as a delimiter.
I would also suggest that you make the names of your record definitions unique in your xml mapping file. The record name is used in error messages for reporting the location of a problem. If you have the same record name for all records, you will not know where to look for the problem.
I would like to map the totalAmt tag in below xml file, both its value 100 and it's attribute Ccy.
<?xml version="1.0" encoding="UTF-8"?>
<transaction>
<id>
<eId>transactionId001</eId>
</id>
<amount>
<totalAmt Ccy="XXX">100</totalAmt>
</amount>
</transaction>
By reading BeanIO reference guide and posts here I got the impression that only one of them can be mapped.
So my question is: Can BeanIO handle this tag and could you show me how?
What I have tried and didn't work:
<segment name="amount">
<field name="totalAmount" xmlName="totalAmt"></field>
<field name="currency" xmlName="Ccy" xmlType="attribute"></field>
</segment>
Close, but you still need to add the segment element inside the segment tag to tell which field the attribute is belong to.
example.
<segment name="amount">
<field name="totalAmount" xmlName="totalAmt"></field>
<segment name="totalAmt">
<field name="type" xmlName="Ccy" xmlType="attribute"></field>
</segment>
</segment>
I am using bean io 2.1 version
The
<segment name="totalAmt">
<field name="totalAmount" xmlType="text"></field> --->the bean variable "totalAmount" will give say 100
<field name="Cctype" xmlName="Ccy" xmlType="attribute" default="XXX"></field> -->either set default value as XXX or it will take from cctype variable
</segment>
I have a requirement which is as follows. Lets say I have a XML file which contains the following content.
<?xml version="1.0"?>
<items>
<item id="1" class="Company" interface="true">
</item>
<item id="2" class="MyCompany" implements="Company">
<attribute name="name" value="CompanyB"/>
<attribute name="vatNumber" value="5678"/>
<reference name="CEO" ref_id="11"/>
<reference name="address" ref_id="19"/>
<collection name="contractors">
<reference ref_id="4"/>
<reference ref_id="3"/>
</collection>
<collection name="departments">
<reference ref_id="7"/>
<reference ref_id="6"/>
</collection>
<collection name="oldContracts">
<reference ref_id="4"/>
<reference ref_id="3"/>
</collection>
<collection name="secretarys">
<reference ref_id="14"/>
<reference ref_id="15"/>
</collection>
</item>
</items>
I want to have a convertor to convert this items file into database tables directly and on the same time generate model classes for each type of items. So than I can have a modelservice to control them .Also when i add more attributes to the type it should be able to update the database table and the model code automatically.
In more better way I require some kind of model code generator which create database tables and maps them both in a well planned manner ?
Is some kind of tool already avaiable to do this type of buisness logic.??? I don't like to reinvent the wheel again.?
I'd suggest you you to develop code that transforms your XML to Hibernate HBM file. Then use Hibernate as a persistence layer.
You can even probably create XSLT transformation from your format to HBM.
Actually after little googling I came across Apache Torque which looks awesome from my needs.
I'm using Castor to write out a map of user ID's to time intervals. I'm using it to save and resume progress in a lengthy task, and I'm trying to make the XML as compact as possible. My map is from string userID's to a class that contains the interval timestamps, along with additional transient data that I don't need to serialize.
I'm able to use a nested class mapping:
...
<field name="userIntervals" collection="map">
<bind-xml name="u">
<class name="org.exolab.castor.mapping.MapItem">
<field name="key" type="string"><bind-xml name="n" node="attribute"/></field>
<field name="value" type="my.package.TimeInterval"/>
</class>
</bind-xml>
</field>
...
<class name="my.package.TimeInterval">
<map-to xml="ti"/>
<field name="intervalStart" type="long"><bind-xml name="s" node="attribute"/></field>
<field name="intervalEnd" type="long"><bind-xml name="e" node="attribute"/></field>
</class>
...
And get output that looks like:
<u n="36164639"><value s="1292750896000" e="1292750896000"/></u>
What I'd like is the name, start, and end of the user in a single node like this.
<u n="36164639" s="1292750896000" e="1292750896000"/>
But I can't seem to finagle it so the start and end attributes in the "value" go in the same node as the "key". Any ideas would be greatly appreciated.
Nash,
I think to arrange the castor mapping is bit tricky.
If you want to have structure like
<u n="36164639" s="1292750896000" e="1292750896000"/>
Then you need to create a new pojo file where it will be having
all the three fields Key,intervalStart,intervalEnd.
And let the File name as KeyTimeInterval
And map it like the below.
<field name="userIntervals" collection="map">
<class name="org.exolab.castor.mapping.MapItem">
<field name="u" type="my.package.KeyTimeInterval">
<bind-xml name="u" node="element"/>
</field>
</class>
</field>
<class name="my.package.KeyTimeInterval">
<field name="key" type="String">
<bind-xml name="n" node="attribute"/></field>
<field name="intervalStart" type="long">
<bind-xml name="s" node="attribute"/></field>
<field name="intervalEnd" type="long">
<bind-xml name="e" node="attribute"/></field>
</class>
I think you should be able to use location on s and e. Try this:-
...
<class name="my.package.TimeInterval">
<map-to xml="ti"/>
<field name="intervalStart" type="long">
<bind-xml name="s" location="u" node="attribute"/>
</field>
<field name="intervalEnd" type="long">
<bind-xml name="e" location="u" node="attribute"/>
</field>
</class>
Am answering my own question here, since there is a solution that does exactly what I want, and there's actually an error in the explanation at http://www.castor.org/xml-mapping.html#Sample-3:-Using-the-container-attribute - the container attribute is exactly what's needed here.
Changing one line in the mapping:
<field name="value" type="my.package.TimeInterval" container="true"/>
did exactly what I wanted, it didn't create a subelement for the value, just mapped the fields into the existing parent element. Since then, I've used this quite a few times to map multiple-value classes into their parent.
The error of course is the documentation states you do this by setting the container attribute to false. Of course, it should be true.
I have this class model:
abstract class A {
int a;
}
class B extends A {
int b;
}
class C extends B {
int c;
}
And I'd like to get jibx to output this XML:
<B b=1 a=0>
<children>
<C c=2 b=1 a=0/>
</children>
</B>
I have this binding xml:
<binding>
<mapping class="A" abstract="true">
<value name="a" field="a" style="attribute" usage="optional"/>
<collection field="children" type="java.util.ArrayList"/>
</mapping>
<mapping name="B" class="B" extends="A">
<value name="b" field="b" style="attribute" usage="optional"/>
<structure map-as="A"/>
</mapping>
<mapping name="C" class="C" extends="B">
<value name="c" field="c" style="attribute" usage="optional"/>
<structure map-as="B"/>
</mapping>
</binding>
However I keep getting artifacts like this:
<C c=2>
<B b=1 a=0>
<children>
...
</children>
</B>
</C>
As temporary solution I've changed my inheritance structure to have AbstractB and B extends AbstractB and C extends AbstractB, but it really annoys me to have to redesign my class because of jibx.
Anyone knows how to solve this?
Edit:
As a bonus question - how do you use code/decode java.util.Map with Jibx? I know it can't be done natively (would be glad to be disproved!) but what would you do to code Map (no strings). Please note we're not using jibx-extras.jar, so solutions should not rely on it.
Actually IMHO it feels kind of normal to get C as parent (in XML sense) of B, because C contains the information of B (from wich it inherits) and its own information aside, but B doesn't know about those C-specific information right ?
To make it clearer: it B is Bird and C is Chicken. Chicken is a Bird, so C inherits form B, OK. But in XML format, would store :
<Bird color="brown">
<Chicken label="Kentucky-fried" />
</Bird>
or
<Chicken label="Kentucky-fried"> <!-- chicken-specific information -->
<Bird color="brown" /> <!-- "birdy" part of the chicken -->
</Chicken>
?
So on the model point of view, it seems logical to me...
And I didn't find a way of achieving the opposite in the binding tutorial, sorry.