Wednesday, December 26, 2007

An EMF Editor for VoiceXML

The following entry provides a starting point for creating a basic EMF editor for VoiceXML. It is actually very straightforward and provides a good demonstration of the power of EMF for creating a basic, yet powerful editor (with cut-and-paste, drag-and-drop, syntax checking, etc.) for a language with an existing, well-defined schema. My goal here is not to provide a polished, finished editor, but a fully-functional starting point.

Download the VoiceXML Shemas from the W3C website


The VoiceXML schemas can all be downloaded from http://www.w3.org/TR/voicexml21
We will need the following 9 files:
  • vxml.xsd
  • vxml-attribs.xsd
  • vxml-datatypes.xsd
  • vxml-grammar-extension.xsd
  • vxml-grammar-restriction.xsd
  • vxml-synthesis-extension.xsd
  • vxml-synthesis-restriction.xsd
  • grammar-core.xsd
  • synthesis-core.xsd

From a unix shell, you can use the following command to retrieve these files:

wget http://www.w3.org/TR/voicexml21/vxml.xsd \
http://www.w3.org/TR/voicexml21/vxml-attribs.xsd \
http://www.w3.org/TR/voicexml21/vxml-datatypes.xsd \
http://www.w3.org/TR/voicexml21/vxml-grammar-extension.xsd \
http://www.w3.org/TR/voicexml21/vxml-grammar-restriction.xsd \
http://www.w3.org/TR/voicexml21/vxml-synthesis-extension.xsd \
http://www.w3.org/TR/voicexml21/vxml-synthesis-restriction.xsd \
http://www.w3.org/TR/voicexml21/grammar-core.xsd \
http://www.w3.org/TR/voicexml21/synthesis-core.xsd


Modify the VoiceXML Schemas


Unfortunately, the schemas cannot currently be converted directly into Ecore files, but the modifications you will need to make are minor.

In the vxml-attribs.xsd file, remove the import declaration for xml.xsd, or else we may see the following warning:
Warning | XSD: The location 'http://www.w3.org/2001/xml.xsd' has not been resolved | vxml-attribs.xsd | line 23
We can remove the declaration from the file in a shell with these commands:
  • perl -pi -e 's~<xsd:import namespace="http://www.w3.org/XML/1998/namespace"~~' vxml-attribs.xsd
  • perl -pi -e 's~schemaLocation="http://www.w3.org/2001/xml.xsd"/>~~' vxml-attribs.xsd

In the vxml-synthesis-extension.xsd, add an import declaration for vxml.xsd, or else we may see the following error:
Error | XSD: Model group reference 'http://www.w3.org/2001/vxml#executable.content is unresolved | vxml-synthesis-extension.xsd | line 93
We can add this declaration in a shell with this command:
  • perl -pi -e 's~<xsd:include schemaLocation="vxml-attribs.xsd"/>~<xsd:include schemaLocation="vxml-attribs.xsd"/>\n <xsd:include schemaLocation="vxml.xsd"/>~' vxml-synthesis-extension.xsd

Remove the redefinition of speak.attribs in vxml-synthesis-restriction.xsd and hard-code the restriction in synthesis-core.xsd, or else we may see the following error:
Error | XSD: The type of attribute '#version' must derive from '#version.datatype' | vxml-synthesis-restriction.xsd | line 34
We can hard-code this redefinition in a shell with these commands:
  • perl -pi -e 's~<xsd:attributeGroup name="speak.attribs">~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~<xsd:attribute name="version" type="version.datatype" fixed="1.0"/>~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~<xsd:attribute ref="xml:lang"/>~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~<xsd:attribute ref="xml:base"/>~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~</xsd:attributeGroup>~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~<xsd:attribute name="version" type="version.datatype"/>~<xsd:attribute name="version" type="version.datatype" fixed="1.0"/>~' synthesis-core.xsd

In the vxml-synthesis-restriction.xsd file, remove the import declaration for xml.xsd, or else we may see the following warning:
Warning | XSD: The location 'http://www.w3.org/2001/xml.xsd' has not been resolved | vxml-synthesis-restriction.xsd | line 21
We can remove the declaration from the file in a shell with these commands:
  • perl -pi -e 's~<xsd:import namespace="http://www.w3.org/XML/1998/namespace"~~' vxml-synthesis-restriction.xsd
  • perl -pi -e 's~schemaLocation="http://www.w3.org/2001/xml.xsd"/>~~' vxml-synthesis-restriction.xsd

