28323


初歩的な質問ですみません．普段XPathしか使っていません．LINQ to
XMLを使用した場合、次のXPathと同等の結果を得るにはどう書いたら良いのでしょうか？

[code]

    Imports System.Xml
    Imports System.Xml.XPath
    Imports Sgml
    ...
    Dim sgml As SgmlReader = New SgmlReader()
    sgml.DocType = "HTML"
    sgml.Href = "http://www.data.jma.go.jp/obd/stats/data/mdrr/synopday/data1s.html"
    sgml.IgnoreDtd = True
    Dim htmlDoc As XDocument = XDocument.Load(sgml)
    Dim nsTable As NameTable = New NameTable
    Dim nsMgr As XmlNamespaceManager = New XmlNamespaceManager(nsTable)
    nsMgr.AddNamespace("xhtml", "http://www.w3.org/1999/xhtml")
    Dim targetTrs As IEnumerable(Of XElement) = htmlDoc.XPathSelectElements("//xhtml:table[@class = 'o1']//xhtml:tr[@class != 'o1h']", nsMgr)
    
[/code]

気象庁の気象データから地点毎の最高気温を取得しようとしています．このプログラムはなんとか動きましたが、LINQで書けばどうなるのかがよくわかりません．

以上 よろしくお願いします．


CC BY-SA 3.0
2016-08-16T12:54:29.817
28316
2016-08-17T01:11:09.647
2016-08-16T23:19:16.577
4236
9503
question
xml vb.net linq xpath
このXPathはLINQ to XMLならどう書くのでしょうか？


XPathの`//`はXLINQの`Descendants`拡張メソッドに対応します。この場合はXML名前空間が設定されているので`XName`を明示的に作成する必要があります。  
`[]`にはLINQの`Where`を使用し、`XElement.Attribute`メソッドで属性を取得します。

[code]

    Dim d = XDocument.Parse(html)
    
    Dim targetTrs = d.Descendants(XName.Get("table", "http://www.w3.org/1999/xhtml")) _
                         .Where(Function(e) e.Attribute("class")?.Value = "o1") _
                     .Descendants(XName.Get("tr", "http://www.w3.org/1999/xhtml")) _
                         .Where(Function(e) e.Attribute("class")?.Value <> "o1h")
    
[/code]


CC BY-SA 3.0
2016-08-16T14:13:06.987
28319
2016-08-16T14:13:06.987
5750
28316
answer


Visual BasicではXML対応しているため、別の記述が可能です。  
まず、XML名前空間については[Import構文](https://msdn.microsoft.com/ja-
jp/library/bb384589.aspx)で指定可能です。

[code]

    Imports <xmlns:xhtml="http://www.w3.org/1999/xhtml">
    
[/code]

次に`//xhtml:table`については[XML子孫軸プロパティ](https://msdn.microsoft.com/ja-
jp/library/bb384876.aspx)で指定可能です。

[code]

    Dim htmlDoc As XDocument = XDocument.Load(sgml)
    Dim targetTables As IEnumerable(Of XElement) = htmlDoc...<xhtml:table>
    
[/code]

次に`[@class =
'o1']`については`Where`を使えますがその際[XML属性軸プロパティ](https://msdn.microsoft.com/ja-
jp/library/bb384755.aspx)が使えます。

[code]

    Dim targetTables As IEnumerable(Of XElement) = htmlDoc...<xhtml:table> _
        .Where(Function(e) e.@class = "o1")
    
[/code]

最後に[クエリ構文](https://msdn.microsoft.com/ja-
jp/library/bb384830.aspx)を使用することでシンプルになります。

[code]

    Imports <xmlns:xhtml="http://www.w3.org/1999/xhtml">
    ...
    Dim htmlDoc As XDocument = XDocument.Load(sgml)
    Dim targetTrs As IEnumerable(Of XElement) = _
        From table In htmlDoc...<xhtml:table> _
        Where table.@class = "o1" _
        From tr In table...<xhtml:tr> _
        Where tr.@class <> "o1h" _
        Select tr
    
[/code]

* * *

なお、pgrhoさんの回答のXName.Getですが、XML名前空間を別途指定する２引数バージョンの他に、XML名前空間を含むXML名を指定することができる[１引数バージョン](https://msdn.microsoft.com/ja-
jp/library/bb357369\(v=vs.110\).aspx)も存在します。その上で、[文字列からXNameへの暗黙の型キャスト](https://msdn.microsoft.com/ja-
jp/library/system.xml.linq.xname.op_implicit\(v=vs.110\).aspx)も用意されているため

[code]

    d.Descendants("{http://www.w3.org/1999/xhtml}table") _
    ...
    
[/code]

と記述できます。この方法はC#言語でも使用でき便利です。


CC BY-SA 3.0
2016-08-16T23:14:00.020
28323
2016-08-17T01:11:09.647
2016-08-17T01:11:09.647
4236
4236
28316
answer