Wagby ではデータの移行前と移行後でモデル項目定義が変更された場合に、これを吸収できる仕組みを提供しています。ここではその方法を説明します。

Wagbyによるインポート処理では、1件の処理毎に、XSLTと呼ばれる変換処理を通ります。 この変換ファイルは directory 要素の importxslfilename 属性で指定されています。標準では次の処理に対応しています。

  • 必須項目に値がセットされていない場合に、代わりの値を設定する。

ただし、次のような変更については手動で対応する必要があります。

  • 項目の型が変更された場合
  • 項目名(英語)が変更された場合
  • 主キーや一意項目を追加した場合

通常、このような変更が発生したデータの移行は手間がかかります。しかし Wagby ではインポートに対する個別のルールを XSLT という形で指定できるため、多くの処理を(ルールを追加記述することによって)自動化することができます。すべてのデータを変更しようとする前に、XSLTによるルール記述ができないかどうかを検討してください。

XSLTの書式についての説明は本ガイドの範囲を超えるので割愛します。ここでは、具体的な例を用いて説明します。

このページで紹介する XSLT を用いず、他の開発言語を用いて直接、XML データを変更することもできます。

項目の型を「文字列」から「数値」に変更した場合などです。 このとき、項目の値に数値でない文字列があると読み込みエラーとなりますので、このようなデータを無視する、または変換するための処理をXSLT内に記述します。

例:項目 age を文字列から数値型に変更したため、数値以外のデータを無視するように設定する

オリジナルの内容:

<xsl:template match="age">
  <age>
    <xsl:value-of select="."/>
  </age>
</xsl:template>

修正後の内容:

<xsl:template match="age">
  <age>
    <xsl:if test="number(.) >= 0">
      <xsl:value-of select="."/>
    </xsl:if>
  </age>
</xsl:template>

例:項目 job を文字列からモデル参照に変更したため、元の文字列をコード値に変換する。

オリジナルの内容:

<xsl:template match="job">
  <job>
    <xsl:value-of select="."/>
  </job>
</xsl:template>

修正後の内容:

<xsl:template match="job">
  <job>
    <xsl:choose>
      <xsl:when test="text() = '学生'">
        <xsl:text>1</xsl:text>
      </xsl:when>
      <xsl:when test="text() = '会社員'">
        <xsl:text>2</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>-1</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </job>
</xsl:template>

例:項目 publishdate の表記内容について「yyyy/MM/dd」を「yyyy-MM-dd」に変換したい。

オリジナルの内容:

<xsl:template match="publishdate">
  <publishdate>
    <xsl:value-of select="."/>
  </publishdate>
</xsl:template>

修正後の内容:

<xsl:template match="publishdate">
  <publishdate>
    <xsl:choose>
      <xsl:when test='contains(text(),"/")'>
        <xsl:value-of
          select='substring-before(text(),"/")'/>
            -<xsl:value-of
              select='substring-before(substring-after(
                text(),"/"),"/")'/>
                  -<xsl:value-of select='substring-after(
                    substring-after(text(),"/"),"/")'/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select='text()'/>
      </xsl:otherwise>
    </xsl:choose>
  </publishdate>
</xsl:element>

項目名(英語)が「name」から「customername」に変更された場合など。自動生成された変換用 XSL では、このような意味的な変換は解釈できないため、手動で(変換用 XSL ファイルを)修正し、正しい項目にマッピングします。

例:項目名を「name」から「customername」に変更する。

オリジナルの内容:

<xsl:template match="name">
  <name>
    <xsl:value-of select="."/>
  </name>
</xsl:template>

修正後の内容:

<xsl:template match="name">
  <customername>
    <xsl:value-of select="."/>
  </customername>
</xsl:template>

追加した主キーや一意項目の値が重複しないように配慮する必要があります。 ただしこのケースでは XSL による変換ではなく、対象データを直接、変更する方がよいかも知れません。

