2つのXML文書を1つにしたい
2つのXML文書を1つにまとめたいのですが、どうすればよいでしょうか?

回答/富士ソフトABC株式会社 技術センター
2001/4/27

 2つのXML文書をどのように1つにまとめるか、単にファイルAのどこかにファイルBを挿入するのか、もしくはファイルBのそれぞれの要素をファイルAのある要素の子要素としてマージするのかによって、方法や難易度が異なります。

 ここでは、単にファイルAのどこかにファイルBを挿入する方法を2つ紹介します。1つ目は、挿入先のファイル、ここではファイルAに手を加える方法です。そして2つ目は、元のXMLファイルに手を加えずに、DOMを使って挿入する方法です。また、複数のファイルをマージするツールについても簡単に紹介します。

■挿入先に手を加えてマージする

 挿入先(ファイルA)に手を加える方法です。変更する箇所は、DTDの部分です。変更手順は次の通りです。

  1. ENTITY 宣言を使用してマージするファイルを外部ファイルとして定義。
      例) <!ENTITY insfile SYSTEM "merge_sample2.xml">

  2. 挿入したい個所に ENTITY 宣言で付けた名前を指定します。
      例) &insfile;

 このように変更すると、XMLパーサがこのXML文書をパースするときに、DTDで指定したファイルを展開し、実体参照として取り込みをしてくれます。

<?xml version="1.0" encoding="Shift_JIS"?>
<doc>
 <info>
  <no>0001</no>
  <title>XML サンプル - 1</title>
  <category>CD-ROM</category>
  <price>10</price>
  <quantity>100</quantity>
 </info>
 <info>
  <no>0002</no>
  <title>XML サンプル - 2</title>
  <category>DVD</category>
  <price>15</price>
  <quantity>60</quantity>
 </info>
</doc>

merge_sample1.xml:ファイルA(変更前)のサンプルファイル


<?xml version="1.0" encoding="Shift_JIS" ?>
<info>
 <no>0003</no>
 <title>XML サンプル - 3</title>
 <category>本</category>
 <price>5</price>
 <quantity>300</quantity>
</info>

merge_sample2.xml:ファイルBのサンプルファイル


<?xml version="1.0" encoding="Shift_JIS" ?>
<!DOCTYPE doc SYSTEM "merge_sample.dtd"
[
 <!ENTITY insfile SYSTEM "merge_sample2.xml">
]
>
<doc>
 <info>
  <no>0001</no>
  <title>XML サンプル - 1</title>
  <category>CD-ROM</category>
  <price>10</price>
  <quantity>100</quantity>
 </info>
 <info>
  <no>0002</no>
  <title>XML サンプル - 2</title>
  <category>DVD</category>
  <price>15</price>
  <quantity>60</quantity>
 </info>

 &insfile;

</doc>
merge_sample3.xml:ファイルA(変更後)のサンプルファイル

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="/">
  <html>
   <head>
    <title>サンプル表示(結合)</title>
   </head>
   <body>
    <p align="center">最新版 技術情報 [2つのファイルを結合]</p>
    <p align="center">----------------------------------</p>
   </body>
   <xsl:apply-templates select="doc" />
  </html>

 </xsl:template>

 <xsl:template match="doc">
  <table align="center" border="2" width="800">
   <tr>
    <th width="100" align="center">
     [番号]
    </th>
    <th width="200" align="center">
     [タイトル]
    </th>
    <th width="200" align="center">
     [カテゴリ]
    </th>
    <th width="100" align="center">
     [価格]
    </th>
    <th width="100" align="center">
     [数量]
    </th>
   </tr>
   <xsl:for-each select="info">
    <tr>
     <td width="100" align="center">
      <xsl:value-of select="no" />
     </td>
     <td width="200" align="center">
      <xsl:value-of select="title" />
     </td>
     <td width="200" align="center">
      <xsl:value-of select="category" />
     </td>
     <td width="100" align="center">
      <xsl:value-of select="price" />
     </td>
     <td width="100" align="center">
      <xsl:value-of select="quantity" />
     </td>
    </tr>
   </xsl:for-each>
  </table>
 </xsl:template>

