Hi,
I am wondering how to transform a given XSD to Xtext grammar and allow to serialize XMLs to Xtext models and vice-versa including arbitrary XML content using xs:any or similar.
To approach this, I am using both the "XSD to Ecore Importer" and "Xtext Project from existing Ecore Models" Eclipse wizards to transform a given XSD into Xtext grammar.
Furthermore, I build a Java class that employs the standalone setup of the Xtext project that has been generated for the Ecore model. It uses the following lines of code to read an XML conforming to the XSD and save it in the format of the Xtext DSL:
// load input model from file
Resource inputResource = resourceSet.getResource(inputModelURI, true);
// create output model resource by copying contents of input model
Resource outputResource = resourceSet.createResource(outputModelURI);
outputResource.getContents().add(EcoreUtil.copy(inputResource.getContents().get(0)));
// save output model to file
outputResource.save(optionsMap);
This works quite well for simple XSDs - even a roundtrip, i.e., from XML to mydsl and (back) to XML, however as soon as constructs like xsd:any or xsd:element with type="xsd:anyType" are introduced, that allow to represent any arbitrary XML content including any attributes and mixed text in an instance, things become fuzzy - let me explain in more detail.
Let's say we have the following simplistic XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" targetNamespace="http://example.com/example-with-anyfeature"
xmlns="http://example.com/example-with-anyfeature">
<!-- ROOT ELEMENT -->
<xsd:element name="rootElement">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="properties" type="Properties" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="Properties">
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
The above XSD allows us to represent an XML like the following:
<?xml version="1.0" encoding="UTF-8"?>
<p:rootElement xmlns:p="http://example.com/example-with-anyfeature"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.com/example-with-anyfeature ../metamodels/Example_with_anyfeature.xsd ">
<properties>
<unknownElement1 xmlns="http://new.com">
<unknownElement2>someValue</unknownElement2>
</unknownElement1>
</properties>
</p:rootElement>
NOTE that we can place arbitrary XML content inside the "properties" element.
If we transform the XSD to an Ecore metamodel using the XSD to Ecore Importer we get the following metamodel:
NOTE that the "any" property inside the EClass "Properties" is of type "EFeatureMapEntry" (i.e., org.eclipse.emf.ecore.util.FeatureMap$Entry, to be specific).
If this Ecore metamodel is used to build Xtext grammar, the following grammar comes out of the "Xtext Project from existing Ecore Models" wizard (using the "RootElementType" as entry rule):
// automatically generated by Xtext
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
import "http://example.com/example-with-anyfeature"
import "http://www.eclipse.org/emf/2003/XMLType" as type
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
RootElementType returns RootElementType:
'RootElementType'
'{'
('properties' properties=Properties)?
'}';
Properties returns Properties:
{Properties}
'Properties'
;
NOTE that the "Properties" grammar rule contains no corresponding construct to store values for the EFeatureMapEntry.
When using the above serialization mechanism the above XML causes a "FeatureNotFoundException: Feature 'unknownElement1' not found".
Here the question arises what are the options that allow representing the content depicted in the above XML file and to allow roundtrip instance transformations (i.e., from XML to Xtext model and vice-versa) that keep such arbitrary XML content in place.
Attached you find the projects containing the above files.
Cheers, Patrick