Compiling XML schema to Java with key/keyref identity constraints - java

Lets say I have the following XML schema:
<xs:schema
xmlns="http://www.example.com/data"
xmlns:data="http://www.example.com/data"
targetNamespace="http://www.example.com/data"
elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="data">
<xs:complexType>
<xs:all>
<xs:element name="countries">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="country" type="country"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="types">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="type" type="type"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="products">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="product" type="product"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
<xs:key name="countryNameKey">
<xs:selector xpath=".//data:country"/>
<xs:field xpath="#name"/>
</xs:key>
<xs:key name="typeNameKey">
<xs:selector xpath=".//data:type"/>
<xs:field xpath="#name"/>
</xs:key>
<xs:keyref name="countryNameRef" refer="data:countryNameKey">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#country"/>
</xs:keyref>
<xs:keyref name="typeNameRef" refer="data:typeNameKey">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#type"/>
</xs:keyref>
<xs:unique name="uniqueProducts">
<xs:selector xpath=".//data:product"/>
<xs:field xpath="#country"/>
<xs:field xpath="#type"/>
</xs:unique>
</xs:element>
<xs:complexType name="country">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="type">
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="product">
<xs:attribute name="country" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
Excuse the contrived example.
As you can see it is tabular data. I define some countries, then I define some types of product. I then define individual products as a type from a country, cheese from France for example.
The important thing to note here is that I use key and keyref to cross-reference all products back to the original country/type.
So, my question is:
Is it possible to compile this schema into java classes that can be unmarshalled using Eclipse Moxy with the cross-references intact?
I know that the JAXB 2.0 spec does not support key/keyref. I also know that Moxy Does.1
Further I know that Moxy doesn't have a Maven plugin and, in any case, uses XJC generated classes and simply adds in a jaxb.properties file to specify the JAXB provider to use.2
So I suspect the answer to my question is "no, you have to craft the classes yourself", but I thought I'd check before I abandoned hope.
To clarify, My product element currently compiles (using maven-jaxb2-plugin) to
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "product")
public class Product implements Cloneable, CopyTo, Equals, HashCode, ToString {
#XmlAttribute(name = "country", required = true)
protected String country;
#XmlAttribute(name = "type", required = true)
protected String type;
//getters and setters
}
It, references the Strings rather than the Country and Type objects.

Currently EclipseLink JAXB (MOXy) only extends the XJC tool to add a jaxb.properties file that indicates that MOXy is the JAXB (JSR-222) provider. I have entered the following enhancement (currently unscheduled) to track this request:
http://bugs.eclipse.org/411619

Related

Java class to XSD

Could someone please tell me what XSD matches this Java class?
public class MyClass {
private List<String> list1;
private List<String> list2;
private XMLGregorianCalendar date;
// getters and setters
}
I've tried the following, but I'm receiving an One of :attribute, :attributeGroup, :anyAttribute is expected error:
<xs:element name="myClass">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="list1" type="xs:string"/>
</xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="list2" type="xs:string"/>
</xs:sequence>
<xs:element name="date" nillable="true" type="xs:dateTime"/>
</xs:complexType>
</xs:element>
So it seems I'm not using the <xs:sequence> tag correctly. Could someone please shed some light? (I'm far from being an expert in XML-related stuff)...
I'm using Spring Boot 1.4.4.RELEASE version with Java 7.
The xs:sequence within a xs:complexType defines a specific order in which an elements children must occur. To create a list of elements you simply use the minOccurs and maxOccurs directly on the xs:element tag you want repeated, as follows:
<xs:element name="myClass">
<xs:complexType>
<xs:sequence>
<xs:element name="list1" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="list2" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="date" nillable="true" type="xs:dateTime"/>
</xs:sequence>
</xs:complexType>
</xs:element>
This should create the class you expect and require XML such as the following (order of tags matter):
<myClass>
<list1>a</list1>
<list1>b</list1>
<list2>y</list2>
<list2>z</list2>
<date>2019-06-26T00:00:00.0000000Z</date>
</myClass>
Placing minOccurs and maxOccurs on the xs:sequence tag requires the entire sequence of elements to be repeated.

How to parser XML schema and fetch the property names

