C#とLinq to XmlとXPath

どうも、先人が3年前に通り過ぎた道を今更辿ってる私ですがこんばんわ。そんなことを思うと虚しいので、せいぜい高速道路!高速道路!と叫ぶことで再舗装したいと思っております。ていうかさー、JavaScriptでゆるふわ系でキャッキャウフフだと思ったのに人格に問題あるのは私ですかー、みたいなー。Xbox360並に殺伐。しょうがないので、リハビリC#。そろそろXbox360に戻りたいのですが、プログラミングはスイーツ(笑)なので甘美ですね、ていうかXbox360は殺伐としすぎだろ常識的に考えて。アウトランNAIJとか。

デススマをスルーしてX-BLADEを買う俺カッコイイ、そう思っていた時期なんてありません。でもデススマはスルーしそう。何というかゲーム脳が恐怖で最近のXbox360へのモチベーションのなさは近年なく異常。どのぐらいかというと、ああもうLinq to XmlもJavaScriptに移植したいんだけど時間考えると結構厳しいかもだーあーもう、ぐらいな感じ。一応、今年はXNAに手を出したいそうなんですが手を出せるのかなあ。何かモチベーションがふらついてますねえ。Linq愛は何故か冷めないどころか燃え上がってるのですけど、斜め上方向に突っ走ってる気がしてならない。

興味という点では、モバイル機器にたいして全く興味が沸かなくなってしまったということをつい数時間前に実感した。Windows MobileもiPhoneもAndroidもどうでもいいですよ、だって私、家にずっといるからモバイル機器触る機会が全くないんだもの。それじゃあ関心とか持つの無理だわ。関心持てないものには何のアイディアも沸かない。うん、ダメダメ。興味なんて天の授かり物なんだから、何かが降ってくるのをただ黙って祈るだけです。今のところ、降ってきている関心であるLinqに、今のうちだけだからこそ全力を注ぎたい。力不足でも全力で。3年前の道だろうと全力で。

というわけで、Linq to Xml。実のところ翌々考えてみるとあまり使ったことがなかったので、ちょっと使ってみる。livedoor 天気情報のRSSを引っ張ってくるとして……

var root = XElement.Load("http://weather.livedoor.com/forecast/rss/13/63.xml");
var result = root.Descendants("item")
    .Where(elem => elem.Element("category").Value != "PR")
    .Select(elem => new
    {
        title = elem.Element("title").Value,
        link = elem.Element("link").Value,
        day = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), elem.Element("day").Value),
        description = elem.Element("description").Value,
        pubDate = (DateTime)elem.Element("pubDate"),
        image = Enumerable.Repeat(elem.Element("image"), 1).Select(img => new
        {
            title = img.Element("title").Value,
            link = img.Element("link").Value,
            url = img.Element("url").Value,
            width = (int)img.Element("width"),
            height = (int)img.Element("height")
        }).First()
    });

えー、XmlDocumentー?XmlDocumentが許されるのは小学生までだよねー。というわけでXDocument/XElement。DateTimeやintに直接キャスト出来るんですね!これは地味に超便利、イイ!

この天気予報RSSはimage以下が更に展開できるようになっているようなので、入れ子で。image以下のものに対して毎回「elem.Element("image").Element("title").Value」といったように書くのが面倒くさいので、1回だけのRepeatを使ってSelectを使えるようにしてやって、First()で戻してやる。うーん、どうなんだろう……。クエリ構文だったらletを使うところでしょうか。

まあしかし実のところ、Elementにこだわらず、Elements("image")にすればEnumerable.Repeatなんぞ必要ないのであった。実質1回リピートだから。ただ、どちらにせよFirst()は必須なんだけど。この辺、何ともしっくりこないなあ。

var xDoc = new XmlDocument();
xDoc.Load("http://weather.livedoor.com/forecast/rss/13/63.xml");
var items = xDoc.SelectNodes("//item"); // Descendants
foreach (XmlElement item in items) // varが使えなかったりする
{
    // これがWhereのかわり
    if (item.SelectSingleNode("category").InnerText == "PR") continue;

    // クラス作ってListにAddだと思うのですが、省略
    var temp = new
    {
        title = item.SelectSingleNode("title").InnerText,
        pubDate = DateTime.Parse(item.SelectSingleNode("pubDate").InnerText)
    };
}

比較のためにXmlDocumentでも書いてみた。foreachがとても忌々しく邪悪なものに見える……。あとInnerTextも良くないよねえ。ただ、思っていたほど見た目に違いはなかった。Linq to Xmlでコード超短縮!とか思ってただけに微妙に残念。ようするにXPathがメソッドの形で書けるのがXElement、といった感じなのかなあ。IntelliSenseがガシガシと効くので、XPath的なことを覚える必要がないのは大変良いです。

JavaScriptに移植できるかなあ。でもまあ、素のJavaScriptが恐ろしくXML操作し辛いのは確かなので補助ライブラリがないとやってられないのは確か。XPathすらついてないなんて知らなかった!

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

Microsoft MVP for Developer Technologies(C#)
April 2011
|
July 2023

Twitter:@neuecc GitHub:neuecc

Archive