請求書PDFの表データを、エクセル台帳へ転記したいときがあります。
このときマウスで一つ一つコピーし、エクセルへ貼り付けしていく場合が多いです。
しかしテキスト情報が多いPDFの場合、この作業は時間がかかる上にとても面倒くさいです。
またコピー箇所を間違えて、抜けや漏れがあったりすることもあります。
そこでこのページではVBAを使ってPDFの表データを取得し、エクセルへ一覧にする方法を紹介します。
・VBA入りのエクセルファイルをダウンロード可能
それでは以下で詳しく紹介していきます。
目次
- 1 VBAで請求書PDFの表データをエクセル台帳に転記する
- 2 VBA入りのエクセルファイルをダウンロード
- 3 類似の事例
- 4 VBA作成前の事前準備
- 5 VBAのプログラムソース解説
- 5.1 プログラム0|変数宣言の指定
- 5.2 プログラムA-1|プログラム開始
- 5.3 プログラムA-2|シート設定
- 5.4 プログラムA-3|セルB1の値をフォルダパスを取得
- 5.5 プログラムA-4|A列の最終行を取得
- 5.6 プログラムA-4|プログラムBを実行
- 5.7 プログラムA-5|FileSystemObjectの設定
- 5.8 プログラムA-6|フォルダ内の全てのPDFを処理
- 5.9 プログラムA-7|プログラムBを実行
- 5.10 プログラムA-8|プログラムCを実行して戻り値としてcmaxを取得
- 5.11 プログラムA-9|xmlpath(xmlファイル)を削除
- 5.12 プログラムA-10|プログラム終了
- 5.13 プログラムB|PDFをXMLファイルに変換
- 5.14 プログラムC-1|プログラム開始
- 5.15 プログラムC-2~プログラムC-5
- 5.16 プログラムC-6|変数設定
- 5.17 プログラムC-7|TRタグの要素をForEachで一つずつ処理
- 5.18 プログラムC-8|請求書ID、請求日、御中をそれぞれ取得
- 5.19 プログラムC-9|表データを取得
- 5.20 プログラムC-10|表データを行ごとに取得
- 5.21 プログラムC-11|行データを列ごとに取得
- 5.22 プログラムC-12|スキップ先
- 5.23 プログラムC-13|最終行cmaxを戻り値とする
- 5.24 プログラムC-14|プログラム終了
- 6 Excel VBAについて詳しく理解したいなら
VBAで請求書PDFの表データをエクセル台帳に転記する
VBAでPDFを操作して、PDFのテキスト情報をエクセルに出力します。
このプログラムの使用手順は以下のとおりです。
手順1. セルB1にPDFのフルパスを入力
手順2. VBAプログラムを実行
以下で使い方の手順を紹介します。
手順1. セルB1にPDFのフルパスを入力
上記のようにセルB1に取得したいPDFが保管されているフォルダパスを入力します。
ここでは3つのPDFと1つのエクセルが保管されたフォルダパスを指定しています。
プログラムの中でエクセルは対象とせずにPDFのみ取得されるようにしています。
対象とする請求書PDFは以下のような形をしています。
上記の赤枠で囲んだ部分をエクセルに出力していきます。
手順2. VBAプログラムを実行
VBAを実行するとエクセルにPDFのデータを出力します。
上記のように3つのPDFのデータをエクセルに出力できました。
私のPCでは3つのPDFのデータを取得するのに10~15秒程度かかりました。
これはお使いのPCの仕様によるかと思いますので、参考情報です。
ボタンにVBAプログラムを登録
上記の画像では、VBAプログラムをボタンに登録しています。
ボタンにVBAプログラムを登録することで、ボタンを押下しプログラムを実行することができます。
ボタンをVBAプログラムを設定したい場合は、以下で動画も交えて設定方法を紹介しているので、そちらをご覧ください。
注意点
ここで紹介しているPDFデータの取得プログラムは汎用性は高くありません。
なぜなら請求書のフォーマットが変更されると使えないからです。
同じフォーマットで作成されていないと、プログラムで正しくデータ構造を正しく読み込めなくなってしまうためです。
要は使い所を選ぶということです。
力を発揮できる条件とそうではない条件を以下で列挙しておきます。
・同じフォーマットで作成された請求書のデータを取得する場合
・フォーマットが異なる請求書が複数ある場合(複数の取引先が異なる書式の請求書を使っている場合)
上記の点に注意した上で、このプログラムを活用してみていただければと思います。
請求書PDFをエクセルに書き出すための別手段
少しコピペ作業が発生しますが、PDFからデータを取得するよりは早く処理を行える方法もあります。
以下のようにPDFをエクセルに書き出して、その表データをコピペする方法です。
複数のPDFを一括でエクセルに変換し、エクセルの表を一つに集約すれば、PDFをそのままコピペして作業するよりは早く作業完了できるはずです。
なおAdobe Acrobat Proのような有料版でしか使えない機能のため、Readerのようなフリーのアプリしかインストールされていない場合、使えないと思います。
私のPCではReader(フリー)での検証をしていないので、真偽は定かではありませんが、使えないと理解しています。
VBA入りのエクセルファイルをダウンロード
以下で紹介しているVBAプログラムをそのまま使いたい人は、以下のフォームからダウンロードできます。
登録したメールアドレスへ「VBAプログラムが含まれたエクセル」を送信します。
本プログラムの内容をそのまま使用可能です。ぜひお仕事にお役立てください。
それでは、以下でプログラムについて詳細を説明します。
類似の事例
ここでは請求書PDFをエクセルへ出力するプログラムを紹介しました。
他にも類似の事例を紹介しています。
VBAでPDF操作するプログラムのまとめ
VBA作成前の事前準備
ExcelでVBAを使うためにはいくつかの準備が必要です。
具体的には以下です。
準備2. 「Microsoft XML v6.0」の参照設定を変更
準備3. フォルダを扱うための事前準備
準備4. 「Acrobat」の参照設定を変更
上記に関して、以下で説明します。
準備1. ExcelでVBAを使うための事前準備
エクセルVBAを使うためには、保存ファイルの拡張子変更、Excelの基本設定変更の2つをしておきます。
2つともで難しい作業はなく、それぞれ1分もあれば設定変更可能です。
上記に関しては、以下の記事で解説をしています。
もしVBAを使うための準備段階に不安がある人は上記をご覧ください。
この内容は以下の動画で紹介しています。
入門エクセルマクロの使い方|マクロ作成から実行までを徹底解説
文字や画像だけで分かりづらい人は上記の動画をご覧ください。
準備2. 「Microsoft XML v6.0」の参照設定を変更
エクセルVBAでXML情報を取得するために、VBAの設定を変更しておく必要があります。
実はVBAのデフォルト設定の場合、メール送信操作はできません。
参照設定を変更することで、HTTPリクエスト通信とHTMLの解析が可能になります。
参照設定の変更手順は以下のとおりです。
手順2. 「参照設定」を選択
手順3. 「Microsoft XML v6.0」にチェックを入れる
手順4. OKをクリック
手順を以下で説明します。
上記の設定をしていないと、本事例で紹介しているプログラムは動作しません。必ずチェックを入れるようにします。
それでは、以下でプログラムについて詳細を説明します。
準備3. フォルダを扱うための事前準備
この事例ではフォルダを操作するために、FileSystemObjectを活用します。
FileSystemObjectを使用する場合、VBAの参照設定を変更しておく必要があります。参照設定とは、機能拡張させることです。
FileSystemObjectを使用するために以下の参照設定を変更します。
これでフォルダやファイルの情報を取得することができるようになります。
設定方法の詳細は以下のページで紹介しています。
準備4. 「Acrobat」の参照設定を変更
Adobe Acrobatを使用するためには、VBAの参照設定を以下のとおり変更します。
これでAdobe Acrobatを使ってPDF操作が可能になります。
設定方法の詳細は以下のページで紹介しています。
注意|Acrobat操作には、Acrobat Proを利用する必要がある
使用するパソコンにAcrobat Readerしか含まれていなかったとしたら、VBAでPDF操作はできません。
このページで紹介するPDF操作には、Adobe Acrobat Proを購入しておく必要があります。参照設定で、Acrobatをチェックできないならば、Acrobat Proに登録されていないことを意味しています。
したがって、こちらからAcrobat Proを試すことができます。
なお、Acrobat Standardでも可能かも思われますが、検証しておりません。
VBAのプログラムソース解説
今回紹介するプログラムの概要は以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
'プログラム0|変数設定の指定 Option Explicit 'プログラムA-1|プログラム開始 Sub GetPDFTableData() 'プログラムA-2|シート設定 Dim ws As Worksheet Set ws = Worksheets("Sheet1") 'プログラムA-3|セルB1の値をフォルダパスを取得 Dim folderpath As String folderpath = ws.Range("B1").Value 'プログラムA-4|A列の最終行を取得 Dim cmax As Long cmax = ws.Range("A65536").End(xlUp).Row 'プログラムA-5|FileSystemObjectを設定 Dim fs As FileSystemObject Set fs = New Scripting.FileSystemObject 'プログラムA-6|フォルダ内の全てのPDFを処理 Dim basefolder As Scripting.Folder Set basefolder = fs.GetFolder(folderpath) Dim mysubfiles As Scripting.Files Set mysubfiles = basefolder.Files Dim mysubfile As Scripting.File For Each mysubfile In mysubfiles If fs.GetExtensionName(path:=mysubfile) = "pdf" Then 'プログラムA-7|プログラムBを実行 Dim xmlpath As String xmlpath = ConvertXml(mysubfile) 'プログラムA-8|プログラムCを実行して戻り値としてcmaxを取得 cmax = XmlParse(xmlpath, ws, cmax) 'プログラムA-9|xmlpath(xmlファイル)を削除 fs.DeleteFile (xmlpath) End If Next 'プログラムA-10|プログラム終了 End Sub 'プログラムB-1|プログラム開始 Function ConvertXml(path) 'プログラムB-2|Acrobatアプリケーションを起動 Dim objAcroApp As New Acrobat.AcroApp objAcroApp.Show 'プログラムB-3|AcrobatでPDFを開く Dim objAcroAVDoc As New Acrobat.AcroAVDoc Set objAcroAVDoc = New Acrobat.AcroAVDoc objAcroAVDoc.Open path, "" 'プログラムB-4|PDFの情報を取得 Dim objAcroPDDoc As Acrobat.AcroPDDoc Set objAcroPDDoc = objAcroAVDoc.GetPDDoc() 'プログラムB-5|JavaScriptオブジェクトを作成 Dim js As Object Set js = objAcroPDDoc.GetJSObject 'プログラムB-6|PDFをxmlファイルに変換 Dim savename As String savename = Replace(path, "pdf", "xml") js.SaveAs savename, "com.adobe.acrobat.xml-1-00" 'プログラムB-7|PDFファイルを変更無しで閉じる objAcroAVDoc.Close (1) 'プログラムB-8|Acrobatアプリケーションを終了 objAcroApp.Exit 'プログラムB-9|オブジェクト解放 Set js = Nothing Set objAcroPDDoc = Nothing Set objAcroAVDoc = Nothing Set objAcroApp = Nothing 'プログラムB-10|Funtionプロシージャの戻り値を設定 ConvertXml = savename 'プログラムB-11|プログラム終了 End Function 'プログラムC-1|プログラム開始 Function XmlParse(xmlpath, ws, cmax) 'プログラムC-2|MSXMLオブジェクトを生成 Dim XMLDocument As MSXML2.DOMDocument60 Set XMLDocument = New MSXML2.DOMDocument60 'プログラムC-3|非同期処理に対応しない XMLDocument.async = False 'プログラムC-4|xmlファイルをロード XMLDocument.Load (xmlpath) 'プログラムC-5|ロード失敗した場合、メッセージ表示してプログラム終了 Dim strMsg As String If XMLDocument.parseError.ErrorCode <> 0 Then strMsg = XMLDocument.parseError.reason 'エラー内容を出力 MsgBox "ロードに失敗しました・・・" & vbCrLf & vbCrLf & strMsg, vbCritical Exit Function End If 'プログラムC-6|変数設定 Dim objxml As Object, cnode As Object, dnode As Object, enode As Object Dim id As String, torihiki As String Dim hiduke As Date 'プログラムC-7|TRタグの要素をForEachで一つずつ処理 For Each objxml In XMLDocument.getElementsByTagName("TR") 'プログラムC-8|請求書ID、請求日、御中をそれぞれ取得 If InStr(objxml.XML, "請求書ID") > 0 Then id = objxml.ChildNodes(1).Text ws.Range("A" & cmax + 1).Value = id End If If InStr(objxml.XML, "請求日") > 0 Then hiduke = objxml.ChildNodes(1).Text ws.Range("B" & cmax + 1).Value = hiduke End If If InStr(objxml.XML, "御中") > 0 Then torihiki = objxml.ChildNodes(2).Text ws.Range("C" & cmax + 1).Value = torihiki End If Next 'プログラムC-9|表データを取得 For Each cnode In XMLDocument.getElementsByTagName("Table") '特定の文字列を含むTableタグを取得 If InStr(cnode.XML, "取引ID") > 0 Then 'プログラムC-10|表データを行ごとに取得 For Each dnode In cnode.SelectNodes("TR") 'Tableのヘッダーは処理をスキップ If InStr(dnode.XML, "取引ID") > 0 Then GoTo Continue End If 'プログラムC-11|行データを列ごとに取得 'kをゼロリセット Dim k As Long: k = 0 '行データを列ごとに取得 For Each enode In dnode.ChildNodes If enode.Text <> "" Then ws.Range("D1").Offset(cmax, k).Value = enode.Text k = k + 1 End If Next '行数をカウントアップ cmax = cmax + 1 'プログラムC-12|スキップ先 Continue: Next End If Next 'プログラムC-13|最終行cmaxを戻り値とする XmlParse = cmax 'プログラムC-14|プログラム終了 End Function |
それでは、以下でプログラムを詳しく説明していきます。
プログラム0|変数宣言の指定
1 |
Option Explicit |
「Option Explicit」とは、変数宣言を強制するためのものです。
予期しないエラーを防止できるため「Option Explicit」を入力することを習慣化することを推奨しています。
詳しい説明は以下のページで紹介しています。
また変数については、以下のページで紹介しています。
プログラムA-1|プログラム開始
1 |
Sub GetPDFTableData() |
「Sub GetPDFTableData()」のプログラムを開始することを意味します。
VBAではプロシージャという単位でプログラムを呼び出します。
プロシージャの構文は下記となっています。
1 2 3 |
Sub プロシージャ名() '実行プログラム End Sub |
「Sub」で始まり「End Sub」で終わります。
プロシージャに関連するmoduleの話については以下で説明しています。
プログラムA-2|シート設定
1 2 |
Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets("Sheet1") |
「Sheet1」をwsとして設定します。
なお「ThisWorkbook」を付けることで、VBAプログラムが含まれるエクセルファイルの「Sheet1」を細かく指定しています。
プログラムA-3|セルB1の値をフォルダパスを取得
1 2 |
Dim folderpath As String folderpath = ws.Range("B1").Value |
変数folderpathを文字列型で設定し、セルB1の値をfolderpathとして取得します。
Debug.Printでの検証結果
1 2 3 4 5 6 |
Dim folderpath As String folderpath = ws.Range("B1").Value Debug.Print folderpath >>>D:\Website_パソコンスキルの教科書\307_VBA_PDF\14_請求書PDFをエクセル台帳へ\VBA\2021-06-07_請求書リスト |
上記のとおりフォルダパスを取得できていることが分かります。
プログラムA-4|A列の最終行を取得
1 2 |
Dim cmax As Long cmax = ws.Range("A65536").End(xlUp).Row |
変数cmaxを整数(Long)型で設定し、A列の最終行を取得します。
Debug.Printでの検証結果
1 2 3 4 5 6 |
Dim cmax As Long cmax = ws.Range("A65536").End(xlUp).Row Debug.Print cmax >>>3 |
上記のとおりcmaxで最終行を取得できていることが分かります。
プログラムA-4|プログラムBを実行
1 2 |
Dim xmlpath As String xmlpath = ConvertXml(path) |
xmlpathを文字列型で変数設定し、プログラムB「Funtion ConvertXml(path)」を実行します。
「Funtion ConvertXml(path)」を実行後に、その戻り値をxmlpathとして取得します。
xmlpathはプログラムBを実行後に、値が格納されます。
プログラムBで説明していますが、このxmlpathはプログラムB-10のとおりsavename(プログラムB-6で設定)の値を返ってきます。
Debug.Printでの検証結果
1 2 3 4 5 6 |
Dim xmlpath As String xmlpath = ConvertXml(path) Debug.Print xmlpath >>>D:\Website_パソコンスキルの教科書\307_VBA_PDF_10\13_PDFToText\VBA\副業・兼業のガイドライン.xml |
これでxmlpathに、PDFをxmlに変換したファイルパスを取得できていることが分かります。
プログラムA-5|FileSystemObjectの設定
1 2 |
Dim fs As FileSystemObject Set fs = New Scripting.FileSystemObject |
FileSystemObjectは、ファイルやフォルダを操作するときに使うオブジェクトです。
本事例ではFileSystemObjectをfsという変数として扱います。
変数fsは定義するだけではなく、「Set fs = New Scripting.FileSystemObject」と記入して使えるようになります。
これを忘れてしまうことが多いので、注意が必要です。
FileSystemObjectに関する注意点
参照設定にて、Microsoft Scripting Runtimeを設定に入れておく必要があります。
設定を忘れると動作しませんので、事前に設定を変更しておく必要があります。
なお、FileSystemObject以外にもフォルダを操作する方法はあります。しかしFileSystemObjectを使えば、ファイルとフォルダを両方操作できるので、覚えることが少なくて済みます。
細かいことを覚えるのが面倒な人は、ファイルやフォルダを操作するときはFileSystemObjectを使うと覚えておくといいです。
FileSystemObjectについては以下で詳しく説明していますので、ご覧ください。
プログラムA-6|フォルダ内の全てのPDFを処理
1 2 3 4 5 6 7 8 9 |
Dim basefolder As Scripting.Folder Set basefolder = fs.GetFolder(folderpath) Dim mysubfiles As Scripting.Files Set mysubfiles = basefolder.Files Dim mysubfile As Scripting.File For Each mysubfile In mysubfiles If fs.GetExtensionName(path:=mysubfile) = "pdf" Then |
folderpathで取得したフォルダパスに含まれる全てのファイルを処理します。
そのときファイルの拡張子を一つずつ取得してpdfの場合のみ、プログラムA-7~プログラムA-9の処理を実行するようにします。
特定の拡張子の場合だけ処理する事例は以下で紹介しています。
Debug.Printでの検証結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Dim basefolder As Scripting.Folder Set basefolder = fs.GetFolder(folderpath) Dim mysubfiles As Scripting.Files Set mysubfiles = basefolder.Files Dim mysubfile As Scripting.File For Each mysubfile In mysubfiles If fs.GetExtensionName(path:=mysubfile) = "pdf" Then Debug.Print mysubfile.Name End If Next >>>20210607_愛媛不動産_report.pdf >>>20210607_愛知製本_report.pdf >>>20210607_愛知販売_report.pdf |
上記のようにフォルダ内のPDFのみ対象としていることが分かります。
プログラムA-7|プログラムBを実行
1 2 |
Dim xmlpath As String xmlpath = ConvertXml(mysubfile) |
プログラムBを実行します。
引数としてmysubfileを渡します。mysubfileはPDFのフルパスです。
これをプログラムBに渡して、PDFをXML化します。
プログラムA-8|プログラムCを実行して戻り値としてcmaxを取得
1 |
cmax = XmlParse(xmlpath, ws, cmax) |
プログラムC(XmlParse)を実行します。
このとき引数として、xmlpath(プログラムA-7で取得)、とws(プログラムA-2)、cmax(プログラムA-4およびプログラムA-8で更新される)を渡します。
プログラムCはFunctionプロシージャとして設定しています。
プログラムA-9|xmlpath(xmlファイル)を削除
1 2 3 |
fs.DeleteFile (xmlpath) End If Next |
この時点でxmlファイルの解析は終了しているため、ファイル削除します。
FileSystemObjectのDeleteFileメソッドを使ってxmlファイル(xmlpath)のファイルを削除します。
プログラムA-10|プログラム終了
1 |
End Sub |
これでプログラムAは終了です。
プログラムB|PDFをXMLファイルに変換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
'プログラムB-1|プログラム開始 Function ConvertXml(path) 'プログラムB-2|Acrobatアプリケーションを起動 Dim objAcroApp As New Acrobat.AcroApp objAcroApp.Show 'プログラムB-3|AcrobatでPDFを開く Dim objAcroAVDoc As New Acrobat.AcroAVDoc Set objAcroAVDoc = New Acrobat.AcroAVDoc objAcroAVDoc.Open path, "" 'プログラムB-4|PDFの情報を取得 Dim objAcroPDDoc As Acrobat.AcroPDDoc Set objAcroPDDoc = objAcroAVDoc.GetPDDoc() 'プログラムB-5|JavaScriptオブジェクトを作成 Dim js As Object Set js = objAcroPDDoc.GetJSObject 'プログラムB-6|PDFをxmlファイルに変換 Dim savename As String savename = Replace(path, "pdf", "xml") js.SaveAs savename, "com.adobe.acrobat.xml-1-00" 'プログラムB-7|PDFファイルを変更無しで閉じる objAcroAVDoc.Close (1) 'プログラムB-8|Acrobatアプリケーションを終了 objAcroApp.Exit 'プログラムB-9|オブジェクト解放 Set js = Nothing Set objAcroPDDoc = Nothing Set objAcroAVDoc = Nothing Set objAcroApp = Nothing 'プログラムB-10|Funtionプロシージャの戻り値を設定 ConvertXml = savename 'プログラムB-11|プログラム終了 End Function |
プログラムB(B-1~B-11)でpathで指定したPDFをxmlファイルに変換します。
こちらは以下のページで詳しく説明しています。
プログラムC-1|プログラム開始
1 |
Function XmlParse(xmlpath, ws1, cmax) |
Subプロシージャ「XmlParse」のプログラムの開始を表します。
引数としてxmlpath、ws、cmaxを受け取ります。
2. ws:プログラムA-2で設定したシート
3. cmax:エクセルへ出力するときの行数
上記の引数を受け取って、プログラムCを実行します。
プログラムC-2~プログラムC-5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
'プログラムC-2|MSXMLオブジェクトを生成 Dim XMLDocument As MSXML2.DOMDocument60 Set XMLDocument = New MSXML2.DOMDocument60 'プログラムC-3|非同期処理に対応しない XMLDocument.async = False 'プログラムC-4|xmlファイルをロード XMLDocument.Load (xmlpath) 'プログラムC-5|ロード失敗した場合、メッセージ表示してプログラム終了 Dim strMsg As String If XMLDocument.parseError.ErrorCode <> 0 Then strMsg = XMLDocument.parseError.reason 'エラー内容を出力 MsgBox "ロードに失敗しました・・・" & vbCrLf & vbCrLf & strMsg, vbCritical Exit Function End If |
MSXMLオブジェクトを生成してXMLを読み込みを行います。
読み込みが失敗したら、プログラムを強制終了させます。
このプログラムC-2~プログラムC-5は、以下のページで説明をしているので、ここでは省略します。
プログラムC-6|変数設定
1 2 3 |
Dim objxml As Object, cnode As Object, dnode As Object, enode As Object Dim id As String, torihiki As String Dim hiduke As Date |
変数を設定します。
変数については、以下のページで説明しています。
プログラムC-7|TRタグの要素をForEachで一つずつ処理
1 |
For Each objxml In XMLDocument.getElementsByTagName("TR") |
対象となるXMLの「TR」タグを一つずつ処理をしていきます。
プログラムC-8|請求書ID、請求日、御中をそれぞれ取得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
If InStr(objxml.XML, "請求書ID") > 0 Then id = objxml.ChildNodes(1).Text ws.Range("A" & cmax + 1).Value = id End If If InStr(objxml.XML, "請求日") > 0 Then hiduke = objxml.ChildNodes(1).Text ws.Range("B" & cmax + 1).Value = hiduke End If If InStr(objxml.XML, "御中") > 0 Then torihiki = objxml.ChildNodes(2).Text ws.Range("C" & cmax + 1).Value = torihiki End If |
TRタグに含まれる「請求書ID」、「請求日」、「御中」が含まれるとき、その1番目の子要素を取得しています。
今回扱う請求書のデータ構造上、「請求書ID」、「請求日」、「御中」が含まれるTRタグ内の1番目の子要素に求めるデータが入っているからです。
取得した「請求書ID」、「請求日」、「御中」をエクセルに書き出します。
プログラムC-9|表データを取得
1 2 3 4 |
For Each cnode In XMLDocument.getElementsByTagName("Table") '特定の文字列を含むTableタグを取得 If InStr(cnode.XML, "取引ID") > 0 Then |
対象XMLの表をTableタグとして取得します。
この事例で対象とするXMLは複数のTableタグがあります。
その中でデータを取得したい表は「取引ID」を持っているため、Instr関数を使って、取引IDをもつ文字列を含む表を特定します。
Instr関数については以下のページで事例を交えて紹介しています。
プログラムC-10|表データを行ごとに取得
1 2 3 4 5 6 |
For Each dnode In cnode.SelectNodes("TR") 'Tableのヘッダーは処理をスキップ If InStr(dnode.XML, "取引ID") > 0 Then GoTo Continue End If |
プログラムC-9で特定したTableタグに含まれるTRタグを一つずつ取得していきます。
ヘッダー情報は取得不要なので、処理をスキップ
表のヘッダー情報はエクセルに出力する必要はありません。
ヘッダー情報には「取引ID」の文字列を含んでいるため、それを利用し、dnode.XMLに「取引ID」を含んでいる場合は処理をスキップさせます。
1 2 3 |
If InStr(dnode.XML, "取引ID") > 0 Then GoTo Continue End If |
これでプログラムC-12にジャンプさせて、プログラムC-11をスキップさせることができます。
プログラムC-11|行データを列ごとに取得
1 2 3 4 5 6 7 8 9 10 11 12 13 |
'kをゼロリセット Dim k As Long: k = 0 '行データを列ごとに取得 For Each enode In dnode.ChildNodes If enode.Text <> "" Then ws.Range("D1").Offset(cmax, k).Value = enode.Text k = k + 1 End If Next '行数をカウントアップ cmax = cmax + 1 |
行データを列ごとに取得してエクセルに出力します。
kをゼロリセット
1 |
Dim k As Long: k = 0 |
kをゼロリセットします。kはOffset(cmax,k)の部分で使用します。
つまりkを使って、エクセルにデータを出力するときの列番号を指定しています。
このタイミングでゼロリセットすることで、エクセルに出力するときのA列から順番に出力されるようにしています。
行データを列ごとに取得
1 2 3 4 5 6 |
For Each enode In dnode.ChildNodes If enode.Text <> "" Then ws.Range("D1").Offset(cmax, k).Value = enode.Text k = k + 1 End If Next |
行データ(dnode)を取得し、その行に含まれる列データをdnode.ChildNodesでコレクションとして取得します。
ForEachを使って列データを一つずつ処理していっきます。
処理する列データが空欄でなければエクセルにその値を出力します。
kをカウントアップすることで、エクセルに出力する列がずれないようにします。
行数をカウントアップ
1 |
cmax = cmax + 1 |
cmaxをカウントアップすることで、エクセルに出力する行数をカウントアップします。
これをやっておかないとエクセルの同じ行に上書きされるだけになってしまいます。
プログラムC-12|スキップ先
1 2 3 4 |
Continue: Next End If Next |
プログラムC-10で処理をスキップさせるときの行先として使います。
プログラムC-13|最終行cmaxを戻り値とする
1 |
XmlParse = cmax |
戻り値としてcmaxを返します。
ここではプログラムA-8で「cmax = XmlParse(xmlpath, ws, cmax)」としているため、プログラムCでカウントアップしたcmaxをプログラムAに戻すことになります。
こうすることで、エクセルに出力する行数を正しくカウントアップできます。
プログラムC-14|プログラム終了
1 |
End Function |
プログラムC-1と対になるプログラムです。プログラム終了させる記載です。
「End Function」を読み込んで呼び出されたプログラムに戻ります。
この事例ではプログラムA-8に戻ります。
プログラムの解説はここまでです。
Excel VBAについて詳しく理解したいなら
上記は、私が実際にVBAを活用して効率化してきた事例を紹介しています。
VBAを活用すると、仕事を効率化できる幅を広げることができます。
Excel VBAで出来ることは動画でも解説
動画でも解説しています。
エクセルマクロVBAで出来ることを15の事例で紹介|日常業務をラクにするヒントを見つけよう!
(音声が小さいので、ボリュームを上げてご覧いただければと思います)
VBAの勉強方法
私はプログラミング初心者からVBAを勉強を始めて少しずつレベルアップしていきました。
成長の過程は以下で紹介しています。
学習の過程では、意識すべきポイントがあります。
特に独学の場合だと、勉強を優先してしまい、肝心な実践を疎かにしがちです。
私の経験では、実践から逆算した勉強が必要だと考えています。
目指すべきは会社でお金をもらいながら勉強することです。
要はVBAを仕事の一つとして上司に認めてもらうのです。
そうすればわざわざ高いお金を払って勉強をする必要がなくなります。
しかも作業を自動化して、会社やチームに貢献しつつ、自らのスキルアップできます。
そのために必要な考え方を以下で紹介しています。
とはいえ、プログラミング初心者でVBAについて知識ゼロの人もいるはずです。
いきなり会社でVBAで使うことさえ、とてつもなくハードルが高く見えてしまうものです。
その場合は、VBAの基本について学ぶ必要があります。
たとえば車の運転も慣れてしまえば、たいしたことではありません。
しかし教習所で運転の基本を学び、免許を取得することで、公道で運転できるようになります。
VBAも同じです。VBAに免許はありませんが、まずは基本を学ばないことには会社で使えるレベルにはなりません。
実際に私もプログラミング初心者のときは、動画を見たり書籍を読んだりして勉強しました。
今はオンラインの教材で無料で学習できるものも多いです。
上記のリンクでは、私の経験から勉強にオススメの教材を紹介しています。
興味がある人はご覧ください。