</xsl:stylesheet>

merge_sample.xsl:表示用の変換ファイル

 この方法で2つのXML文書をマージすることは、XML の規約上では問題はありませんが、実行するパーサの実装においてどのような対応がなされているかによって結果は変化しました。実際、今回の検証はマイクロソフトのパーサ(MSXML3)と、サン・マイクロシステムズのパーサを使用したのですが、MSXML3では、2つのXML文書を同一マシン上においた場合と、取り込まれるXML文書をインターネット上において、URLで参照したときには正常に動作しましたが、ファイル共有機能を利用して、リモートドライブを経由した場合(e:\merge_sample3.xmlなど)は、うまく動作しませんでした。MSXML3は、リモートドライブを経由した動作を想定していないのかもしれません。

■ファイルに手を加えず文章を挿入する

 2つ目は、元のXMLファイルに手を加えずに挿入する方法です。ここでは DOM(Document Object Model)を使用した例を挙げます。

 処理手順は、以下のようになっています。サンプルでは1〜3の手順で確認のために、メッセージボックスでデータを表示しています。

  1. 挿入先のファイル(merge_sample1.xml)を読み込む
  2. 挿入元のファイル(merge_sample2.xml)を読み込む
  3. 挿入先のルートノードの子ノードとして追加する
  4. 表示用のXSL(T)ファイル(merge_sample.xsl)を読み込む
  5. XSL(T)を適用してブラウザに表示する

<html>
<head>
<title>XML文書を結合する</title>
</head>
<body>
DOM を使って2つの XML 文書を結合します。
<div id="reslst"></div>
<script language="JavaScript">
<!--
  // XML ドキュメントオブジェクトを作成
  var objDoc1 = new ActiveXObject("Microsoft.XMLDOM");
  objDoc1.async = false;
  // マージ先の XML ドキュメントファイルを読込み
  objDoc1.load("merge_sample1.xml");

  // 読込んだ XML データを確認のために表示
  window.alert(objDoc1.xml);

  // ルートノードのオブジェクトを作成
  var root1 = objDoc1.documentElement;

  // XML ドキュメントオブジェクトを作成
  var objDoc2 = new ActiveXObject("Microsoft.XMLDOM");
  objDoc2.async = false;
  // マージする XML ドキュメントファイルを読込み
  objDoc2.load("merge_sample2.xml");

  // 読込んだ XML データを確認のために表示
  window.alert(objDoc2.xml);

  // ルートノードのオブジェクトを作成
  var root2 = objDoc2.documentElement;

  // マージ先のデータの最後にマージするデータを追加
  root1.insertBefore(root2, null);

  // 追加した結果の XML データを確認のために表示
  window.alert(objDoc1.xml);

  // XML ドキュメントオブジェクトを作成
  var objXSLT = new ActiveXObject("Microsoft.XMLDOM");
  objXSLT.async = false;
  // 適応する XSL(T) ファイルを読込み
  objXSLT.load("merge_sample.xsl");

  // XSL(T) を適応してブラウザに表示
  reslst.innerHTML = objDoc1.transformNode(objXSLT);
//-->
</script>
</body>
</html>
merge_sample.html:DOM のサンプルファイル

<?xml version="1.0" encoding="Shift_JIS"?>
<doc>
 <info>
  <no>0001</no>
  <title>XML サンプル - 1</title>
  <category>CD-ROM</category>
  <price>10</price>
  <quantity>100</quantity>
 </info>
 <info>
  <no>0002</no>
  <title>XML サンプル - 2</title>
  <category>DVD</category>
  <price>15</price>
  <quantity>60</quantity>
 </info>
</doc>
merge_sample1.xml:ファイルAのサンプルファイル

