プログラミング言語とネームスペース(3)

.netでVBを使う例です.最初はXPathを使用する例です.

Imports System.Xml
Imports System.Xml.XPath

Module XPath2
    Sub Main()
        Dim xpDoc As XPathDocument = New XPathDocument("MusicLibraryNS.xml")
        Dim xpNav As XPathNavigator = xpDoc.CreateNavigator()
        Dim nt As NameTable = New NameTable
        Dim nsm As XmlNamespaceManager = New XmlNamespaceManager(nt)
        nsm.AddNamespace("mlp", "uri:music:library")
        nsm.AddNamespace("cdp", "uri:music:cd")
        nsm.AddNamespace("ttlp", "uri:music:title")
        Dim xpExp As String = "/mlp:musicLibrary/cdp:cd[string(mlp:year) = '1994']/ttlp:title"
        Dim xpNodeIter As XPathNodeIterator = xpNav.Select(xpExp, nsm)
        For Each title As XPathNavigator In xpNodeIter
            Console.WriteLine("The title is '{0}'", title.Value)
        Next
    End Sub
End Module

VBで書くときはNamespaceManagerに、XPathで使用するネームスペースプレフィックスとネームスペースを登録して、それをXPathNavigatorクラスのSelectメソッドにXPathと一緒に指定してやります.Javaより超簡単で素直ですね.あとXPathNavigatorクラスはValueメソッドがあって、string値を一発で持ってこれるところもやはり魅力です.

このプログラムで、恒例のごとく以下のように出てくれます.

イメージ 1


それではこれをLinqでやったらどうなるでしょうか?VBではここで、あっと驚くネームスペースの宣言とLinq式の記述が出来ちゃいます.

Imports System.Xml.Linq
Imports System.Xml.XPath.Extensions
Imports System.Text.RegularExpressions.Regex
Imports <xmlns:mlp="uri:music:library">
Imports <xmlns:cdp="uri:music:cd">
Imports <xmlns:ttlp="uri:music:title">

Module Linq2
    Sub Main()
        Dim xd As XDocument = XDocument.Load("MusicLibraryNS.xml")
        Dim titles1 As IEnumerable(Of XElement) = _
            From title In xd.<mlp:musicLibrary>.<cdp:cd>.<ttlp:title> _
            Where title.Ancestors().ElementAt(0).<mlp:year>.Value = "1994" _
            Select title
        For Each title As XElement In titles1
            Console.WriteLine("The title is '{0}'", title.Value)
        Next
    End Sub
End Module

なんとVBではImportステートメントXMLの記法そのままにネームスペースの宣言が書けてしまいます.そして、Linq式もそのネームスペースプリフィックスを使用してXMLライクな記法で直感的に書けます.これは他の言語にはない機能ですね.VBをバカにする(自称プロの)人が居ますけれど、なかなかどうしてVBはすごく進化していると思います.

あとこのようなLinqの書き方はイマイチという人のために次のようにも書けます.でもこちらはすこし冗長です.

Imports System.Xml.Linq
Imports System.Xml.XPath.Extensions
Imports System.Text.RegularExpressions.Regex
Imports <xmlns:mlp="uri:music:library">
Imports <xmlns:cdp="uri:music:cd">
Imports <xmlns:ttlp="uri:music:title">

Module Linq2
    Sub Main()
        Dim xd As XDocument = XDocument.Load("MusicLibraryNS.xml")
        Dim mlns As XNamespace = GetXmlNamespace(mlp)
        Dim cdns As XNamespace = GetXmlNamespace(cdp)
        Dim ttlns As XNamespace = GetXmlNamespace(ttlp)
        Dim titles2 As IEnumerable(Of XElement) = _
            From title In xd.Element(mlns + "musicLibrary").Elements(cdns + "cd").Elements(ttlns + "title") _
            Where title.Ancestors().ElementAt(0).Element(mlns + "year").Value = "1994" _
            Select title
        For Each title As XElement In titles2
            Console.WriteLine("The title is '{0}'", title.Value)
        Next
    End Sub
End Module

また次のようにも書けます.

Dim titles3 As IEnumerable(Of XElement) = _
    xd.Element(mlns + "musicLibrary").
    Elements(cdns + "cd").
    Where(Function(cd) cd.Element(mlns + "year").Value.Equals("1994")).
    Elements(ttlns + "title")
For Each title As XElement In titles3
    Console.WriteLine("The title is '{0}'", title.Value)
Next

あとほとんど変わりませんが次ではF#の例を紹介します.