The XSD Adapter allows oAW to read/write XML files as models and to use XML Schemas (XSDs) as meta models. This reference provides in-depth details, for a quick and pragmatic introduction see XSD Tutorial .
The XSD Adapter performs two major tasks:
It converts XML Schemas (XSDs) to Ecore models in a transparent manner, so that the Ecore models are hidden from the user. This is done in the workflow as well as in the IDE (to allow XSD-aware code completion for Xtend/Xpand/Check). For details about the mapping see the section called “Behind the scenes: Transforming XSD to Ecore” . For details about the workflow integration see the section called “Workflow Components”
It extends the EmfMetaModel with concepts that are needed for XSDs. Theses are, for example, support for feature maps (needed to handle comments, nested text, CDATA and processing instructions), QNames, EMaps and composed Simpletypes.
The XSDMetaModel loads
the specified XSD, transforms them to Ecore
models and makes them available for the other oAW components. If XSDs
include/import other XSDs or if XML files reference XSDs via
schemaLocation, theses XSDs are also loaded
(details: the section called “How to declare XML Schemas” ). The most
common scenario is to declare the XSDMetaModel
within an XMLReader
:
<component class="org.openarchitectureware.xsd.XMLReader"> <modelSlot value="model" /> <uri value="model.xml" /> <metaModel id="mm" class="org.openarchitectureware.xsd.XSDMetaModel"> <schemaFile value="metamodel.xsd" /> <registerPackagesGlobally value="true" /> </metaModel> </component>
Another option is to specify an
XSDMetaModel
independently of other components as
a bean:
<bean id="mymetamodel" class="org.openarchitectureware.xsd.XSDMetaModel"> <schemaFile value="metamodel.xsd" /> </bean> <component class="org.openarchitectureware.xsd.XMLReader"> <modelSlot value="model" /> <uri value="model.xml" /> <metaModel idRef="mymetamodel" /> </component>
Attention: It can lead to errors when XSDs are loaded multiple
times, which can only happen when using multiple
XSDMetaModels
within one workflow. The safe way
to go is to declare just one XSDMetaModel
per
workflow and reference it from all components that need it.
Properties:
schemaFile: optional, allowed multiple times: Specifies an XSD file which is being loaded. The path can be a complete URI, or relative to the project root or classpath.
registerPackagesGlobally: optional,
default "false": If true,
generated EPackages are registered to
org.eclipse.emf.ecore.EPackage.Registry.INSTANCE
,
EMF's global package registry. Warning: when running workflows from
your own java code, make sure to remove the generated packages from
the registry before the next run!
The XMLReader
reads one XML file which is
valid according to the XSDs loaded by the
XSDMetaModel
. The XML file is loaded as a model
and stored in the specified slot. Example:
<component class="org.openarchitectureware.xsd.XMLReader"> <modelSlot value="model" /> <uri value="model.xml" /> <metaModel idRef="mymetamodel" /> </component>
Properties:
slot: required: The name of the slot which in which the loaded model is stored. Other workflow components can access the model via referring to this slot.
uri: required: The file name of the XML file which should be read. Absolute URIs, and pathnames relative to the project root or to the classpath are valid.
metaModel: optional: Specifies the
XSDMetaModel
(see the section called “
XSDMetaModel
”) for the
XMLReader
. In case no
XSDMetaModel
is specified, an
XSDMetaModel
with default configuration is
instantiated implicitly. It is important to pay attention that all
needed XSDs can be found while the loading process: the section called “How to declare XML Schemas”.
useDocumentRoot: optional, default
"false": Dealing with XML files as models, most
people think of the XML's root element as the model's root object.
This is the default used by the XMLReader
.
But the XML's root element actually has a parent, the so-called
DocumentRoot. Additionally the DocumentRoot contains
comments/processing instructions and CDATA section which appears
before or after the XML's root element, and, most notably, the
DocumentRoot contains information about the used namespaces. If
useDocumentRoot is set to
true, the XMLReader
stores the DocumentRoot-Object instead the XML's root element's
object to the specified slot.
option: optional, can be specified
multiple times: Option specifies a key-value-pair, which is handed
on to the EMF's XMLResource in the loading process. Valid options
are documented via JavaDoc in interface
org.eclipse.emf.ecore.xmi.XMLResource
. Additionally, the XMLReader
supports these options:
DEFAULT_NAMESPACE: Specifies a default namespace, in case the XML file does not declare one:
<option key="DEFAULT_NAMESPACE" val="http://www.dlese.org/Metadata/opml" />
NAMESPACE_MAP: Specifies a mapping for namespaces, which is applied when loading XML files.
<option key="NAMESPACE_MAP"> <val class="org.openarchitectureware.xsd.lib.MapBean"> <mapping from="http://www.openarchitectureware.org/example/model/wrong" to="http://www.openarchitectureware.org/example/model/loadcurve" /> </val> </option>
The XMLWriter
writes the model stored in a
slot to an XML file. If the slot contains a collection of models, each
one is written to a separate file. The model(s) must have been
instantiated using an XSD-based meta model. Example:
<component class="org.openarchitectureware.xsd.XMLWriter"> <metaModel idRef="svgmm" /> <modelSlot value="svgmodel" /> <uri value="src-gen/mycurve.svg" /> </component>
Properties:
slot: required: The name of the slot which holds the model or the collection of models which shall be serialized to XML.
metaModel: required: The instance of
XSDMetaModel
, which holds the XSD that the
supplied models are based on. Also see the section called “
XSDMetaModel
”
uri: required if no uriExpression is specified: The file name of the XML file which should be written. Absolute URIs are valid. Use relative path names on your own risk.
uriExpression: required if no
uri is specified: In the scenario where
multiple XML files are written, this provides a mechanism to
determine the file name for each of them. The oAW-expression
specified in expression
is evaluated for each
file and has to return a file name. The model that is going to be
written is accessible in the expression via a variable that has the
name specified in varName
. Example:
<uriExpression varName="docroot" expression="'src-gen/'+ecore2xsd::getFileName(docroot)" />
option: optional, can be specified
multiple times: Option specifies a key-value-pair, which is handed
on to the EMF's XMLResource in the writing process. Valid options
are documented via JavaDoc in interface
org.eclipse.emf.ecore.xmi.XMLResource
.
The XMLBeautifier
uses EMF to load the XML
file, formats the mixed content (elements and text contained by the same
element) and writes the file back to disk applying a nice indentation
for the elements. The XMLBeautifier
is not
intended to be used in combination with the
XMLWriter
, since the
XMLWriter
cares about indentation by itself.
Instead, use it for "manually" constructed XML files using Xpand. Since
the frameworks for loading/storing XML always load the whole file into a
complex data structure in memory, this approach does not scale well for
huge XML files. Example:
<component class="org.openarchitectureware.xpand2.Generator"> <metaModel idRef="mm" /> <expand value="${src-pkg}::${file}::Root FOR '${out}'" /> <outlet path="${src-gen-dir}" /> <beautifier class="org.openarchitectureware.xsd.XMLBeautifier"> <maxLineWidth value="60" /> <formatComments value="true" /> <fileExtensions value=".xml, .html" /> </beautifier> </component>
Properties:
maxLineWidth: optional: Specifies the number of character after which a linewrap should be performed.
formatComments: optional, default true: Specifies if formatting should also be applied to comments.
fileExtensions: optional, default ".xml, .xsl, .xsd, .wsdd, .wsdl": Specifies a filter for which files formatting should be applied. Only files that match one of the specified file extensions are processed.
loadOption: optional, can be specified
multiple times: Option specifies a key-value-pair, which is handed
on to the EMF's XMLResource in the loading process. Valid options
are documented via JavaDoc in interface
org.eclipse.emf.ecore.xmi.XMLResource
.
saveOption: optional, can be specified multiple times: Same as loadOption, except for the difference that these options are applied while the writing process. Example:
<saveOption key="XML_VERSION" val="1.1" /> <saveOption key="ENCODING" val="ASCII" />
In the code generation process an XML Schema is transformed to an
EMF Ecore model, which is then used as a meta model by EMF. XSD complex
data types are mapped to EClasses, XSD simple data types are mapped to EMF
data types defined in
org.eclipse.emf.ecore.xml.type.XMLTypePackage
and
org.openarchitectureware.xsd.XSDMetaModel
maps them to oAW
data types. The document XML
Schema to Ecore Mapping explains the mapping's details.
http://www.eclipse.org/modeling/emf/docs/overviews/XMLSchemaToEcoreMapping.pdf
There are three different ways to declare your XSDs. It does not matter which way you choose, or how you combine them, as long as the XSD Adapter can find all needed schemas.
Within the Workflow:
org.openarchitectureware.xsd.XSDMetaModel
can have any
amount of schemaFile
elements.
<component class="org.openarchitectureware.xsd.XMLReader"> <modelSlot value="model" /> <uri value="${file}" /> <metaModel id="mm" class="org.openarchitectureware.xsd.XSDMetaModel"> <schemaFile value="model/loadcurve.xsd" /> <schemaFile value="model/device.xsd" /> </metaModel> </component>
Within the XML file: XML files can contain
schemaLocation
attributes which associate the
schema's namespace with the schema's filename. If the schema is
created using WTP like described in the section called “Step 3: Create a Model using XML” , the
schemaLocation
attribute is created
automatically.
<?xml version="1.0" encoding="UTF-8"?> <device:Device xmlns:device="http://www.openarchitectureware.org/example/model/device" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchitectureware.org/example/model/device device.xsd"> <device:Name>MyLaptop</device:Name> </device:Device>
Within an XSD: If one schema imports another, the
import
element can have a
schemaLocation
attribute, too.
<?xml version="1.0" encoding="UTF-8"?> <schema targetNamespace="http://www.openarchitectureware.org/example/model/device" elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.openarchitectureware.org/example/model/device" xmlns:lc="http://www.openarchitectureware.org/example/model/loadcurve" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"> <import namespace="http://www.openarchitectureware.org/example/model/loadcurve" schemaLocation="loadcurve.xsd"> </import> <complexType name="Device"> <sequence> <element name="Name" type="string" /> <element name="LoadCurve" type="lc:LoadCurve" /> </sequence> </complexType> <element name="Device" type="tns:Device"></element> </schema>