調べもの:Excel VBAでSAXを使ってXMLデータ表示 [プログラミング学習]
なんとかできた。
きちんとした説明・修正はおいおいするとして。とりあえずメモ。
今回は、ほぼ以下のサイトのコードを流用させていただきました。ありがとうございました。
「Visual Basic を使用した SAX2 アプリケーション作成のジャンプスタート」
http://msdn.microsoft.com/ja-jp/library/ms994347.aspx
まず、仕様。
XMLファイルを読み込んで、要素、要素の値、属性、属性値をシートに表示する
表示は以下のような構成になる。
大きく要素名、要素の値、属性を表示するフィールドに分かれる。
要素名は階層構造で示す。要素の値と属性は要素名と同一行に表示する。
処理フローは以下の通り。
・ユーザがシートに設置されたボタンを押下する
-> [ファイルを開く]ダイアログが表示される
・ユーザがXMLファイルを選択する
複数選択可。XML形式以外のファイルを開いた場合のエラー処理はしない
-> XMLファイルの内容がExcelシートに表示される
ファイル構成は以下の通り。
ただし、コードを見るとわかるが、実は処理がモジュールでちゃんとわかれていない。
この辺は今後の課題。
・ボタン押下処理を実行するモジュール(Module1)
・SAXでの処理を実行するクラスモジュール(ContentHandlerImpl, ErrorHandlerImpl)
(※ErrorHandlerImplは実際には実装せず)
参照として、MS XML 6.0を追加
ソースコードは以下の通り。
Module1
ContentHandlerImpl
今回参考にしたサイト
ありがとうございました。
「Excel VBA 入門講座 セルのクリア」
http://excelvba.pc-users.net/fol2/2_6.html
「Excel VBA 入門講座 セルの挿入」
http://excelvba.pc-users.net/fol2/2_7.html
「Excel VBAではじめるクラス入門:CodeZine」
http://codezine.jp/article/detail/499?p=1
参考にしたサンプルがクラス作成前提だったので、今回はこちらを参照しました。
・・・作らなくてもいいとは思うんですが、その裏付けが取れませんでした。orz
作る必要ありますね。継承しないといけませんもの。orz
「セルについて」
http://abcclub.cside.ne.jp/vbahelp_help/dai6.htm
デバッグ用に出力セルに色をつけて、正しく動作するかを確認しました。
「Excel VBA を学ぶなら moug モーグ | 即効テクニック | セル範囲を参照する2(Cellsプロパティ)」
http://www.moug.net/tech/exvba/0050084.htm
「エクセルExcel大事典 VBAマクロ 文字列操作 Instr Strcomp Trim StrConv Chr Asc Format」
http://home.att.ne.jp/zeta/gen/excel/c04p40.htm
不要な改行・空白セル、タブを除くために文字コードで除外しました。
Schemaを使っていないため、ignoreableWhitespeceが使えませんでした。
「Asc 関数、AscW 関数」
http://msdn.microsoft.com/ja-jp/library/zew1e4wc(VS.80).aspx
http://www009.upp.so-net.ne.jp/Mishika/
今回は、ほぼ以下のサイトのコードを流用させていただきました。ありがとうございました。
「Visual Basic を使用した SAX2 アプリケーション作成のジャンプスタート」
http://msdn.microsoft.com/ja-jp/library/ms994347.aspx
まず、仕様。
XMLファイルを読み込んで、要素、要素の値、属性、属性値をシートに表示する
表示は以下のような構成になる。
大きく要素名、要素の値、属性を表示するフィールドに分かれる。
要素名は階層構造で示す。要素の値と属性は要素名と同一行に表示する。
処理フローは以下の通り。
・ユーザがシートに設置されたボタンを押下する
-> [ファイルを開く]ダイアログが表示される
・ユーザがXMLファイルを選択する
複数選択可。XML形式以外のファイルを開いた場合のエラー処理はしない
-> XMLファイルの内容がExcelシートに表示される
ファイル構成は以下の通り。
ただし、コードを見るとわかるが、実は処理がモジュールでちゃんとわかれていない。
この辺は今後の課題。
・ボタン押下処理を実行するモジュール(Module1)
・SAXでの処理を実行するクラスモジュール(ContentHandlerImpl, ErrorHandlerImpl)
(※ErrorHandlerImplは実際には実装せず)
参照として、MS XML 6.0を追加
ソースコードは以下の通り。
Module1
Option Explicit '共通変数宣言 '共通定数宣言 Const CNT_FILE_TYPE = "XMLファイル" '選択するファイルの説明 Const CNT_FILE_EXT = "*.xml" '選択するファイルの拡張子 '’*********************************** '' ' 概要:ファイルを開くダイアログを表示し、XMLデータの表示を行う ' Sub ボタン4_Click() ' *********************************** '変数宣言 ' *********************************** Dim selectFile As Variant Dim i As Integer Dim reader As SAXXMLReader 'Reads the XML document Dim contentHandler As New ContentHandlerImpl 'Receives parsing events Dim errorHandler As New ErrorHandlerImpl 'Receive error events ' *********************************** '初期化 ' *********************************** Set reader = New SAXXMLReader Set reader.contentHandler = contentHandler 'They work together Set reader.errorHandler = errorHandler 'They also work together ' Sheetのクリア ThisWorkbook.ActiveSheet.Cells.Clear ' *********************************** '処理 ' *********************************** 'Application.FileDialog 'msoFileDialogFilePicker:ファイル 'msofiledialogfolderpicker :フォルダ With Application.FileDialog(msoFileDialogFilePicker) 'ダイアログタイトル名 .Title = "ファイル選択" '開いた時に表示されるフォルダ .InitialFileName = ThisWorkbook.Path '複数ファイル選択の可否 True:可能、False:不可 .AllowMultiSelect = True 'ファイルの種類 .Filters.Add CNT_FILE_TYPE, CNT_FILE_EXT .Filters.Add "すべてのファイル", "*.*" '選択された場合 If .Show = -1 Then '選択されたアイテムでループ For Each selectFile In .SelectedItems reader.parseURL (selectFile) 'Parse the document Next End If End With ' シート内の列幅自動調整 ActiveSheet.Select Cells.Columns.AutoFit End Sub
ContentHandlerImpl
Option Explicit '’*********************************** '' ' ContentHandlerの実装 '’*********************************** Implements IVBSAXContentHandler '共通変数宣言 Public intCurrentCol As Integer ' 現在データ入力中の行 Const CNT_INITIAL_COL = 2 ' データ入力を開始する行 Const CNT_INITIAL_ROW = 2 ' データ入力を開始する列 Public intLastElementRow As Integer ' 要素入力の最終列を示す。この右隣の行がNodeValueの入力列。その右隣がAttributeの入力位置 Public intCurrentElementRow As Integer ' 現在データ入力中の要素の列。要素の階層に同じ '’*********************************** '' ' 概要:セル位置の初期化 ' '’*********************************** Private Sub Class_Initialize() intCurrentCol = CNT_INITIAL_COL intCurrentElementRow = CNT_INITIAL_ROW - 1 intLastElementRow = intCurrentElementRow End Sub '’*********************************** '' ' 概要:要素・属性の表示 ' '’*********************************** Private Sub IVBSAXContentHandler_startElement(strNamespaceURI As _ String, strLocalName As String, strQName As String, ByVal attributes As _ MSXML2.IVBSAXAttributes) ' *********************************** '変数宣言 ' *********************************** Dim i As Integer ' *********************************** '初期化 ' *********************************** intCurrentCol = intCurrentCol + 1 ' 行を1つ下に移動する intCurrentElementRow = intCurrentElementRow + 1 ' 列を1つ右に移動する ' *********************************** '処理 ' *********************************** ' 要素の表示列の最後尾より現在の列が右の場合 If intCurrentElementRow > intLastElementRow Then '列を挿入する intLastElementRow = intLastElementRow + 1 ActiveSheet.Range(Cells(intCurrentCol, intLastElementRow), Cells(intCurrentCol, intLastElementRow)).EntireColumn.Insert End If ' 要素の現在列に現在の要素名を格納する Cells(intCurrentCol, intCurrentElementRow).Value = strLocalName Cells(intCurrentCol, intCurrentElementRow).Font.Color = RGB(0, 255, 0) 'デバッグ用色分け:要素名 ' 属性表示列に現在の属性名と属性値を格納する For i = 0 To (attributes.Length - 1) Cells(intCurrentCol, intLastElementRow + 2 * i + 2).Value = attributes.getLocalName(i) Cells(intCurrentCol, intLastElementRow + 2 * i + 2).Font.Color = RGB(255, 0, 0) 'デバッグ用色分け:属性名 Cells(intCurrentCol, intLastElementRow + 2 * i + 2 + 1).Value = attributes.getValue(i) Cells(intCurrentCol, intLastElementRow + 2 * i + 2 + 1).Font.Color = RGB(255, 0, 0) 'デバッグ用色分け:属性値 Next End Sub '’*********************************** '' ' 概要:要素の終了 ' '’*********************************** Private Sub IVBSAXContentHandler_endElement(strNamespaceURI As String, _ strLocalName As String, strQName As String) ' 列を一つ左に移動する intCurrentElementRow = intCurrentElementRow - 1 End Sub '’*********************************** '' ' 概要:要素の値の表示 ' '’*********************************** Private Sub IVBSAXContentHandler_characters(text As String) ' 先頭文字の文字コードが制御文字・空白でない場合 If AscB(Left(text, 1)) > &H20 Then ' セルに値を表示する Cells(intCurrentCol, intLastElementRow + 1).Value = text Cells(intCurrentCol, intLastElementRow + 1).Font.Color = RGB(0, 0, 0) 'デバッグ用色分け:要素値 End If End Sub '’*********************************** '' ' (2009/10/24追加)以降、ContentHandlerのその他イベントハンドラの実装 ' 処理なし ' '’*********************************** Private Property Set IVBSAXContentHandler_documentLocator(ByVal RHS As _ MSXML2.IVBSAXLocator) End Property Private Sub IVBSAXContentHandler_endDocument() End Sub Private Sub IVBSAXContentHandler_endPrefixMapping(strPrefix As String) End Sub Private Sub IVBSAXContentHandler_ignorableWhitespace(strChars As String) End Sub Private Sub IVBSAXContentHandler_processingInstruction(target As String, _ data As String) End Sub Private Sub IVBSAXContentHandler_skippedEntity(strName As String) End Sub Private Sub IVBSAXContentHandler_startDocument() End Sub Private Sub IVBSAXContentHandler_startPrefixMapping(strPrefix As String, _ strURI As String) End Sub
今回参考にしたサイト
ありがとうございました。
「Excel VBA 入門講座 セルのクリア」
http://excelvba.pc-users.net/fol2/2_6.html
「Excel VBA 入門講座 セルの挿入」
http://excelvba.pc-users.net/fol2/2_7.html
「Excel VBAではじめるクラス入門:CodeZine」
http://codezine.jp/article/detail/499?p=1
参考にしたサンプルがクラス作成前提だったので、今回はこちらを参照しました。
作る必要ありますね。継承しないといけませんもの。orz
「セルについて」
http://abcclub.cside.ne.jp/vbahelp_help/dai6.htm
デバッグ用に出力セルに色をつけて、正しく動作するかを確認しました。
「Excel VBA を学ぶなら moug モーグ | 即効テクニック | セル範囲を参照する2(Cellsプロパティ)」
http://www.moug.net/tech/exvba/0050084.htm
「エクセルExcel大事典 VBAマクロ 文字列操作 Instr Strcomp Trim StrConv Chr Asc Format」
http://home.att.ne.jp/zeta/gen/excel/c04p40.htm
不要な改行・空白セル、タブを除くために文字コードで除外しました。
Schemaを使っていないため、ignoreableWhitespeceが使えませんでした。
「Asc 関数、AscW 関数」
http://msdn.microsoft.com/ja-jp/library/zew1e4wc(VS.80).aspx
http://www009.upp.so-net.ne.jp/Mishika/
使わせていただこうと思ったらこんなの出ます。
僕の環境だけでしょうか?
--------------------------------------------------------
コンパイル エラー:
オブジェクト モジュールにはインターフェイス 'documentLocator' 用の 'IVBSAXContentHandler' が必要です。
--------------------------------------------------------
documentLocatorって何・・・。
by Yoshi (2009-10-21 03:45)
〉Yoshiさん
コメントありがとうございます。
今携帯なので、詳細調べられないのですが、参照が上手くいってないように見えます。
追って調べさせていただきます。
by Mishika (2009-10-21 21:58)
>Yoshiさん
発生していた現象ですが、結論から言うと、原因は必要なコードが足りなかったためでした。
ContentHandlerImplはContentHandlerインタフェースを実装しているので、ContentHandlerのすべてのイベントハンドラを実装する必要があります。
実際に私が作成したExcelマクロのファイルでは、中身にコードが記載されていないイベントハンドラが定義されていました。
ただ、上の記事では、ContentHandlerのイベントハンドラのうち、処理をしていないイベントハンドラは記載しておりませんでした。
ContentHandlerImpのコードに、処理をしていないイベントハンドラも追加しましたので、ご参照いただければ幸いです。
最後になりましたが、コメントおよびフィードバックありがとうございました。
by Mishika (2009-10-24 23:06)