XSD Adapter

Prerequisites
Overview
Workflow Components
Behind the scenes: Transforming XSD to Ecore
How to declare XML Schemas

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 .

Prerequisites

Please take a look at the section called “Setup” .

Overview

The XSD Adapter performs two major tasks:

  1. 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”

  2. 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.

Workflow Components

The XSD Adapter provides the following workflow components:

XSDMetaModel

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!

XMLReader

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>

XMLWriter

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 .

XMLBeautifier

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" />

Behind the scenes: Transforming XSD to Ecore

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

How to declare XML Schemas

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.

  1. 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>
  2. 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>
  3. 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>