Java XML: How to force wildcard (xs:any) strict matching? - java

I have a bunch of external XSDs which I can't change.
They use wildcard content models (xs:any) with processContents="skip".
Question:
Is there a programmatic way in java/JAXP to force wildcard (xs:any) processContents="strict" matching instead (without changing the XSDs)?

Sure. Use Java to modify the schema before using it for validation. You don't have to change the original schema, just the one that you're validating against.
If you're using XSD 1.1 you could create the locally-modified schema using xs:override.

Related

JAXB issue with missing namespace definition

So I searched around quite a bit for a solution to this particular issue and I am hoping someone can point me in a good direction.
We are receiving data as XML, and we only have XSD to validate the data. So I used JAXB to generate the Java classes. When I went to unmarshal a sample XML, I found that some attribute values are missing. It turns out that the schema expects those attributes to be QName, but the data provider didn't define the prefix in the XML.
For instance, one XML attribute value is "repository:<uuid>", but the namespace prefix "repository" is never defined in the dataset. (Never mind the provider's best practices suggest defining it!)
So when I went to unmarshal a sample set, the QName attributes with the specified prefix ("repository" in my sample above) are NULL! So it looks like JAXB is "throwing out" those attribute QName values which have undefined namespace prefix. I am surprised that it doesn't preserve even the local name.
Ideally, I would like to maintain the value as is, but it looks like I can't map the QName to a String at binding time (Schema to Java).
I tried "manually" inserting a namespace definition to the XML and it works like a charm. What would be the least complicated method to do this?
Is there a way to "insert" namespace mapping/definition at runtime? Or define it "globally" at binding time?
The simplest would be to use strings instead of QName. You can use the javaType customization to achieve this.
If you want to add prefix/namespace mappings in the runtime, there are quite a few ways to do it:
Similar to above, you could provide your own QName converter which would consider your prefixes.
You can put a SAX or StAX filter in between and declare additional prefixes in the startDocument.
What you actually need is to add your prefix mappings into the UnmarshallingContext.environmentNamespaceContext. I've checked the source code but could not find a direct and easy way to do it.
I personally would implement a SAX/StAX filter to "preprocess" your XML on the event level.

Is there a way I can read a xml file in java without having to define the class to read into

I am experimenting with JAXB library to read xml files and I see that I need to define the Class objects along with annotations to indicate the xml element structure. I was wondering if there is a way that I can read the xml file without having to define such a class. this will permit the user to add a new tag without having to redefine my class.
I am not particular about jaxb usage, any other java libraries are ok too.
Sure, if you just want to work with raw XML without binding it onto POJOs, you can use javax.xml.parsers.DocumentBuilderFactory/javax.xml.parsers.DocumentBuilder to read any arbitrary XML directly into a org.w3c.dom.Document and just work with it as a document instead of as mapped data.

Map JAXB generated Objects using XPATH

I would like to map the value using Xpath instead of directly accessing the Classname.methodname Using JAXB
eg:
Customer/name
ideal jaxb : new Customer().setName("XXXX");
instead of above : xxxx.setValue("customer/name","XXXXX") should automatically set the value for the Xpath. and generate in the XML .
Is there any provision like this in JAXB. ( I know this in castor using FieldDescriptors and ClassDescriptors).
As far I know there is no provison in JAXB to do this. It's primary purpose is to
Marshall and Unmarshall XML Documents to/from Java Objects.
If I understand you correctly, JAXB is irrelevanto to what you want to do; if you can handle the expressions not being XPATH, have a look into Apache Beanutils: specifically BeanUtils.setProperty(object, "customer.name", "XXXX").
If you are wiling to use another technology, JXPath can be used to navigate javabeans via something similar to xpaths. You can also use JXPath to poplulate javabeans with information
http://commons.apache.org/proper/commons-jxpath/
Specifically, when you supply a factory you can create objects. There are several situations that are not supported nativly, but with a little bit of thought you can implement your own extension of createPathAndSetValue that can deal with your specific predicate logic.
http://commons.apache.org/proper/commons-jxpath/users-guide.html#Creating_Objects

How to allow for different XSD versions to be validated properly?

I am attempting to update some xml parsers, and have hit a small snag. We have an xsd that we need to keep compatible with older versions of the xml, and we had to make some changes to it. We made the changes in a new version of the xsd, and we would like to use the same parser (as the changes are pretty small in general, and the parser can easily handle both). We are using the XMLReader property "http://java.sun.com/xml/jaxp/properties/schemaSource" to set the schema to the previous edition, using something like the following:
xmlReader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource",
new InputSource(getClass().getResourceAsStream("/schema/my-xsd-1.0.xsd")));
This worked fine when we only had one version of the schema. Now we have a new version, and we want the system to use whichever version of the schema is defined in the incoming xml. Both schemas define a namespace, something like the following:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.mycompany.com/my-xsd-1.0"
xmlns="http://www.mycompany.com/my-xsd-1.0"
elementFormDefault="unqualified" attributeFormDefault="unqualified">
and, for the new one:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.mycompany.com/my-xsd-1.1"
xmlns="http://www.mycompany.com/my-xsd-1.1"
elementFormDefault="unqualified" attributeFormDefault="unqualified">
So, they have different namespaces and different schema "locations" defined. We don't want the schema to live on the 'net - we want it to be bundled with our system. Is there a way to use the setProperty mechanism to do this behavior, or is there a different way to handle this?
I tried putting both resources in an input stream in an array as the parameter, but that didn't work (I remember reading somewhere that this was a possible solution - although now I can't find the source, so it might have been wishful thinking).
So, it turns out what I had tried actually worked - we were accidentally using invalid xml! What works (for anyone else who is interested) is the following:
List<InputSource> inputs = new ArrayList<InputSource>();
inputs.add(new InputSource(getClass().getResourceAsStream("/schema/my-xsd-1.0.xsd")));
inputs.add(new InputSource(getClass().getResourceAsStream("/schema/my-xsd-1.1.xsd")));
xmlReader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource",
inputs.toArray(new InputSource[inputs.size()]));
Personally I think it's generally a bad idea to change the namespace when you version a schema, unless the changes are radical - but views differ on that, and you seem to have made your decision, and you may as well reap the benefits.
Since you're using two different namespaces, the schemas are presumably disjoint, so you should be able to give the processor a schema that's the union of the two - I don't know if there's a better way, but one way of achieving this is to write a little stub schema that imports both, and supply this stub as your schemaSource property. The processor will use whichever schema declarations match the namespace of the elements in the source document.
(Using version-specific namespaces makes this task - validation - easier. But it makes subsequent processing of the XML, e.g. using XPath, harder, because it's hard to write code that works with both namespaces.)

regenerate ecore after schema changes

I have a schema in xsd file. once in a while a new version of the schema is created, and I need to update my .ecore (and .genmodel).
How do I update them, without deleting them and re-generate them. I have made some manual modification to the ecore, and i want to keep this modifications.
Ido.
Use the Reload... action on the *.genmodel to update the *.ecore based on the new version of the *.xsd.
And don't change the .ecore directly. Using ecore: annotations in the schema. http://www.eclipse.org/modeling/emf/docs/overviews/XMLSchemaToEcoreMapping.pdf
I've never tried this, but the XSD FAQ says this:
JAXB produces a simple Java API given
an XML Schema and it does so using
essentially a black box design. EMF
produces an Ecore model given an XML
Schema and then uses template-based
generator technology to generate a
rich Java API (of hand written
quality). The XML Schema to Ecore
conversion can be tailored, the
templates used to generate the Java
API can be tailored, and the resulting
Java API can be tailored. The
generator supports merging
regeneration so that it will preserve
your hand written changes. In other
words, EMF is far richer and more
flexible, and supports a broader
subset of XML Schema (especially in
2.0, where wildcards and mixed content will be supported).
If I were you, I'd try some experiments to see how well this process works, and what the practical limitations are.
You can regenerate using the context menu options. To preserve your modifications:
If there is a method that has "Gen" added to the name -- e.g. setWhateverGen in addition to setWhatever -- new code will be generated to the "Gen" method. So leave the "Gen" method alone so that it can be overwritten, and then call it from the non-Gen method, which you can modify.
All the generated methods are annotated with #generated. If you add "NOT" -- #generated NOT -- it will not be overwritten.
All other content should be merged. Go ahead and experiment -- that's what version control is for....

Categories

Resources