linq.js ver 1.1.0.0 - Linq to Xml for JavaScript

linq.js - LINQ for JavaScript Library - Home

linq.xml.jsとしてver 0.0.0.1を同梱しました。更新系はほとんど未実装ですが、抽出系のメソッドで主要なものは動いているので、お試しぐらいには使えると思います。linq.xml.jsなしで書くとしたら、ああ、ここでfor回して、ああ、ここで再帰書いて、もう! 面倒くさい面倒くさい、と思ってしまうわけなので素の状態と比べたらとっても役立ちです。

サンプルとしてTwitterビューアを同梱しました。AttachEventをつけた結果、限りなくAjaxライブラリな状態になってしまいました。まあ、この辺はオマケみたいなもので、基本的には抽出->加工がメイン、なはずです。あとドメイン間の通信は当然出来ないので、IEの場合はインターネットオプション→セキリティ→レベルカスタマイズ→ドメイン間データソースアクセスを有効にしてください。Firefoxでのやり方は分かりません。ただのデモで実用的なものでもないので、IEで見ていただければと思います。サンプルなので、チュートリアルがわりに解説します。

// window.onload時に動く関数を登録する
X.Initialize(function()
{
    // ボタンを特定して、クリックイベントを登録する
    X.ID("description")
        .Elements("input")
        .Where("$.Attribute('type').Value()=='button'")
        .Single()
        .AttachEvent("click", UpdatePanelFromTwitter);
});

function UpdatePanelFromTwitter()
{
    var twitterBasePath = "https://twitter.com/statuses/user_timeline/";
    var placeHolder = X.ID("placeHolder"); // IDからXElementを取得
    placeHolder.SetValue("Loading..."); // Element以下の要素を消去してテキストを追加
    var userID = X.ID("userID").Attribute("value").Value(); // UserIDを属性から取得

    // 非同期でXML読み込み
    X.Load(twitterBasePath + userID + ".xml", function(rootXml)
    {
        placeHolder.RemoveNodes(); // Loading表記を削除
        rootXml.Descendants("status").Select(function(xEle) // XMLからオブジェクトにマッピング
        {
            return {
                created_at: xEle.Element("created_at").Value(),
                id: xEle.Element("id").Value(parseInt),
                text: xEle.Element("text").Value()
            }
        }).ForEach(function(obj) // そのオブジェクトを使ってforeach
        {
            var elem = X.CreateHTMLElement("p");
            elem.Add(obj.id + " : " + obj.created_at);
            elem.Add(X.CreateHTMLElement("br"));
            elem.Add(obj.text);
            placeHolder.Add(elem);
        })
    });
}
<body>
    <div id="description">
        TwitterID:<input type="text" id="userID" value="" /><input type="button" value="Refresh" />
    </div>
    <div id="placeHolder">
    </div>
</body>

X.Initializeはwindow.onloadに対するイベント登録です。こういう、Linq to Xmlとは全く関係ないメソッドは入れたくなかったのですが、やむをえず。最初はX.Body()でdocument.bodyが取れるので、それにたいしてAttachEventでいいかなーと思ったのですが、ヘッダ内だとbodyがまだ生成されていないのでイベント登録できなくて、特例的にこのメソッドを作りました。

そして、登録するものはボタンを押した時に発生するイベントの登録用関数。わざわざdescriptionから辿っていますが、IDが振ってあればX.ID()でダイレクトに取れます。やっていることはメソッドチェーンの順番通りで、IDが"description"の要素下の -> Element名が"input"の -> Attribute名が"type"で値が"button"である -> 唯一の要素に対し -> イベントを登録。思考の流れ通りの、非常にシンプルで分かりやすい登録方法だと思います。

XMLを読み込んでいるX.Loadですが、これは第一引数がファイルパス、第二引数がコールバック関数になります。第二引数を省略した場合は同期通信になります。例えばvar xml = X.Load("hoge.xml")という使い方が出来るわけです。ローカル環境でテストしたい場合は同期通信のほうを使った方がやりやすいかと思います。

Descendantsは子孫ノードの取得。XMLの要素取得では最も使われるものだと思いますが、ぶっちゃけgetElementsByTagNameです。その次のSelectは射影です、ようするにmapです。Linq to Xmlのキモの部分で、XMLをオブジェクトに変換します。xEleには"status"以下の要素が順番に渡されていくので、それに対してElement("要素名")の値(Value)を取得。といった流れ。Value()には変換関数を渡すことが出来るので、stringじゃなくintにしておきたい、という場合にはparseIntなんかを入れると良いです。

ForEachは、Selectを通って出来たobjectに対してforeachです。今回はpタグのエレメントをつくって挿入してplaceHolderに追加-。ということでした。ここの要素追加のaddは、ようするにappendChildなわけで、本来のLinq to Xmlではもっと洗練された形になっているので修正するつもりです。今は暫定ということで、この形での登録しか出来ません。あとCreateHTMLElementということで、HTMLとXMLを区別しているのも頂けないですね……。ここは統一したやり方で何とかなるよう調整したいと思います。そのうち。

FAQ

  • わざわざjQueryじゃないこんな意味不明粗製ライブラリの使い方を覚える必要あるの?

それ言ったらXPathイラネ、とかE4Xイラネ、とかにも繋がりますし。そんなに比較するようなものじゃないと思います。出来ることの幅も全然違いますし。あくまでこちらはリスト/DOM操作のみです。ただし、リスト/DOM操作でのみ言えばこちらのほうが多くのことがスムーズに出来ると思います。C#のLINQは本当に良く出来てるライブラリだから、というわけで、主な利点はC# Linqの学習ができること、です。中身はともかく表面的な模写としてはわりと忠実なので、C#でも同じ書き方で十分行けます。

  • で?

私が喜びます。Disって欲しいんだって、ほんとうに。0反響よりは100のDis。

  • そもそもlinq.jsって何?

初回リリース時のチュートリアルをどうぞ。

Profile

Yoshifumi Kawai

Cysharp, Inc
CEO/CTO

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

Twitter:@neuecc GitHub:neuecc

Archive