I want to parse XML schema and then fetch elements from schema in that if there is complex object then that attributes should be fetch with prefix as main complex type.
for instance
<xs:element name="address" >
<xs:complexType>
<xs:sequence>
<xs:element name="city" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="zipcode" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Address is complex type if we want to fetch zipcode then it should be like 'address.zipcode'
Is there a way to do this or we have to check manually for type and create fields.
below is XML schema.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Employee">
<xs:complexType>
<xs:sequence>
<xs:element name="empId" type="xs:integer"/>
<xs:element name="firstName" type="xs:string"/>
<xs:element name="lastName" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="address" >
<xs:complexType>
<xs:sequence>
<xs:element name="city" type="xs:string"/>
<xs:element name="street" type="xs:string"/>
<xs:element name="zipcode" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
Extracting information from raw schema documents is challenging unless you know that the schema will be restricted to use a subset of the language: for example, that it will not use named model groups, or substitution groups, or complex types derived by extension.
It's easy to write something (e.g. in XSLT) that works with your examples - or at least, it would be easy if we had a clearer picture of what output you wanted - but writing something that can handle ANY schema is much more difficult.
It may be better to work with the compiled representation of a schema produced by a "real" schema processor. For example Xerces has an API allowing access to the "schema components" produced by the schema compiler, and Saxon has an option to produce an SCM file (schema component model) which is an XML file containing the same information; at this level you don't have to cope with all the variety of ways the source schema might have been written.

How to get the right jaxb object when having two elements under one list (jaxbObj.getAoAndBo() )?

I'm using Java and JAXB for parsing a xml file.
I had a schema(xsd) that contains secquence element that contains two inner sequence element.
the xsd looks something like the following:
...
<xs:element name="product_list">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element maxOccurs="unbounded" name="product">
<xs:complexType>
<xs:sequence />
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="release" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
<xs:element maxOccurs="unbounded" name="info">
...
</xs:complexType>
</xs:element>
</xs:schema>
After unmarshalling, when I want to fetch the list of "product", I get:
product_list.getProductsAndInfo() => type: List<Object>
How can I get the information from the "product" object? (e.g product_list.getProduct)
for getting the needed object information there is a need to use casting on the list of objects, for example:
ProductList pl = new ProductList(); // xml main object/element
pl= unmarshallfunc();
((ProductList.Product)pl.getProductAndInfo().get(0)).getName(); //type: List cast to Product.

Jaxb generate one get method for all elements

Part of my xsd file looks like this:
<xs:complexType name="group">
<xs:sequence maxOccurs="unbounded" minOccurs="1">
<xs:element name="title" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="module" type="module" nillable="true" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" />
</xs:complexType>
When I generate my classes using Jaxb in Eclipse. The "Group" class generates a method called:
public List<JAXBElement<?>> getTitleAndDescriptionAndModule();
How do I change the xsd so that I get getter for each of the elements?

How to properly declare an extension within a schema?

In my schema file below, I have an element Stat which extends Entity. As far as I am aware, I follow w3's example, but when I go to parse the schema (and the xml that uses the schema) with through java's DocumentBuilderFactory and SchemaFactory I get this exception:
org.xml.sax.SAXParseException; systemId: file:/schema/characterschema.xsd;
src-resolve.4.2: Error resolving component 'cg:Entity'. It was detected that
'cg:Entity' is in namespace 'http://www.schemas.theliraeffect.com/chargen/entity',
but components from this namespace are not referenceable from schema document
'file:/home/andrew/QuasiWorkspace/CharacterGenerator/./schema/characterschema.xsd'.
If this is the incorrect namespace, perhaps the prefix of 'cg:Entity' needs
to be changed. If this is the correct namespace, then an appropriate 'import'
tag should be added to '/schema/characterschema.xsd'.
So, it seems that I cannot see my namespace within my schema. Do I need to import my schema into itself or am I completely misreading this exception? Could it be that I am declaring my schema incorrectly?
This is my schema for reference:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:cg="http://www.schemas.theliraeffect.com/chargen/entity"
elementFormDefault="qualified">
<xs:element name="Entity">
<xs:complexType>
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="description" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="Stat">
<xs:complexType>
<xs:complexContent>
<xs:extension base="cg:Entity">
<xs:sequence>
<xs:element name="table" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:schema>
There are two problems with your schema. First, you don't declare a targetNamespace so the Entity and Stat elements you are defining are not in a namespace. Second, a type can't extend an element, only another type.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:cg="http://www.schemas.theliraeffect.com/chargen/entity"
targetNamespace="http://www.schemas.theliraeffect.com/chargen/entity"
elementFormDefault="qualified">
<xs:complexType name="EntityType">
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="description" type="xs:string"/>
</xs:complexType>
<xs:element name="Entity" type="cg:EntityType" />
<xs:complexType name="StatType">
<xs:complexContent>
<xs:extension base="cg:EntityType">
<xs:sequence>
<xs:element name="table" type="xs:string" minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="Stat" type="cg:StatType" />
</xs:schema>
Here I'm defining two types, one of which extends the other, and two top level elements of the respective types. All the top-level types and elements are defined into the targetNamespace of the schema, and the nested table element inside StatType is also in this namespace because of the elementFormDefault="qualified" - without this the Entity and Stat elements would be in the http://www.schemas.theliraeffect.com/chargen/entity namespace but the table element would be in no namespace.

Categories