Replace the xsd:union references in synthesis-core.xsd with the regex restrictions for the unioned datatypes, or else we may see the following when trying to create an EMF project from the schemas:
Error: XSD: The 'memberTypes' attribute must be present or tehre must be contained member types : URI null Line 155 Column 2
Error: XSD: The 'memberTypes' attribute must be present or tehre must be contained member types : URI null Line 159 Column 2
Error: XSD: The 'memberTypes' attribute must be present or tehre must be contained member types : URI null Line 163 Column 2
Error: XSD: The 'memberTypes' attribute must be present or tehre must be contained member types : URI null Line 167 Column 2
Error: XSD: The value '100.0' of attribute 'default' must be one of the members types of 'http://www.w3.org/2001/vxml#volume.datatype' : URI null Line 365 Column 4
We can replace the xsd:union references in synthesis-core.xsd in a unix shell with the following commands:
  • perl -pi -e 's~<xsd:union memberTypes="hertz.number hertz.relative percent semitone height.scale"/>~<xsd:restriction base="xsd:string">\n <xsd:pattern value="(([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)Hz)|([+\-]([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)Hz)|([+\-]?([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)%)|([+\-]([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)st)|(x-high|high|medium|low|x-low-default)" />\n </xsd:restriction>~' synthesis-core.xsd
  • perl -pi -e 's~<xsd:union memberTypes="number percent speed.scale"/>~<xsd:restriction base="xsd:string">\n <xsd:pattern value="([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)|([+\-]?([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)%)|(x-fast|fast|medium|slow|x-slow|default)" />\n </xsd:restriction>~' synthesis-core.xsd
  • perl -pi -e 's~<xsd:union memberTypes="volume.number relative percent volume.scale"/>~<xsd:restriction base="xsd:string">\n <xsd:pattern value="(0*(100.[0-9]*|[0-9][0-9].[0-9]*|[0-9].[0-9]*|.[0-9]+))|([+\-]([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+))|([+\-]?([0-9]+|[0-9]+.[0-9]*|[0-9]*.[0-9]+)%)|(silent|x-soft|soft|medium|loud|x-loud|default)" />\n </xsd:restriction>~' synthesis-core.xsd


Create an EMF Project From the VoiceXML Schemas


We will need to install 2 plugin-projects in order to generate the EMF model and editor from the VoiceXML schemas:
Eclipse Modelling Framework (EMF) SDK
XML Schema Infoset Model (XSD) Extender SDK

We can install these through the Europa Discovery Site by following this path of menu options:
Help -> Software Updates -> Find and Install... -> Search For New Features To Install -> Europa Discovery Site -> Models and Model Development -> EMF Extender SDK and XSD Extender SDK
EMF Extender SDK and XSD Extender SDK

Now, we are ready to create the EMF Project with a standard menu: File -> New -> Project... -> EMF Project.
We can call the project org.w3.vxml.
Create the EMF Project in the New Project Wizard

We will select the XML model importer from the New Project Wizard.
Select the XML model importer from the New Project Wizard

We can select the nine schemas listed above for generating the genmodel file, which we will call vxml.genmodel.
Select the nine schemas listed above for generating the genmodel file

We can select to generate the packages org.w3._2001.vxml and org.w3.xml._1998.namespace (since the vxml package depends on the xml package).
Generate org.w3._2001.vxml and org.w3.xml._1998.namespace


Modify the Generated Ecore and Genmodel


This step is open-ended, as modifications to the ecore and genmodel files will be as needed, depending on how our target audience will use the editor. Here are a few quick cosmetic changes:
  • In the ecore file, remove any Type suffixes from the model objects (e.g., change AssignType -> Assign, BlockType -> Block, etc.). Unfortunately, since there are both a Meta and MetaType and Metadata and MetadataType elements in the ecore file, these names cannot be changed. Also, if we try to change ObjectType to Object, we will get errors in the generated code.
  • In the ecore file, change Audio -> BaseAudio and Audio1 -> Audio since Audio1 and not Audio is the element that is primarily used. Do the same for Mark and Mark1, SayAs and SayAs1, VersionDatatype and VersionDatatype1, and MixedGrammar, MixedGrammar1 and MixedGrammar11.
  • In the genmodel file, change the Namespace Base Package from org.w3.xml._1998 to org.w3.xml. Likewise, change the VXML Base Package from org.w3._2001 to org.w3.vxml.


Generate the Model, Edit and Editor Code


From the root Vxml Node in the genmodel file, generate the Model code, then the Edit code and then the Editor code. Just like that, the Model Objects, the ItemProviders for displaying the Model in the UI and the multi-tab Editor code has all been generated. So let's try it out!
Generate the model, edit and editor code.

Start Coding VoiceXML


On the Overview page of the /org.w3.vxml.editor/META-INF/MANIFEST.MF form editor, in the Testing section, we will click on Launch an Eclipse application.
In the new Workbench, we will create a New General project and call it hello.world.vxml.
Now, from the New -> Other... wizard, we will create a new Vxml Model (Under Example EMF Creation Wizards) and call it HelloWorld.vxml.
Create a new Vxml Model.

We will select Vxml as the Model Object and Finish the Wizard.
Use Vxml as the Model Object.

In the Editor that is now opened, we can start writing Vxml!
Hello World Vxml in the generated editor.

We can view the emitted VoiceXML with the Text editor.
The emitted Hello World Vxml code.

2 comments:

Unknown said...

I just can say... Thank you!

Your tips completely resolved my problems importing the VXML schema.

Thank you a lot.

Tim Myer said...

It's great to hear that someone found the post useful.