Visual Basic 初級講座 [改訂版]
VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

第41回 XML

2021/8/8

この記事が対象とする製品・バージョン

VB2019 Visual Basic 2019 対象です。
VB2017 Visual Basic 2017 対象です。
VB2015 Visual Basic 2015 対象です。
VB2013 Visual Basic 2013 対象です。
VB2012 Visual Basic 2012 対象です。
VB2010 Visual Basic 2010 対象です。
VB2008 Visual Basic 2008 × 対象外です。
VB2005 Visual Basic 2005 × 対象外です。
VB.NET 2003 Visual Basic.NET 2003 × 対象外です。
VB.NET 2002 Visual Basic.NET (2002) × 対象外です。
VB6対応 Visual Basic 6.0 × 対象外です。

 

目次

 

1.XMLリテラル

VBはXMLをリテラルとして扱うことができます。リテラルとは文字列や数値のように直接プログラム中に記述できる値のことを言います。

C#やJavaなど多くの汎用言語ではXMLを扱うことはできますが、リテラルとして扱うことができるのは私が知る限りVBだけです。

たとえば、次のような記述ができます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <person>
              <name>徳川家康</name>
              <age>19</age>
          </person>


Dim result = xml.<name>.Value

Debug.WriteLine(result) '徳川家康と表示されます。

 

今回はVBのXML機能について説明しますが、この機能はXMLの読み書きが必要なプログラム以外ではほとんど出番はありません。そのため、あまり深入りせずダイジェスト的に使い方を紹介するに留めます。

 

2.XML

2-1.要素とタグ

XMLの機能を説明する前に、そもそもXMLとな何なのかごく簡単に説明しておきます。

XMLとは、データを構造化するためのルールの1つです。特定のプログラミング言語には依存しない仕様です。2021年現在ではJSONと並んで幅広く使われています。

表現するデータは文字として表現できるものならなんでもよく制約はありません。

XMLの中ではデータは「要素」(Element)として記述します。要素を記述するにはよく見かけるように < > を使ったタグを使います。

次の例では、動物要素にとしてキリンを定義しています。動物要素を定義するために動物タグを使っています。


<動物>キリン</動物>

要素は自分で自由に定義してよいことになっています。たとえば、「動物」の代わりに、「生物」、「いきもの」、「Animal」など何を使っても良いのが特徴です。

このように自由にデザインできるため拡張性に優れて広く普及しているわけです。

 

次の例のように要素を入れ子にすることもできます。

<人物>
    <名前>徳川家康</名前>
    <住所>東京都千代田区1丁目</住所>
</人物>

この例では人物要素と名前要素と住所要素が存在します。

 

2-2.ルート要素

XMLでは一番外側の要素は1つである必要があります。そうでない場合、完全なXMLとはみなされません。この一番外側の唯一の要素のことをルート要素と呼びます。

たとえば、次のXMLは一番外側が Persons 要素1つであるので有効です。ルート要素は Persons要素です。

<Persons>
    <Person>徳川家康</Person>
    <Animal>キリン</Animal>
    <Person>豊臣秀吉</Person>
</Persons>

次のXMLは3つの要素全部が一番外側になっているので完全なXMLではありません。

<Person>徳川家康</Person>
<Animal>キリン</Animal>
<Person>豊臣秀吉</Person>

 

2-3.属性

XMLの要素には属性(Attribute)を付けて、追加の情報を記述することができます。

属性はタグの中に属性名="値" の形で記述します。複数の属性を記述することができます。属性も要素と同じで自由な名前を使ってよいことになっています。

次の例では Person要素に born属性と died属性を記述しています。

<Persons>
    <Person born="1543" died="1616">徳川家康</Person>
    <Person died="1598" >豊臣秀吉</Person>
</Persons>

豊臣秀吉の方には born 属性がありませんが、これでもXMLとしては問題ありません。

 

2-4.XML宣言

データXMLであることを示すためにXMLの先頭にXML宣言を記述することができます。