<?xml version="1.0" encoding="Shift_JIS" ?>
<info>
 <no>0003</no>
 <title>XML サンプル - 3</title>
 <category>本</category>
 <price>5</price>
 <quantity>300</quantity>
</info>
merge_sample2.xml:ファイルBのサンプルファイル

<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="/">
  <html>
   <head>
    <title>サンプル表示(結合)</title>
   </head>
   <body>
    <p align="center">最新版 技術情報 [2つのファイルを結合]</p>
    <p align="center">----------------------------------</p>
   </body>
   <xsl:apply-templates select="doc" />
  </html>

 </xsl:template>

 <xsl:template match="doc">
  <table align="center" border="2" width="800">
   <tr>
    <th width="100" align="center">
     [番号]
    </th>
    <th width="200" align="center">
     [タイトル]
    </th>
    <th width="200" align="center">
     [カテゴリ]
    </th>
    <th width="100" align="center">
     [価格]
    </th>
    <th width="100" align="center">
     [数量]
    </th>
   </tr>
   <xsl:for-each select="info">
    <tr>
     <td width="100" align="center">
      <xsl:value-of select="no" />
     </td>
     <td width="200" align="center">
      <xsl:value-of select="title" />
     </td>
     <td width="200" align="center">
      <xsl:value-of select="category" />
     </td>
     <td width="100" align="center">
      <xsl:value-of select="price" />
     </td>
     <td width="100" align="center">
      <xsl:value-of select="quantity" />
     </td>
    </tr>
   </xsl:for-each>
  </table>
 </xsl:template>

</xsl:stylesheet>
merge_sample.xsl :表示用の変換ファイル

(XMLファイルは1つ目の方法と同じサンプルファイルを使用します)

 そのほかに、2つ以上のXMLドキュメントファイルをマージするツールとして川俣晶氏が公開する「Merge XML Files Version 0.1」があります。

 このツールはコマンドラインで実行するアプリケーションで、パラメータに複数の XML ファイル名を指定し、最後に指定されたファイル名を出力ファイルとして処理を行うものです。

例) axmlmerge in1.xml in2.xml in3.xml out.xml

 この例の場合、in1.xml 〜 in3.xmlをマージして out.xml に結果を出力します。下のファイルリストは、このツールのテストで使用したファイルです。ツールを実行するとマージ対象のデータはすべてarchive要素の子要素として1つにまとめられます。エンコーディングは UTF-16 となります。

> axmlmerge merge_sample4.xml merge_sample5.xml merge_out.xml

<?xml version="1.0" encoding="Shift_JIS"?>
<doc>
 <info>
  <no>0001</no>
  <title>XML サンプル - 1</title>
  <category>CD-ROM</category>
  <price>10</price>
  <quantity>100</quantity>
 </info>
 <info>
  <no>0002</no>
  <title>XML サンプル - 2</title>
  <category>DVD</category>
  <price>15</price>
  <quantity>60</quantity>
 </info>
</doc>
merge_sample4.xml:マージするサンプルファイル

<?xml version="1.0" encoding="Shift_JIS" ?>
<doc>
 <info>
  <no>0003</no>
  <title>XML サンプル - 3</title>
  <category>本</category>
  <price>5</price>
  <quantity>300</quantity>
 </info>
</doc>
merge_sample5.xml:マージするサンプルファイル

<?xml version="1.0" encoding="UTF-16"?>
<archive><doc>
  <info>
   <no>0001</no>
   <title>XML サンプル - 1</title>
   <category>CD-ROM</category>
   <price>10</price>
   <quantity>100</quantity>
  </info>
  <info>
   <no>0002</no>
   <title>XML サンプル - 2</title>
   <category>DVD</category>
   <price>15</price>
   <quantity>60</quantity>
  </info>
 </doc>
 <doc>
  <info>
   <no>0003</no>
   <title>XML サンプル - 3</title>
   <category>本</category>
   <price>5</price>
   <quantity>300</quantity>
  </info>
 </doc>
</archive>
merge_out.xml:マージ結果のファイル

 

「Ask XML Expert」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間