EMFモデルインスタンスの直列化方法をカスタマイズする

XMLスキーマからEMFモデルを生成した場合、そのEMFモデルのインスタンスを直列化すると、そのXMLスキーマに従ったXMLファイルとして保存されます。一方、EMFモデルをEcoreエディタ等を用いてスクラッチから作成した場合、例えばクラスの属性はXML要素の属性として直列化されます。しかし、属性の内容によっては、XML要素として直列化させたい場合があります。

例として、以下のようなCompositeパターンに従ったシンプルなファイルシステムモデルfs.ecoreを考えます。

Fileクラスの属性"contents"はString型として定義され、テキストファイルの内容をモデル化しているものとします。この.ecoreファイルから.genmodelを生成し、Modelコード、Editコード、Editorコードを生成します。ただし、テキストファイルは一般に複数行の文章を含むはずですから、以下のように、.genmodelにおいて、属性"contents"に対応する"Property Multi-line"をtrueに設定します。これにより、生成したモデルEditorのプロパティビューで、属性"contents"を編集する際、複数行編集可能(改行を入力可能)なダイアログが表示されるようになります。

以下が生成したモデルEditorを用いて属性"contents"を編集している様子です。

ここで、生成したモデルEditorを用いて編集したMy.fsの内容をテキストエディタで見ると以下のようになるはずです。

<?xml version="1.0" encoding="UTF-8"?>
<fs:FileSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fs="http://www.example.org/fs">
  <root name="root">
    <children xsi:type="fs:Directory" name="home">
      <children xsi:type="fs:Directory" name="kojihashi">
        <children xsi:type="fs:File" name="message.txt" contents="Hello, Eclipse!&#xD;Hello, EMF!"/>
      </children>
    </children>
  </root>
</fs:FileSystem>

上記のように、Fileクラスの属性"contents"がXML要素の属性として直列化されています。このファイルを常に生成したモデルEditorで閲覧する分には問題ありませんが、時にはこのようにテキストエディタ等で生の情報が見る必要があるかもしれません。その際に、複数行にわたる文字列は、XML要素として直列化したいところです。

そこで、以下のようにXSDプラグインを用いてEAnnotationをEMFモデルに追加することにより、直列化方式をカスタマイズ可能です。

まず、fs.ecoreに含まれるEPackageに対し、以下のようにEAnnotationを追加します。

<ecore:EPackage xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="fs"
    nsURI="http://www.example.org/fs" nsPrefix="fs">
  <eAnnotations source="http:///org/eclipse/emf/mapping/xsd2ecore/XSD2Ecore">
    <details key="representation" value="schema"/>
    <details key="targetNamespace" value="http://www.example.org/fs"/>
  </eAnnotations>
  ...

次に、XML要素として直列化したいFileクラスの属性"contents"に対し、以下のようにEAnnotationを追加します。

<eClassifiers xsi:type="ecore:EClass" name="File" eSuperTypes="#//Element">
  <eStructuralFeatures xsi:type="ecore:EAttribute" name="contents" lowerBound="1"
      eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
    <eAnnotations source="http:///org/eclipse/emf/mapping/xsd2ecore/XSD2Ecore">
      <details key="representation" value="element"/>
      <details key="targetNamespace"/>
    </eAnnotations>
  </eStructuralFeatures>
</eClassifiers>

.ecoreエディタで編集すると以下のようになります。

次に、.genmodelにおいて修正した.ecoreモデルをリロードします。そして、.genmodelにおけるEPackageの属性"Resource Type"を"None"から"XML"に変更します。

最後に、再度Modelコード、Editコード、Editorコードを生成します。ここで注意したいのは、EMFモデルから各種コードを再生成する場合、MANIFEST.MFやplugin.xmlは再生成されません。今回のカスタマイズを有効にする場合、Required Plug-insにorg.eclipse.emf.ecore.xmiを追加する必要があります。手動で追加するか、一度MANIFEST.MFを削除すると良いでしょう。

再生成したモデルEditorを用いて再度モデルインスタンスを編集してみると、一見全く変わりませんが、保存したモデルインスタンスのファイルをテキストエディタで開くと、属性"contents"がXML要素として直列化されているのがわかります。

<?xml version="1.0" encoding="UTF-8"?>
<fs:FileSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fs="http://www.example.org/fs">
  <root name="root">
    <children xsi:type="fs:Directory" name="home">
      <children xsi:type="fs:Directory" name="kojihashi">
        <children xsi:type="fs:File" name="message.txt">
          <contents>Hello, Eclipse!&#xD;Hello, EMF!</contents>
        </children>
      </children>
    </children>
  </root>
</fs:FileSystem>

上記のように、生成したモデルEditorで複数行にわたる属性を編集し保存すると、改行コードが"$#xD;"という風に直列化されます。しかし、テキストエディタでその部分を以下のように改行しても、そのファイルを生成したモデルEditorで開くことができます。

<?xml version="1.0" encoding="UTF-8"?>
<fs:FileSystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fs="http://www.example.org/fs">
  <root name="root">
    <children xsi:type="fs:Directory" name="home">
      <children xsi:type="fs:Directory" name="kojihashi">
        <children xsi:type="fs:File" name="message.txt">
          <contents>Hello, Eclipse!
Hello, EMF!</contents>
        </children>
      </children>
    </children>
  </root>
</fs:FileSystem>