XML宣言は <?xml version="1.0" encoding="UTF-8"?> のように記述します。

次のXML有効です。

<?xml version="1.0" encoding="UTF-8"?>
<Persons>
    <Person born="1543" died="1616">徳川家康</Person>
    <Person died="1598" >豊臣秀吉</Person>
</Persons>

 

 

3.XMLの生成

VBでXMLをあつかうには冒頭で紹介したようにXMLリテラルを使用する方法の他にファイルから読み込む方法や文字列のXMLを読み込む方法などがあります。

XMLリテラルからXMLを生成する冒頭の例を再掲します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <person>
              <name>徳川家康</name>
              <age>19</age>
          </person>


Dim result = xml.<name>.Value

Debug.WriteLine(result) '徳川家康と表示されます。

この例では変数 xml は XMLの要素を表す XElement型になります。

次のようにXML宣言を付けるとXDocument型になります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <?xml version="1.0" encoding="utf-8"?>
          <person>
              <name>徳川家康</name>
              <age>19</age>
          </person>


Dim result = xml.<person>.<name>.Value

Debug.WriteLine(result) '徳川家康と表示されます。

name要素の値を読み込むために <person>. が必要であるという違いがある点に注意してください。

 

XMLが記述されたファイルがあれば、次のようにファイルのパスを指定してXMLを読み込むこともできます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = XDocument.Load("C:\temp\xmlsample.xml")

Dim result = xml.<person>.<name>.Value

Debug.WriteLine(result) '徳川家康と表示されます。

 

文字列で表現されたXMLを読み込むには、少し作業が必要です。次のようになります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xmlText As String = "<person><name>徳川家康</name><age>19</age></person>"
Dim xml As XDocument

Using reader As New IO.StringReader(xmlText)
    xml = XDocument.Load(reader, LoadOptions.None)
End Using

Dim result = xml.<person>.<name>.Value

Debug.WriteLine(result) '徳川家康と表示されます。

 

VBのXMLの強力な点はXMLリラテルの中でLINQを使用できる点です。

XMLリテラルの中で特別な記号 <%= から %> の間にVBの式を記述できます。

次の例ではWindowsフォルダーのファイル一覧をXML化します。最後にSaveメソッドを使ってそのXMLをファイルに保存します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim winFolder As New IO.DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.Windows))

Dim xml = <files>
              <%= From file In winFolder.GetFiles
                  Select <file>
                             <name><%= file.Name %></name>
                             <size><%= file.Length %></size>
                         </file>
              %>
          </files>


xml.Save("C:\temp\files.xml")

保存されたXMLは次のようになります。

<?xml version="1.0" encoding="utf-8"?>
<files>
    <file>
        <name>bfsvc.exe</name>
        <size>77824</size>
    </file>
    <file>
        <name>bootstat.dat</name>
        <size>67584</size>
    </file>
    <file>
        <name>comsetup.log</name>
        <size>762</size>
    </file>
…以下略

 

4.XMLから値を取得

4-1.要素の取得

XMLから要素を取得するには、タグをオブジェクトのプロパティであるかのように使用します。XML要素はXElement型になります。

次の例では nama要素を取得します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <persons>
              <person><name>徳川家康</name><age>19</age></person>
          </persons>


Dim result = xml.<person>.<name>

Debug.WriteLine(result.Value) '徳川家康と表示されます。

Person要素が複数ある場合は、該当する要素をのコレクションが取得されます。

コレクションから各要素を取り出すには、配列やListと同じように (0)、(1)、…という添え字を使用します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <persons>
              <person><name>徳川家康</name><age>19</age></person>
              <person><name>織田信長</name><age>30</age></person>
          </persons>

Dim result = xml.<person>.<name>

Debug.WriteLine(result(0).Value) '徳川家康と表示されます。
Debug.WriteLine(result(1).Value) '織田信長と表示されます。

Debug.WriteLine(result.Value) '徳川家康と表示されます。

例外的に添え字なしの Valueプロパティも用意されており、これは先頭の要素のValueプロパティを呼び出します。

