Motivation
Given the example of programmitically creating a SamplingFeature and adding this to a gml:FeatureCollection. "sa:SamplingFeature" is a member of the substitution group "gml:_Feature", hence it is not possible to create the "!SamplingFeature" with a single method call (such as collection.addNewSamplingFeature()). Here is a short example how this can be achieved using XmlCursors and a few lines of code. It can be used for any substitution group you want to programmatically create.
Note that this applies for valid substitutions of a substitution group which are
not available at the time of schema compilation (an example is OGC Sampling 1.0 [as the extension schema] with SamplingPoint as a valid substitution for GML 3.1 [as the base schema] gml:_Feature). Here,
Available at the time of schema compilation means that the contens of both schemas need to be compiled into one resulting jar. Having a .jar with the compiled extension schema on the classpath while compiling the base schema is not sufficient.
Dealing with unresolvable but valid substitutionGroup members
Creating substitutionGroup members
The starting point is the creation the
FeatureCollection and the
SamplingFeature:
FeatureCollectionDocument doc = FeatureCollectionDocument.Factory.newInstance();
FeaturePropertyType member = FeatureCollectionDocument.Factory.newInstance().addNewFeatureCollection().addNewFeatureMember();
SamplingFeatureDocument samplingFeature = SamplingFeatureDocument.Factory.newInstance();
SamplingFeatureType feature2 = samplingFeature.addNewSamplingFeature();
StringOrRefType desc = feature2.addNewDescription();
desc.setStringValue("test");
member.setFeature(feature2);
|
As no method like "member.addNewSamplingFeature()" is available, it must use "member.setFeature()". Therefore this would result in:
<gml:_FeatureCollection xmlns:gml="http://www.opengis.net/gml">
<gml:featureMember>
<gml:_Feature xsi:type="sa:SamplingFeatureType" xmlns:sa="http://www.opengis.net/sampling/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<gml:description>test</gml:description>
</gml:_Feature>
</gml:featureMember>
</gml:_FeatureCollection>
|
Obviously we need to replace the "gml:_Feature" with "sa:SamplingFeatureType" to make the resulting document valid. This can be done by using the XMLBeansTools.qualifySubstitutionGroup(...) method:
...
member.setFeature(feature2);
XMLBeansTools.qualifySubstitutionGroup(member.getFeature(), SamplingFeatureDocument.type.getDocumentElementName(), null)
|
Note the usage of XMLBeansTools class. It is available in the 52n-oxf-2.0/52n-oxf-xmlbeans module. Also note that the last argument is null. This allows the method to skip the built-in XmlObject.substitute(...) mechanism as we know that it will fail (due to unavailability of the SamplingFeature type during GML schema compilation time). For convenience, here are the contents of the "qualifySubstitutionGroup(...)" method:
public static XmlObject qualifySubstitutionGroup(XmlObject xobj, QName newInstance, SchemaType newType) {
XmlObject substitute = null;
if (newType != null) {
substitute = xobj.substitute(newInstance, newType);
if (substitute != null && substitute.schemaType() == newType &&
substitute.getDomNode().getLocalName().equals(newInstance.getLocalPart())) {
return substitute;
}
}
XmlCursor cursor = xobj.newCursor();
cursor.setName(newInstance);
QName qName = new QName("http://www.w3.org/2001/XMLSchema-instance", "type");
cursor.removeAttribute(qName);
cursor.dispose();
return null;
}
|
The method will return null if the cursor.setName(...) technique is applied. This is done because the returned object (e.g. xobj, or cursor.getObject()) is disconnected and thus can no longer be manipulated. So its just null to make sure you won't do that.
Sometimes the famous xsi:type is added when using substitution groups. This methods also removes it as it is not needed.
The overall result is a valid document, using "sa:SamplingFeature". This method can be applied to any substitution group you are dealing with by only providing the XmlObject instance and target QName.
<gml:_FeatureCollection xmlns:gml="http://www.opengis.net/gml">
<gml:featureMember>
<sa:SamplingFeature xmlns:sa="http://www.opengis.net/sampling/1.0">
<gml:description>test</gml:description>
</sa:SamplingFeature>
</gml:featureMember>
</gml:_FeatureCollection>
|
Of course, the same procedure can be applied to gml:_FeatureCollection. Give it a try (by replacing it with sa:SamplingFeatureCollection).
Attached find a working example. You need 52n-xml-gml-v311, 52n-xml-sampling-v100, 52n-xml-filter-v20, 52n-oxf-xmlbeans and log4j on your buildpath.
Parsing substitutionGroup members with unresolved valid substitutions
TBD. We have created a work around for document validation with unresolved substitutionGroup members. Located within the XMLBeansParser class of 52n-oxf-2.0/52n-oxf-xmlbeans module. Description tbd.
Creating substitutionGroup members with compiled-in valid substitutions
There are also valid substitutions which are available at schema compilation time and thus can be easily substituted. an example is a substitution for fes:logicOps such as fes:And. Here, we are able to continue using the object after successfully qualifying it.
FilterDocument filterDoc = FilterDocument.Factory.newInstance();
FilterType filter = filterDoc.addNewFilter();
XmlObject andOp = XMLBeansTools.qualifySubstitutionGroup(filter.addNewLogicOps(), AndDocument.type.getDocumentElementName(), BinaryLogicOpType.type);
XmlObject anotherAndOp = XMLBeansTools.qualifySubstitutionGroup(((BinaryLogicOpType) andOp).addNewLogicOps(),
AndDocument.type.getDocumentElementName(), BinaryLogicOpType.type);
|