XML用ライブラリ,XML::ParserとMS XML Parser2.0を使ってみる

XMLパーサーをPerl,VisualBasicから使う

 あれから,XMLについて勉強を進めてみました.

Unicode

まず,日本語の文字化けの件について. これは,Microsoft XMLパーサの仕様ということになりますが, 日本語については,Unicode形式で取り扱うことになるようです. つまり,この内容をメモ帳に貼り付けて,
<?xml version="1.0"?>

<albums>
<album>
<band>AION</band>
<title>Aionism</title>
<comment></comment>
</album>
<album>
<band>ALCATRAZZ</band>
<title>Alcatrazz</title>
<comment>Yngwieのギターが速いぞ</comment>
</album>
<album>
<band>AMORPHIS</band>
<title>Elegy</title>
<comment></comment>
</album>
</albums>

メモ帳で「ファイルを名前を付けて保存」 とし,「Unicodeで保存する」にチェックを入れて保存します. (WindowsNTではできますが,Win95, 98でできるかどうかはわかりません)

メモ帳保存画面

これで,Internet Explorer 5.0で日本語が正しく表示されるようになります.

ブラウザ表示画面

また,XMLファイル内で明示的にエンコーディングを指定するには,先頭行を下記のように記述すればOKです.

<?xml version="1.0" encoding="UTF-16"?>

で,Microsoft XMLパーサ以外を使った場合にどうなるかですが, とりあえず環境が手に入ったということで, Perl for Win32の XML::Parser モジュールを使ってみました. すると,これも同じで,Unicodeで用意しておく必要がありました.
例えばTreeスタイルを使う場合,こんな感じで初期化します.

$p = new XML::Parser(
    ErrorContext => 2,
    Style => 'Tree',
    ProtocolEncoding => 'UTF-16'); 

補足
この件について,Itou-T15さんから指摘があり,また日経ソフトウェアの記事にもあったのですが, Microsoft XMLパーサでは,encoding="Shift_JIS" が使用することで, Shift JISコードの漢字を扱えるようです.失礼いたしました.


XML::Parser

XML::Parser とは,PerlでXMLファイルを扱うための汎用ライブラリです.

今回,XML::Parserを使ってPerl for Win32で苦心惨憺で作ったアルバム情報抽出プログラムを,載せてみます. 全然Perlらしくないプログラムだとは思いますが,お目こぼしあれ.

use XML::Parser;

$html2 = <<EOF;
<albums>
<album>
<band>AION</band>
<title>Aionism</title>
<comment></comment>
</album>
<album>
<band>ALCATRAZZ</band>
<title>Alcatrazz</title>
<comment>Yngwie</comment>
</album>
<album>
<band>AMORPHIS</band>
<title>Elegy</title>
<comment></comment>
</album>
</albums>
EOF


$p = new XML::Parser(
  ErrorContext => 2,
  Style => 'Tree',
  ProtocolEncoding => 'UTF-16');

$html2 =~ s/\n//g;
$r_tree = $p->parse($html2);

@albums = getAlbums( $r_tree);

open(OUTFILE, '>b.txt');

print OUTFILE $albums[2]{comment};

close(OUTFILE);


sub getAlbums
{
  my ($r_parsedTree) = @_;
  my ($albumNo, $elmNo, $r_albumCont);
  my (@rslt);
  my (%rsltWork);

  $albumNo = 1;
  while ( defined( $r_parsedTree->[1][$albumNo*2-1])) {

    if ( $r_parsedTree->[1][$albumNo*2-1] eq 'album') {

      $r_albumCont = $r_parsedTree->[1][$albumNo*2];
      $elmNo = 1;

      while ( defined( $r_albumCont->[($elmNo-1)*2+1]) )
      {
        $elmName = $r_albumCont->[($elmNo-1)*2+1];
        if ( defined( $r_albumCont->[($elmNo-1)*2+2][2]) ) {
          $rsltWork{$elmName} =
            $r_albumCont->[($elmNo-1)*2+2][2];
        }
        $elmNo++;
      }
      $rslt[$albumNo] = { %rsltWork}; # 無名ハッシュ化
      $albumNo++;
    }
  }
  return (@rslt);
}

XML文書中の改行の考え方で苦労しました.結局このプログラムでは, parseをかける前に改行を除去しています.なんか根本的に考えかたがおかしいのだろうか.