子要素があれば、さらにタグをプロパティにように記述することで中の要素のアクセスできます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <persons>
              <person><name>徳川家康</name><age>19</age></person>
              <person><name>織田信長</name><age>30</age></person>
          </persons>

Dim result = xml.<person>

Debug.WriteLine(result(0).<name>.Value) '徳川家康と表示されます。
Debug.WriteLine(result(1).<age>.Value) '30と表示されます。

 

4-2.全子孫の取得

様子がわかってきたところで、もう少し複雑なXMLを扱ってみましょう。

次のXMLにはperson要素が3つ出現しますが、そのうち2つはera要素の子要素であり、もう1つはculture要素の子要素であるという違いがあります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2">藤原道長</person>
                  <culture>
                      <person id="3">清少納言</person>
                  </culture>
              </era>
          </history>

Dim result = xml.<era>.<person>

For Each element In result
    Debug.WriteLine(element.Value)
Next

このプログラムでは xml.<era>.<person> と指定しているので era要素の子要素であるperson要素を取得しており、結果そてい坂上田村麻呂と藤原道長が表示されます。

別の書き方で xml...<person> という表現ができて、この記述をした場合は、親要素を無視してすべてのperson要素を取得します。

次の例では、結果として坂上田村麻呂と藤原道長と清少納言が表示されます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2">藤原道長</person>
                  <culture>
                      <person id="3">清少納言</person>
                  </culture>
              </era>
          </history>

Dim result = xml...<person>

For Each element In result
    Debug.WriteLine(element.Value)
Next

 

4-3.属性の取得

valueプロパティの代わりに、@属性名 という記述を使用すると要素の属性の値を取得できます。

たとえば、次の例では、全person要素を取得してから、それぞれのid属性の値を表示します。結果として1,2,3が出力されます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2">藤原道長</person>
                  <culture>
                      <person id="3">清少納言</person>
                  </culture>
              </era>
          </history>

Dim result = xml...<person>

For Each element In result
    Debug.WriteLine(element.@id)
Next

次の例では最初のera要素のstart属性を取得します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2">藤原道長</person>
                  <culture>
                      <person id="3">清少納言</person>
                  </culture>
              </era>
          </history>

Dim result = xml.<era>.@start

Debug.WriteLine(result) '710と表示されます。

次の例では2番目の era要素を取得し、name属性とstart属性を表示します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2">藤原道長</person>
                  <culture>
                      <person id="3">清少納言</person>
                  </culture>
              </era>
          </history>

Dim era = xml.<era>(1)

Debug.WriteLine(era.@name) '平安時代と表示されます。
Debug.WriteLine(era.@start) '794と表示されます。

属性は Attributeプロパティを使って取得することもできます。

 

5.XMLリテラル内の式

XMLリテラル内には <%= =%> を使用してVisual Basic の式を埋め込むことができます。

次のプログラムでは 1 + 2 が計算され 3 として埋め込まれます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <sample><%= 1 + 2 %></sample>

Debug.WriteLine(xml.ToString)

結果として、<sample>3</sample> と出力されます。

通常のVBの式が使用できるので、変数やいろいろなクラスのメソッドやプロパティを使用することもできます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <env>
              <os><%= Environment.OSVersion.ToString %></os>
          </env>

Debug.WriteLine(xml.ToString)

 

コレクションを埋め込むと合成されて単一の値になります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim list As New List(Of String)({"Apple", "Banana", "Cat", "Dog"})

Dim xml = <data>
              <%= list %>
          </data>

Debug.WriteLine(xml.ToString)

この例を実行すると <data>AppleBananaCatDog</data> と表示されます。

 

コレクションの要素が XElement型の場合は、XMLとしてうまく合成します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim list As New List(Of String)({<item>Apple</item>, <item>Banana</item>, <item>Cat</item>, <item>Dog</item>})

Dim xml = <data>
              <%= list %>
          </data>

Debug.WriteLine(xml.ToString)

この実行結果は次のように出力されます。

