Is it possible to get restrictions of specific element when I'm parsing XML file in Java?
For example, if I have a schema:
<xs:element name="MyString" minOccurs="0">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
when I get node MyString during XML file parsing I want to be able to acquire information that its restrictions are xs:string and maxLength = 100.
I would recommend this project.
It is the same jaxb plugin as Puce linked, but with proper maven project and some improvements.
You could look for/ write a JAXB plugin to generate Bean Validation Annotations (JSR-303), e.g.:
http://metro.1045641.n5.nabble.com/JAXB-plugin-to-generate-Bean-Validation-Annotations-JSR-303-td5598189.html
Related
I'm working on a project in java where xml input is read via xjc into generated classes. So the xsd schema is converted into java type.
All is well, and usually I have no problems, but I can't seem to get this conversion right: I want to convert an xml list of enums into a java list of enums.
This is my xsd part:
<xs:attribute name="myTypes" use="required">
<xs:simpleType >
<xs:list itemType="output.myType"/>
</xs:simpleType>
</xs:attribute>
<xs:simpleType name="output.myType">
<xs:annotation>
<xs:appinfo>
<jaxb:javaType
name="packagename.MyEnumType"
parseMethod="...TypeConverter.unmarshalOutputMyType"
printMethod="...TypeConverter.marshalOutputMyType"
/>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:enumeration value="option1"/>
<xs:enumeration value="option2"/>
<xs:enumeration value="option3"/>
</xs:restriction>
</xs:simpleType>
When doing the xjc generation I keep getting this in the generated java class:
public List<String> getMyTypes()
While I'm expecting this:
public List<MyEnumType> getMyTypes()
How can I make jaxb/xjc to use the List for the generated list, in stead of just parsing the type into a List of Strings? The conversion works perfect if I'm just using the output.myType directly as simpleType for the attribute, but it doesn't work when I try to make the attribute into a list of those items.
I have the following structure in a JAR:
Products.xsd
ProductCommonTypes.xsd
/com
/foo
Products.class
When I do
schemaURL = Products.class.getClassLoader().getResource(schemaFile);
I see "Using schemaURL: jar:file:/C:/my.jar!/Products.xsd". I think this is good.
Later, I try to create a Schema and get an exception stating "Cannot resolve the name 'common:nonEmptyString' to a(n) 'type definition' component."
I believe that the problem is that it is unable to find common:nonEmptyString (which is in ProductCommonTypes.xsd) but can not figure out how to fix it.
Products.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:p="http://www.foo.com/Products"
targetNamespace="http://www.foo.com/Products"
xmlns:common="http://www.foo.com/ProductsCommonTypes"
elementFormDefault="qualified">
<xs:import schemaLocation="ProductsCommonTypes.xsd"
namespace="http://www.foo.com/ProductsCommonTypes"/>
<xs:element name="products">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="common:nonEmptyString" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
ProductCommonTypes.xsd
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foo.com/ProductsCommonTypes"
xmlns="http://www.foo.com/ProductsCommonTypes"
elementFormDefault="qualified" >
<xs:simpleType name="nonEmptyString">
<xs:annotation>
<xs:documentation>A type that will require a non-empty string value be present
</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="(\s*[^\s]\s*)+"></xs:pattern>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="url">
<xs:annotation>
<xs:documentation>A HTTP URL</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:anyURI">
<xs:pattern value="https?://.+"></xs:pattern>
</xs:restriction>
</xs:simpleType>
</xs:schema>
[jaxb - Unable to unmarshall from XSD which included other xsd
suggests adding all schema references, but I am working with many schemas that all import several other schemas. Seems like it could get ugly quick!
Is there a generic/dynamic solution that does not require me to identify and hardcode all schemas everytime I plan on working with one that might import others?
I plan to move all XSDs to a MyXSDs folder within the jar at some point. After moving them, will I have to do anything differently due to the location change?
Solution
I was able to solve this using an XMLCatalogResolver and creating an XML catalog file.
I moved all of my XSDs into a single folder and have the following structure in my JAR:
MyXSDs
Products.xsd
ProductCommonTypes.xsd
/com
/foo
Products.class
First, I created the catalog file and identified the schema that was being referenced.
<!DOCTYPE catalog
PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
<public
publicId="http://www.foo.com/ProductCommonTypes"
uri="ProductCommonTypes.xsd"/>
</catalog>
Then, I created an XMLCatalogResolver that uses my catalog file and used it as the ResourceResolver for my SchemaFactory. It is important to note that the catalogs must be specified as an ordered array of absolute URIs as per the constructor's documentation.
// The catalogs must be an ordered array list of *ABSOLUTE* URIs
String[] catalogs = new String[] { xmlCatalogAbsPath };
XMLCatalogResolver resourceResolver = new XMLCatalogResolver(catalogs);
schemaFactory.setResourceResolver(resourceResolver);
You must specify the relative path to the XSD file. Therefore, because I put all of mine into a folder, I set relatativeSchemaPath="MyXSDs/Products.xsd" for use with ClassLoader.getSystemResource.
StreamSource streamSource = new StreamSource(ClassLoader.getSystemResource(relatativeSchemaPath).toString());
Schema schema = schemaFactory.newSchema(streamSource);
I'm trying to generate java classes using XJC and I have the following problem:
I'm trying to parse this schema which is a big enum type (bigger than default typesafeEnumMaxMembers). So I use following binding:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<!-- Raise theEnumMemberSizeCap limit -->
<jxb:bindings >
<jxb:globalBindings typesafeEnumMaxMembers="2000"/>
</jxb:bindings>
</jxb:bindings>
and then I call xjc with following line:
C:\Program Files\Java\jdk1.7.0_17\bin\xjc.exe -d C:\Users\buriak\out xml\dAllDocuments_v02.1.xsd xml/binding.xjb
this gives no errors, just that:
parsing a schema...
compiling a schema...
Then it ends without creating anything.
Smaller enum types are easily parsed same way, but bigger once are just ignored and if they are a part of some other type other xsd - they simply become a string:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:include schemaLocation="dAllDocuments_v02.1.xsd"/>
<xs:complexType name="tDocument">
<xs:annotation>
<xs:documentation>Документ - описание</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="Code_Document" type="dAllDocuments">
<xs:annotation>
<xs:documentation>Код документа</xs:documentation>
</xs:annotation>
</xs:element>
...............
public class TDocument {
#XmlElement(name = "Code_Document", required = true)
protected String codeDocument;
...............
Using JAXB or XmlBeans results with nothing aswell.
Hope somebody knows what to do with that.
EDIT
After browsing without finding answers for long time I started to think, that it is not the size that is the problem.
I was right and as a result I found this - JAXB enumeration with numeric values
But XSD which I'm trying to parse is very big:
<xs:simpleType name="dAllDocuments">
<xs:restriction base="xs:string">
<xs:enumeration value="008001000000"/>
<xs:enumeration value="008001001000"/>
<xs:enumeration value="008001002000"/>
<xs:enumeration value="008001003000"/>
<xs:enumeration value="008001004000"/>
<xs:enumeration value="008001005000"/>
<xs:enumeration value="008001006000"/>
<xs:enumeration value="008001007000"/>
<xs:enumeration value="008001008000"/>
<xs:enumeration value="008001009000"/>
<xs:enumeration value="008001010000"/>....
And it keeps going for long more. There is absolutely no way I can write them all down in such a way:
<jxb:bindings node="//xs:simpleType[#name='dAllDocuments']/xs:restriction/xs:enumeration[#value='008001000000']">
<jxb:typesafeEnumMember name="OOBOOIOOOOOO"/>
</jxb:bindings>
Is there any way to make this work other than specifying name for each value manually?
I mean I can create a program which will make that kind of stuff using Strings, but is there any smart way?
Because actual XSD that I'm parsing is connected to multiple of such ENUM XSD and I need to parse them all.
After spending some more time on research I finally managed to get results which I was waiting for from xjc.
Here is binding file I was using, so that I don't get warning for enum type being too big and so that all those big enum types would have a generated name like VALUE_1, VALUE_2 etc.
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<!-- Raise theEnumMemberSizeCap limit -->
<jxb:bindings >
<jxb:globalBindings typesafeEnumMaxMembers="2000" typesafeEnumMemberName="generateName"/>
</jxb:bindings>
<jxb:bindings schemaLocation="STD_Region_Cadastr.xsd">
<jxb:bindings node="//xs:complexType[#name='tRight_Owner']">
<jxb:class name="tRight_Owner2"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Also I'd like to mention that, since XSD files, which I was parsing, had a lot of cyrillic letters, here is xjc call I was using:
C:\Program Files\Java\jdk1.7.0_17\bin>xjc.exe -b xml/binding.xjb -d C:\Users\buriak\out xml\STD_Region_Cadastr.xsd -encoding UTF-8
That makes almost every cyrillic letter enterance show in java files correctly.
That's it.
I am new to JAX B. I created a project with the structure :
src-
entity-
Person
property-
Address
I generate a xsd document using the command
C:\workspace\JAXTest\src>schemagen entity\Person.java property\Address.java
I see schema1.xsd in src folder now but it does not have any package information. So, If I use xjc to generate classes, I get all the classes in the same folder.
C:\workspace\JAXTest\src>xjc schema1.xsd
parsing a schema...
compiling a schema...
generated\Address.java
generated\ObjectFactory.java
generated\Person.java
What can be done so that the xsd can contain the package information so that the generated classes follow the structure of the classes used to create the xsd.
Thanks in advance!
Edit :
There is no particular requirement I am working towards. I am just trying to learn XSD-Class and Class-XSD conversions correctly. Also, I have found that I can use jax customization to specify the global package name but it doesn't work for individual classes. Basically, this does not put my Person in PersonPackage package.
<xs:complexType name="person">
<xs:annotation>
<xs:appinfo>
<jaxb:package name="PersonPackage"/>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="address" type="address" minOccurs="0">
</xs:element>
<xs:element name="name" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
I doubt if there is something like this but I thought to ask though:
Does anyone know if there is a library in Java that reads an xsd file and "creates" the defined elements e.g. in a String format to use in the code?
E.g. read in the following schema:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Address">
<xs:complexType>
<xs:sequence>
<xs:element name="Street" type="xs:string" />
<xs:element name="Town" type="xs:string" />
<xs:element name="Country" type="xs:string" minOccurs="0" />
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
And have a String in the following format:
<Address>
<Street></Street>
<Town></Town>
<Country></Country>
</Address>
Automatic tools do something similar, i.e. parse a WSDL and from the types section create for example JAXB classes that can be instances of the elements defined in schema.
Is there any library to do this?
UPDATE:
For example in Eclipse when creating an xml descriptor for a web application it presents a tree table with all the required elements for the users to fill in according to schema. How do they do it? I imagine they parse the xsds included in the jars
Any input is very welcome.
Thank you!
If its a WSDL file with which you want to generate Java classes, then Axis WSDL2Java (based on JAXB) can be used to get classes based on the schema defined in the WSDL.
JAXB also offers binding framework which you might want to look up.
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/twbs_jaxbschema2java.html
Above link should be useful.
oXygen has an XML instance generator that can generate a set of XML document samples based on a given XML Schema.
You can also invoke it from the commandline.