GPXファイルの標高データを書き換える
目的なんかは実行ファイルの配布ページを参照GPXファイルはGPSの軌跡情報を記録したXML形式のファイルです。
XMLとは何ぞやは「XMLとは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典」あたりを見てください。
XMLの説明が主題ではないので割愛します。
画面を作ります
最初に表示されるFormのデザイン画面でForm上にアイテムを置いて画面を作ります。リストからアイテムを選んでForm上に配置するだけの簡単なお仕事です。
配置したアイテムのプロパティを設定します。
アイテムをクリックして表示されるプロパティタブの項目を設定します。
(Name)はプログラムからアイテムを操作するためのインスタンス名(変数名のようなもの)です。
この例では文字を表示するだけで入力・編集はできないように ReadOnly を設定しています。
ボタンなどに表示するテキスト、入力枠に入力した文字も同じですが Text に設定設定します。
この例では文字を大きくしたいので Fonr を MS UI Gothicフォントの20ポイントに設定しています。
ボタンをクリックしたときの動作をプログラミングします
この例で操作するアイテムは1) オリジナルGPX Fileを選択する[...]ボタン
2) 変換操作を実行する[変換実行]ボタン
の二つです。
各々のボタンをクリックすると処理メソッドの雛形が作られます。
この例では プロパティタブの(Name)にFileSelectと名前を設定したボタンがクリックされたときの動作を記述するメソッドが表示されています。
Private Sub FileSelect_Click(sender As Object, e As EventArgs) Handles FileSelect.Click
End Sub
End Sub
ココにファイルチューザー(ファイルを選ぶダイアログ)を表示し、選んだファイルのファイル名を上でInputFileNameと(Name)を設定したアイテムに表示する処理を書きます。
※ついでに変換後のファイル名を変換後のファイル名 OutputFileNameaアイテムに表示します。
Private Sub FileSelect_Click(sender As Object, e As EventArgs) Handles FileSelect.Click
’ofd = Open File Dialogの略と思ってください。
' この辺りはお約束なので使いまわしできます。
Dim ofd As New OpenFileDialog()
ofd.Filter = "GPXファイル(*.gpx)|*.gpx"
ofd.Title = "GPXファイルを選択してください"
ofd.FilterIndex = 1
ofd.RestoreDirectory = True
ofd.CheckPathExists = False
If ofd.ShowDialog() = DialogResult.OK Then
InputFileName.Text = ofd.FileName
' 変換後のファイル名は末尾にNEを付け足す。
Dim fileNE As String = Strings.Left(ofd.FileName, ofd.FileName.Length - 4) & "NE.gpx"
OutputFileName.Text = fileNE
End If
End Sub
’ofd = Open File Dialogの略と思ってください。
' この辺りはお約束なので使いまわしできます。
Dim ofd As New OpenFileDialog()
ofd.Filter = "GPXファイル(*.gpx)|*.gpx"
ofd.Title = "GPXファイルを選択してください"
ofd.FilterIndex = 1
ofd.RestoreDirectory = True
ofd.CheckPathExists = False
If ofd.ShowDialog() = DialogResult.OK Then
InputFileName.Text = ofd.FileName
' 変換後のファイル名は末尾にNEを付け足す。
Dim fileNE As String = Strings.Left(ofd.FileName, ofd.FileName.Length - 4) & "NE.gpx"
OutputFileName.Text = fileNE
End If
End Sub
[変換実行]ボタンをクリックすると同じように処理メソッドの雛形が作られます。
プロパティタブの(Name)にExecと名前を設定したのでメソッドの名前は Exec_Click になります。
ここからGPXファイルを書き換えるプログラムの本体を呼び出します。
Private Sub Exec_Click(sender As Object, e As EventArgs) Handles Exec.Click
' フォームの値を取得:直接指定でも良い気がする
Dim inFileName As String = InputFileName.Text
Dim outFileName As String = OutputFileName.Text
Dim mode As Integer = Elevation.SelectedIndex ' 0 - 0m変換 1-削除
' 入力ファイルが存在するかチェック
If Not My.Computer.FileSystem.FileExists(inFileName) Then
MessageBox.Show("参照不能なファイルが指定されました。" & vbCrLf & "変換を実行できません。")
Exit Sub
End If
' 出力ファイルが存在するか(上書き)チェック
If My.Computer.FileSystem.FileExists(outFileName) Then
If MessageBox.Show(outFileName & vbCrLf & "は存在します。上書きしますか?", "上書き確認", MessageBoxButtons.YesNo) = DialogResult.No Then
Exit Sub
End If
End If
' 変換実行
GPXChange(inFileName, outFileName, mode)
End Sub
' フォームの値を取得:直接指定でも良い気がする
Dim inFileName As String = InputFileName.Text
Dim outFileName As String = OutputFileName.Text
Dim mode As Integer = Elevation.SelectedIndex ' 0 - 0m変換 1-削除
' 入力ファイルが存在するかチェック
If Not My.Computer.FileSystem.FileExists(inFileName) Then
MessageBox.Show("参照不能なファイルが指定されました。" & vbCrLf & "変換を実行できません。")
Exit Sub
End If
' 出力ファイルが存在するか(上書き)チェック
If My.Computer.FileSystem.FileExists(outFileName) Then
If MessageBox.Show(outFileName & vbCrLf & "は存在します。上書きしますか?", "上書き確認", MessageBoxButtons.YesNo) = DialogResult.No Then
Exit Sub
End If
End If
' 変換実行
GPXChange(inFileName, outFileName, mode)
End Sub
GPXファイルを書き換える処理本体をプログラミングします
XMLの操作自体はXmlDocumentクラスを使っているだけなので何という事もありません。ツリー状になっているXMLファイルの全部の枝を辿るために再帰呼び出しという技法(?)を使っています。
CheckNode( )メソッドの中からCheckNode( )を、つまり自分自身を呼び出す方法で木構造になっているデータ、例えばハードディスクのフォルダとかを順に操作する時によく使う方法です。
Public Sub GPXChange(inFile As String, outFile As String, mode As Integer)
' XMLを扱うためのオブジェクトを宣言
Dim xmlDoc As New XmlDocument()
' XMLを読み込み
xmlDoc.Load(inFile)
Dim node As XmlNode = xmlDoc.DocumentElement 'XMLドキュメントからルート要素を取り出す
' チャイルドノードを順番に操作するので処理を分けて再帰呼び出しにする。
CheckNode(node,mode)
' 処理したXMLを書込み
xmlDoc.Save(outFile)
End Sub
Private Sub CheckNode(parentNode As XmlNode, mode As Integer)
' チャイルドノードを順番にチェック
For Each node As XmlNode In parentNode.ChildNodes
If node.Name = "ele" Then
If mode = 0 Then ' 0-0mに変更 1-削除
node.InnerText = "0"
Else
parentNode.RemoveChild(node) ' ノードを削除
End If
Else
' トラック名を-NEを付け足した名称に変更
If parentNode.Name = "trk" And node.Name = "name" Then
node.InnerText &= "-NE"
End If
' ノードのチャイルドノードをチェック
If node.HasChildNodes Then
CheckNode(node,mode)
End If
End If
Next
End Sub
' XMLを扱うためのオブジェクトを宣言
Dim xmlDoc As New XmlDocument()
' XMLを読み込み
xmlDoc.Load(inFile)
Dim node As XmlNode = xmlDoc.DocumentElement 'XMLドキュメントからルート要素を取り出す
' チャイルドノードを順番に操作するので処理を分けて再帰呼び出しにする。
CheckNode(node,mode)
' 処理したXMLを書込み
xmlDoc.Save(outFile)
End Sub
Private Sub CheckNode(parentNode As XmlNode, mode As Integer)
' チャイルドノードを順番にチェック
For Each node As XmlNode In parentNode.ChildNodes
If node.Name = "ele" Then
If mode = 0 Then ' 0-0mに変更 1-削除
node.InnerText = "0"
Else
parentNode.RemoveChild(node) ' ノードを削除
End If
Else
' トラック名を-NEを付け足した名称に変更
If parentNode.Name = "trk" And node.Name = "name" Then
node.InnerText &= "-NE"
End If
' ノードのチャイルドノードをチェック
If node.HasChildNodes Then
CheckNode(node,mode)
End If
End If
Next
End Sub
完成
と言う感じで、フォームをデザインしてボタンをクリックすると出てくる雛形の中身を埋めていけばWindowsアプリケーションが出来上がります。プログラマ責任部分(自分でプログラムを書かなければならない部分)が少ないので割と楽に作れます。
実際にはもうちょっと使い易いように手を加えています。
実行中のカーソルの形を変えたりとか、ボタンを二重に押せないようにグレーアウトしたりとか。
そのあたりはプログラムの本質的な問題ではないので割愛します、色々試してみてください。
完成したプログラム(ソースコードと実行ファイル)はコチラ