最初の設計を「担当者1」「担当者2」と定義していたが、これを「担当者」(繰り返し項目)に統合する場合です。

元のモデルでエクスポートしたときの XML ファイルが次のようになっていたとします。

<customer>
<id>1000</id>
<name1>山田</name1>
<name2>佐藤</name2>
</customer>

これを、次のような XML に変換した上で、新モデル側にインポートさせます。

<customer>
<id>1000</id>
<name>山田</name>
<name>佐藤</name>
</customer>

変更した XSLT ファイルは次のようになります。

...(中略)...
<xsl:template match="/*">
  <customer>
    <xsl:choose>
    <xsl:when test="id">
      <xsl:apply-templates select="id[1]"/>
    </xsl:when>
    <xsl:otherwise>
      <id>-1</id>
    </xsl:otherwise>
    </xsl:choose>
    <xsl:apply-templates select="name"/>
    <xsl:apply-templates select="name1"/><!-- 追加 -->
    <xsl:apply-templates select="name2"/><!-- 追加 -->
  </customer>
</xsl:template>

<xsl:template match="id">
  <id>
    <xsl:value-of select="."/>
  </id>
</xsl:template>

<xsl:template match="name">
  <name>
    <xsl:value-of select="."/>
  </name>
</xsl:template>

<xsl:template match="name1"><!-- 追加 -->
  <name>
    <xsl:value-of select="."/>
  </name>
</xsl:template>

<xsl:template match="name2"><!-- 追加 -->
  <name>
    <xsl:value-of select="."/>
  </name>
</xsl:template>

最初の設計を「担当者1」「担当者2」と定義していたが、これを「担当者」(繰り返しコンテナ内の項目)に統合する場合です。

元のモデルの定義は次のようになっています。

項目名(日本語) 項目名(英語) 項目の型 主キー 繰り返し
ID address_id 整数
担当者1 con_member_id 文字列
担当者2 con_member_id2 文字列

このモデル定義でエクスポートしたときの XML ファイルが次のようになっていたとします。

<address>
<address_id>1000</address_id>
<con_member_id>田中</con_member_id>
<con_member_id2>鈴木</con_member_id2>
</address>

これを次のようなモデル定義に変換します。

項目名(日本語) 項目名(英語) 項目の型 主キー 繰り返し
ID address_id 整数
レポート report (繰り返し項目のコンテナ)
レポートID report/id1 (繰り返し項目コンテナ用のID)
担当者 report/syain 文字列
メモ report/memo 文字列
メモ report/date1 日付

具体的には、次に示す XML に変換した上で、新モデル側にインポートさせます。

<address>
<address_id>1000</address_id>
<report>
 <reportjshid>0</reportjshid>
 <id1>1</id1>
 <syain>田中</syain>
</report>
<report>
 <reportjshid>1</reportjshid>
 <id1>2</id1>
 <syain>鈴木</syain>
</report>
</address>

「reportjshid」という項目は、Wagby が内部で利用します。Wagby 定義ファイルには用意されていませんが、インポート時には必要となります。

変更した XSLT ファイルは次のようになります。

...(中略)...
<xsl:template match="/*">
  <address>
    <xsl:choose>
    <xsl:when test="address_id">
      <xsl:apply-templates select="address_id[1]"/>
    </xsl:when>
    <xsl:otherwise>
      <address_id>-1</address_id>
    </xsl:otherwise>
    </xsl:choose>

    <xsl:apply-templates
         select="report | con_member_id | con_member_id2"/>

  </address>
</xsl:template>

<xsl:template match="address_id">
  <address_id>
    <xsl:value-of select="."/>
  </address_id>
</xsl:template>