関数 getAlbums はハッシュの配列を返します.例えば1つめのアルバムの,commentは,

@albums = getAlbums( $r_tree);
print $albums[0]{comment};
で出力することができますので,関数インタフェイスとしてはまずまずだと思うのですが, 内部でやっている処理は,かなり汚いです.

種をあかすと,Treeスタイルでparseすることによって取得できる木構造を, こんな感じで図解して,配列の添え字を考えています.

[albums, [{}, album, [{}, band, [{}, 0, AION],
                          title, [{}, 0, Aionism],
                          comment, [{} ]
                     ]
              album, [{}, band, [{}, 0, ALCATRAZZ],
                          title, [{}, 0, Alcatrazz],
                          comment, [{}, 0, Yngwie]
                     ]
         ]
]
で,これが改行を除去しないままで処理すると,こんな感じになるのです.
[albums, [{}, 0, \n, album, [{}, 0, \n, band, [{}, 0, AION],
                                 0, \n, title, [{}, 0, Aionism],
                                 0, \n, comment, [{} ]
                            ]
              0, \n, album, [{}, 0, \n, band, [{}, 0, ALCATRAZZ],
                                 0, \n, title, [{}, 0, Alcatrazz],
                                 0, \n, comment, [{}, 0, Yngwie]
                            ]
         ]
]
\nというデータが,有効なデータとして取得されているのが邪魔だと言うわけです.

まあとにかく,Perlで木構造を扱うのは私には難しい... 慣れれば良いのでしょうけどねえ


Microsoft XML Parser

他にフリーで利用できるXMLパーサとして,Microsoft XML Parserがあります. ちなみに,Microsoft XML Parser 2.0は,
http://msdn.microsoft.com/downloads/tools/xmlparser/xmlparser.asp

から xmlredist.exe としてダウンロード可能です.

ただし,インストールする環境には Internet Explorer 4.01SP1以上が必要です. いわゆるCOMサーバですので,NewなりCreateObject()なり行って使うことになります.

補足
これまたItou-T15さんから指摘がありましたが,IE5.0環境では, Microsoft XML Parser 2.0は既に組み込まれています.従って, このモジュールを適用する必要はありません.説明不足ですみませんでした.

これを使った場合,Visual Basicに慣れている人なら, かなり簡単にXMLファイルの木構造を操作することができます. コレクション操作になるわけです. Visual Basicを起動して,「Microsoft XML Parser 2.0」を参照設定すると, 下図のようなオブジェクトが使えるようになります.

オブジェクトブラウザ画面

VBの場合,Unicodeが簡単に扱えるのも強みかなあ...

VB6+MSXMLParser2.0で同じようなプログラムを書いてみました.

Private Sub txtShow_Click()
  Dim xd As MSXML.DOMDocument
  Dim xdnAlbum As MSXML.IXMLDOMNode
  Dim blnSuccess As Boolean
  Dim lngAlbumNo As Long
  Dim colWork As Collection

  Set xd = CreateObject("Microsoft.XMLDOM")

  blnSuccess = xd.Load("F:\kamoi\work\XML\album.xml")

  If Not blnSuccess Then
    MsgBox "Can't load xml"
    Exit Sub
  End If

  lngAlbumNo = 1

  ' レコード抽出
  Set xdnAlbum = xd.childNodes(1).childNodes(lngAlbumNo - 1)

  ' レコード構成要素抽出
  Set colWork = getNodeTextCollection(xdnAlbum)

  With Me
    .txtBand.Text = colWork("band")
    .txtTitle.Text = colWork("title")
    .txtContents.Text = colWork("comment")
  End With

  Set colWork = Nothing
End Sub

Private Function getNodeTextCollection( _
  ByRef rxdnPar As MSXML.IXMLDOMNode) As Collection

  Dim xdnWork As MSXML.IXMLDOMNode
  Dim colRslt As New Collection
  Dim strNodeName As String
  Dim vntNodeText As Variant

  For Each xdnWork In rxdnPar.childNodes
    strNodeName = xdnWork.nodeName
    vntNodeText = xdnWork.Text
    colRslt.Add vntNodeText, strNodeName
  Next xdnWork

  Set getNodeTextCollection = colRslt

End Function
kamolandをフォローしましょう


© 2021 KMIソフトウェア