Organizing XSDs in a JAR - java

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);

Related

Generate enum from deeply nested xsd elements

I'm having a problem generating enum from deeply nested xsd elements. When I generate the code during maven build, my enums are of type string. Here's an example.
<xs:element name="Car">
<xs:complexType>
<xs:sequence>
<xs:element name="CarModal">
<xs:complexType>
<xs:sequence>
<xs:element name="Type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="SomeValue"/>
<xs:enumeration value="AnotherValue"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:completType>
</xs:element>
</xs:sequence>
From the above example we would have another 20 elements inside of Car element that contains enum value name 'Type'. I have a binding file to bind 'Type' to jaxb:typesafeEnumClass but it's not working, i'm still getting strings as my enum type. Here's an example of my binding.
<jaxb:bindings schemaLocation="someLocation">
<jaxb:bindings node="//xs:element[#name='Car']>
<jaxb:bindings node="//xs:element[#name='CarModal']">
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
<jaxb:typesafeEnumClass name="Type"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Thanks for any help and I can't change the xsd
I guess your bindings are nor precise enough. When you write //xs:element[#name='CarModal'], you basically say "any CarModal element inside my schema". Next, you say you have many Type elements so xs:element[#name='Type']/xs:simpleType is not precise enough.
Try more precise expressions like
xs:complexType/xs:sequence/xs:element[#name='CarModal']/
xs:complexType/xs:sequence/xs:element[#name='Type']/xs:simpleType
Next, your binding makes a general impression of the incorrect syntax. For instance this:
<jaxb:bindings node="xs:element[#name='Type']/xs:simpleType>
is invalid XML (missing " after xs:simpleType). So it might be the case that you binding is not considered at all - otherwise you should have gotten an error instead of generated code. Double-check if the binding is applied at all.

Make xs and xmls:xsi attributes required in XSD

I have the following schema
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="translator">
...
</xs:element>
</xs:schema>
How I can define the following required attributes, so when adding a new translator node, those attributes are also added?
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Translator.xsd"
If I put them in XSD, like this
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="translator">
<xs:attribute name="xmlns:xsi" type="xs:string" default="http://www.w3.org/2001/XMLSchema-instance"/>
<xs:attribute name="xsi:noNamespaceSchemaLocation" type="xs:string" default="Translator.xsd"/>
</xs:element>
</xs:schema>
The following problem is reported by Xerces
[Error] :678:114: s4s-att-invalid-value: Invalid attribute value for 'name' in element 'attribute'. Recorded reason: cvc-datatype-valid.1.2.1: 'xmlns:xsi' is not a valid value for 'NCName'.
[Error] :678:114: src-attribute.3.1: One of 'ref' or 'name' must be present in a local attribute declaration.
[Error] :679:117: s4s-att-invalid-value: Invalid attribute value for 'name' in element 'attribute'. Recorded reason: cvc-datatype-valid.1.2.1: 'xsi:noNamespaceSchemaLocation' is not a valid value for 'NCName'.
[Error] :679:117: src-attribute.3.1: One of 'ref' or 'name' must be present in a local attribute declaration.
A warning first: the XML Schema specification forbids declaring attributes in the XML Schema instance namespace, and explicitly discourages attempts to alter its behavior.
Having said that, the reason for the errors you are getting is that the name attribute only supports definition of new elements in the target namespace (or in this case in no namespace) by providing their local names.
You could technically do something like this, by referencing the xsi:noNamespaceSchemaLocation attribute, which is already defined in the builtin XML Schema instance namespace:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xs:element name="translator">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute ref="xsi:noNamespaceSchemaLocation" default="Translator.xsd"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
However, you cannot change its definition, and since this attribute is builtin and processed in a special way, I am not sure you can much influence its behavior.

How to maintain package structure when using schemagen and xjc

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>

Getting xsd restrictions of specific xml element

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

Java/XSD parsing

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.

Categories

Resources