<xsl:template match="report">
  <report>
    <xsl:choose>
    <xsl:when test="/*/address_id">
      <xsl:apply-templates select="/*/address_id[1]"/>
    </xsl:when>
    <xsl:otherwise>
      <address_id>-1</address_id>
    </xsl:otherwise>
    </xsl:choose>

    <reportjshid>
        <xsl:value-of select="position()-1"/>
    </reportjshid>

    <xsl:apply-templates select="id[1]"/>

    <xsl:apply-templates select="syain[1]"/>

    <xsl:apply-templates select="memo[1]"/>

    <xsl:apply-templates select="date1[1]"/>

  </report>

</xsl:template>

<xsl:template match="report/id">
  <id>
    <xsl:value-of select="."/>
  </id>
</xsl:template>

<xsl:template match="report/syain">
  <syain>
    <xsl:value-of select="."/>
  </syain>
</xsl:template>

<xsl:template match="report/memo">
  <memo>
    <xsl:value-of select="."/>
  </memo>
</xsl:template>

<xsl:template match="report/date1">
  <date1>
    <xsl:value-of select="."/>
  </date1>
</xsl:template>

<xsl:template match="con_member_id | con_member_id2">
  <report>
    <xsl:choose>
    <xsl:when test="/*/address_id">
      <xsl:apply-templates select="/*/address_id[1]"/>
    </xsl:when>
    <xsl:otherwise>
      <address_id>-1</address_id>
    </xsl:otherwise>
    </xsl:choose>

    <reportjshid>
        <xsl:value-of select="position()-1"/>
    </reportjshid>

    <id1>
        <xsl:value-of select="position()"/>
    </id1>

    <syain>
        <xsl:value-of select="text()"/>
    </syain>
  </report>
</xsl:template>

クラシックカレンダビューのデータをモダンカレンダビューへ取り込む」で説明している移行ツールを使うと、クラシックカレンダー形式データを、モダンカレンダー形式で読み込めるようなXSLTファイルが用意されます。

ここで、モデル schedule を題材とします。次の項目を例に説明します。

利用項目 クラシック モダン
日付 sdate -
開始時刻 stime -
終了時刻 etime -
開始日時 - begindate (= sdate + stime)
終了日時 - enddate (= sdate + etime)

XSLTファイル

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"/>

<xsl:template match="/*">
  <schedule>
...
    <xsl:apply-templates select="sdate[1]"/> <!-- クラシック形式の日付項目 -->
...
  </schedule>
</xsl:template>

<xsl:template match="sdate"> <!-- クラシック形式の日付項目 -->
  <begindate> <!-- モダン形式の開始日時 -->
    <xsl:choose>
      <xsl:when test='contains(text(),"T")'>
        <xsl:value-of select='substring-before(text(),"T")'/>
        <xsl:text>T</xsl:text>
        <xsl:apply-templates select="/*/stime[1]"/> <!-- クラシック形式の開始時刻 -->
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select='text()'/>
      </xsl:otherwise>
    </xsl:choose>
  </begindate>

  <enddate> <!-- モダン形式の終了日時 -->
    <xsl:choose>
      <xsl:when test='contains(text(),"T")'>
        <xsl:value-of select='substring-before(text(),"T")'/>
        <xsl:text>T</xsl:text>
        <xsl:apply-templates select="/*/etime[1]"/> <!-- クラシック形式の終了時刻 -->
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select='text()'/>
      </xsl:otherwise>
    </xsl:choose>
  </enddate>
</xsl:template>

<xsl:template match="stime | etime">
  <xsl:choose>
    <xsl:when test='contains(text(),"T")'>
      <xsl:value-of select='substring-after(text(),"T")'/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select='text()'/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>
  • クラシック形式の「日付」+「開始時刻」項目から、モダン形式の「開始日時」項目を用意します。
  • クラシック形式の「日付」+「終了時刻」項目から、モダン形式の「終了日時」項目を用意します。
  • 日付は内部で"yyyy-MM-ddThh:mm:ss+09:00"となっているため、'T' という文字の前後で日付部と時間部を判断しています。