<data>
    <item>Apple</item>
    <item>Banana</item>
    <item>Cat</item>
    <item>Dog</item>
</data>

 

この性質を利用してXMLリテラルの式の中でLINQを使ってXElementのコレクションを生成することで、文字列やいろいろなコレクションのオブジェクトをXMLとして表現することができます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim list As New List(Of String)({"Apple", "Banana", "Cat", "Dog"})

Dim xml = <data>
              <%= From item In list Select <Item><%= item %></Item> %>
          </data>

Debug.WriteLine(xml.ToString)

この実行結果は次のように出力されます。

<data>
    <item>Apple</item>
    <item>Banana</item>
    <item>Cat</item>
    <item>Dog</item>
</data>

 

次の例では C:\tempフォルダー内の 全jpgファイルをimgタグに設定したhtmlとして保存します。

このhtmlファイルを開くと画像の一覧が表示できます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <html>
              <head>
                  <title>サンプル画像集</title>
              </head>
              <body>
                  <%= From img In IO.Directory.GetFiles("C:\temp", "*.jpg")
                      Select <img src=<%= img %>></img>
                  %>
              </body>
          </html>

'XMLを拡張子 htm で保存します。
xml.Save("C:\temp\sample.htm")

'保存したhtmをデフォルトのアプリケーションで開きます。
Dim p = New Process
p.StartInfo = New ProcessStartInfo("C:\temp\sample.htm") With {.UseShellExecute = True}
p.Start()

このように生成するHTMLにHTML宣言などをつけることはできませんが、おそらくほとんどのブラウザーで問題なく開けます。

 

6.XMLのクエリ

LINQを使ってXMLを検索することができます。

これまで説明してきた以下の記述方法が使用できます。

xml.<elementA>

xml の子要素である elementA 要素を取得します。

xml...<elementA>

xmlのすべての子孫要素である elementA 要素を取得します。

xml.@attrName

xmlの attrName属性を取得します。

 

次の例では gender属性が 男 であるすべての person要素の値を取得します。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim xml = <history>
              <era name="奈良時代" start="710" end="794">
                  <person id="1" gender="男">坂上田村麻呂</person>
              </era>
              <era name="平安時代" start="794" end="1185">
                  <person id="2" gender="男">藤原道長</person>
                  <culture>
                      <person id="3" gender="女">清少納言</person>
                  </culture>
              </era>
          </history>

Dim persons = From person In xml...<person>
              Where person.@gender = "男"
              Select person.Value

For Each person In persons
    Debug.WriteLine(person)
Next

XMLに対してこのように強力なクエリを簡潔に記述できる汎用言語はVBだけです。

C#等の他の言語の場合は、System.XML名前空間の XmlDocumentクラスなどを使ってXMLを操作することになりますが、XML自体は文字列として扱うしかないのでVBほど効率的には記述できません。VBでもあえてC#と同じことをやりたいのであれば、今回説明した内容ではなくXmlDocumentクラスなどを使ってXMLを扱うこともできます。

 

メモ メモ  - XMLリテラルの活用

ある開発チームが作成したプログラムをレビューしているときに、次のような記述を見つけたことがあります。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

        Dim sql = <sql>
SELECT 
    name, age, address, mail
FROM
    T_USER
    INNER JOIN T_MAIL ON T_USER.user_id = T_MAIL.user_id
WHERE
    deleted = 0
                  </sql>


Dim table As DataTable = ExecuteSql(sql.Value)

つまり、形式上XMLリテラルを使っているけれども、XMLが必要なわけではなく、単に改行付きの長い文字列を記述する手段として使っているということです。

生のSQL文のような長い文字列をソースコード内に記述することを選択した場合は、通常の文字列を使うよりこちらの方が記述しやすいように思えなくもありませんが、どうでしょうか・・・。

通常の文字列より冗長な処理が実行されるので性能的にはベターでないことが明確ですが、頻度の低い処理であれば気になるレベルの速度の差が発生するわけでもありませんし、駄目というわけでは内容にも思います。