2011年11月27日 星期日

前端處理JSON資料與陣列 - 使用 LINQ to JavaScript (1)


在上一篇「前端處理JSON資料 - 轉為陣列以及簡單篩選」說明了如何使用 $.grep() 方法在前端程式中去篩選陣列中的資料,

但是如果要處理的篩選條件是比較複雜時,使用 $.grep() 依然是可行,但總會任人覺得不是那麼方便,

尤其是寫 C# 的開發者在 .NET Framework 3.5 之後對於集合資料的操作已經熟悉並且習慣了 LINQ 語法,

而在前端程式中卻沒有這樣方便的處理方式,在處理集合資料時就會覺得綁手綁腳的,

其實這情形早已經有人做了一個解決方案,「LINQ to JavaScript」( 簡稱為 JSLINQ ),

在2009年的時候在MSDN學習園地的CodePlex教學中就有對這個函式庫做介紹「LINQ to JavaScript: 在 JavsScript 也可以用 LINQ

接下來就來說明一下使用的方式。


LINQ to JavaScript (JSLINQ)

網址:http://jslinq.codeplex.com/

下載:http://jslinq.codeplex.com/releases/view/28886

目前的版本是 v2.10 , 2009年6月16日發佈

 

下載「JSLINQ_v2.10_SourcePlusExamples.zip」檔案並解壓縮,

image

如果想要馬上了解JSLINQ有什麼樣的功能以及可以做到什麼樣的操作,可以馬上看「Samples.htm

image

針對JSLINQ裡面每一種方法的操作做詳盡的說明,而JSLINQ也有提供完整的Sample Unit Tests「TestSamples.htm

image

而最重要的就是JSLINQ的函式庫本身,在「scripts」目錄中有三個檔案:JSLINQ.js, JSLINQ-vsdoc.js, Samples.js

image

其中Samples.js就是Sample的前端程式,包含了範例資料以及執行程式本身還有單元測試的程式,

我覺得這個Samples.js相當重要,因為裡面有相當詳盡的程式操作方法,甚至是前端程式的單元測試寫法可以作為參考,

如果說當使用JSLINQ遇到問題時,可以開啟 Samples.js 來查閱程式內容,就應該可以略知一二。

 

而「JSLINQ.js」就是函式庫本身,這是最重要的檔案,而使用上只要將檔案加入到專案並且include之後就可以使用,

「JSLINQ-vsdoc.js」這個檔案對於使用Visual Studio進行開發的程式人員也是相當重要,

因為只要在在網頁中或是檔案中參照這個檔案,在Visual Studio裡面出現智能顯示 ,

 

ASP.NET MVC 3 Razor ViewPage中加入 vsdoc的方式

image

獨立的JS檔案中加入 vsdoc 的方式

image

這邊提供一個簡單的方式在獨立JS檔案快速加入reference的方法,

首先在方案總管中選定你要加入參考的JS檔案

image

選定之後,按住滑鼠的左鍵不放,並且直接拖曳到已開啟的JS檔案裡,然後放開,就會自動加入一段reference的語法

image

image

PS.

記得在加入參考之後一定要更新 JScript Intellisense,更新的快捷鍵是「CTRL + SHIFT + J」如此才能正確顯示Intellisense。

image

 

如何使用並顯示JSLINQ的Intellisense

這地方要特別說明一下,不然很多人一定會發生跟我一樣的狀況,就是語法使用都正確,但怎麼試就是無法顯示Intellisense,

原本JSLINQ的操作方式

image

假如要接著繼續使用JSLINQ的方法,卻無法顯示Intellisense…

image

 

而在Readme.txt文件檔案中也說到,除了原本建立instance的方法:

var option1 = JSLINQ(myArray);

也另外提供了另一組建立instance的方法:

var option2 = new JSLINQ(myArray);

 

所以我們就用另外的建立instance的方式,

image

並且接著看看會不會顯示JSLINQ的Intellisense…

image

Done!可以正常顯示JSLINQ的Intellesense啦!這樣就方便我們編寫使用JSLINQ的前端程式了…

 

JSLINQ有哪些方法

我們在Visual Studio中透過Javascript Parser來看看JSLINQ有提供哪些方法,

image

JSLINQ提供了19個方法(從Where開始一直到最後的LastOrDefault),這些基本的方法就如同在.NET中使用LINQ是一樣的。

 

使用 JSLINQ

接下來我們直接使用JSLINQ Sample中的測試資料來做個簡單操作,

image

 

情境一:我們要取出FirstName是「Chris」的資料
$(document).ready(function ()
{
    var result = "";
 
    var test = new JSLINQ(Samples.People)
        .Where(function (item) { return item.FirstName == "Chris"; })
        .Select(function (item) { result += item.ID + "|" + item.FirstName + " " + item.LastName + "<br/>"; });
 
    $('#ResultContent').html(result);
 
});

執行結果:

image

 

情境二:取出FirstName中有包含「s」或「S」的資料(記住!大小有區分喔)
$(document).ready(function ()
{
    var result = "";
 
    var test = new JSLINQ(Samples.People)
        .Where(function (item)
        {
            return item.FirstName.indexOf("S") >= 0 || item.FirstName.indexOf("s") >= 0
        })
        .Select(function (item) { result += item.ID + "|" + item.FirstName + " " + item.LastName + "<br/>"; });
 
    $('#ResultContent').html(result);
 
});

執行結果:

image

 

情境三:取出BookIDs中含有「1001」的資料(這個就比較進階,集合中再去對資料內的集合進行篩選)
$(document).ready(function ()
{
    var result = "";
 
    var test = new JSLINQ(Samples.People)
        .Where(function (item)
        {
            return new JSLINQ(item.BookIDs).Count(function (inner) { return inner == 1001 }) > 0
        })
        .Select(function (item) { result += item.ID + "|" + item.FirstName + " " + item.LastName + "|" + item.BookIDs + "<br/>"; });
 
    $('#ResultContent').html(result);
 
});

執行結果:

image

 

基本的情境說明就到此為止,如果要詳加了解JSLINQ各個方法的操作可以仔細研究 Sample.htm 以及 Sample.js並且多做練習,相信就會對JSLINQ輕鬆上手。

 

JSON資料轉陣列後使用JSLINQ進行操作

延續上一篇「前端處理JSON資料 - 轉為陣列以及簡單篩選」的資料來做演練,使用JSLINQ來做資料的篩選

原始取得的資料:

image

假定我們要取得CategoryID是「1」的Product出來,使用JSLINQ的寫法如下:

function UseJSLinq()
{
    var result = GetData(ActionUrls.GetProducts);
 
    var details = "<hr/>";
 
    var currentData = JSLINQ(result)
        .Where(function(item) { return item.CategoryID == "1"; })
        .Select(function(item)
        { 
            details += item.ProductID + "|" + item.ProductName + "|"  + item.CategoryID + "|" + item.CategoryName + "|"+ item.SupplierID + "|"+ item.CompanyName + "|" + "<br/>"; 
        });
 
    $('#Products').html(details);
}

執行的結果:

image

 

在上面的各個範例當中,我們都是最後在Select()或是Count()當中的方法進行資料的最終處理,

但如果說我們使用JSLINQ篩選後的資料還不需要馬上做最後處理(如顯示的處理),或許還要對篩選的資料再進行加工,

此時我們可以用以下的方法來操作:

function UseJSLinq2()
{
    var result = GetData(ActionUrls.GetProducts);
 
    var currentData = JSLINQ(result)
        .Where(function(item) { return item.CategoryID == "1"; })
        .Select(function(item){ return item;});
 
    var details = currentData.items.length + "<hr/>";
 
    $.each(currentData.items, function(index, item)
    {
        details += item.ProductID + "|" + item.ProductName + "|"  + item.CategoryID + "|" + item.CategoryName + "|"+ item.SupplierID + "|"+ item.CompanyName + "|" + "<br/>";  
    });
 
    $('#Products').html(details);
}

執行的結果:

image

一定有人覺得這兩個方法除了說多了一個Count資料外,還有什麼地方式不同的嗎?

第一個方法:

var currentData = JSLINQ(result)
  .Where(function(item) { return item.CategoryID == "1"; })
  .Select(function(item)
  { 
    details += item.ProductID + "|" + item.ProductName + "|"  + item.CategoryID + "|" + item.CategoryName + "|"+ item.SupplierID + "|"+ item.CompanyName + "|" + "<br/>"; 
  });

第二個方法:

var currentData = JSLINQ(result)
  .Where(function(item) { return item.CategoryID == "1"; })
  .Select(function(item){ return item;});

 

第一個方法是直接在JSLINQ的Select()方法中把要顯示的資料給處理好,第二個方法則只是單純的將資料給返回,

但是第二個方法對於經過JSLINQ處理後返回的資料處理是有個地方需要特別提醒,

那就是不能直接對返回的資料做處理,像第二個方法所返回的資料是放在 currentData 中,

如果是直接對 currentData 做處理的話,就會有以下的結果:

image

用Firebug進行中斷偵錯來了解一下 currentData 裡面的情況,

image

這麼看就很清楚了,因為經由JSLINQ處理後所返回的資料集合,會放在 items 中,所以無法直接對 currentDate 做處理,

而是需要對 currentData.items 做處理。

所以再看一次第二個方法:

function UseJSLinq2()
{
    var result = GetData(ActionUrls.GetProducts);
 
    var currentData = JSLINQ(result)
        .Where(function(item) { return item.CategoryID == "1"; })
        .Select(function(item){ return item;});
 
    var details = currentData.items.length + "<hr/>";
 
    $.each(currentData.items, function(index, item)
    {
        details += item.ProductID + "|" + item.ProductName + "|"  + item.CategoryID + "|" + item.CategoryName + "|"+ item.SupplierID + "|"+ item.CompanyName + "|" + "<br/>";  
    });
 
    $('#Products').html(details);
}

針對 currentData.items 做處理,而不是對 currentData 本身,要特別注意這個小地方的不同。

 

補遺:使用ToArray()方法

發佈文章後再一次Review文章內容,然後發現到JSLINQ有提供一個方法:ToArray()

看來這應該是把JSLINQ處理後的資料中items的部份給提出,看看原始碼的內容:

image

果不其然……這就是我沒有仔細看原始碼的後果,天真的以為JSLINQ忘記要做這個步驟,

所以我們就可以使用ToArray()方法將JSLINQ處理後的items給取出來使用,

那前面的那一段程式碼就可以改成下面的內容:

function UseJSLinq3()
{
  var result = GetData(ActionUrls.GetProducts);
  var currentData = new JSLINQ(result)
    .Where(function(item) { return item.CategoryID == "1"; })
    .Select(function(item){ return item;})
    .ToArray();
  var details = currentData.length + "<hr/>";
  $.each(currentData, function(index, item)
  {
    details += item.ProductID + "|" + item.ProductName + "|"  + item.CategoryID + "|" + item.CategoryName + "|"+ item.SupplierID + "|"+ item.CompanyName + "|" + "<br/>";  
  });
  $('#Products').html(details);
}

而最後的執行結果就如直接拿currentData.items的執行結果是相同的:

image

補上並且更正原本文章內容的缺漏與錯誤。

 

以上就是對LINQ to JavaScript(JSLINQ)的一些簡單的說明以及操作示範,

透過JSLINQ的操作讓我們可以在開發前程式的時候繼續使用LINQ相同觀念的方式來操作集合資料。

 

參考連結:

CodePlex – LINQ to JavaScript

MSDN CodePlex教學 - LINQ to JavaScript: 在 JavsScript 也可以用 LINQ

 

以上

2 則留言:

  1. 另一款類似的LinqJs最後更新日期比較新
    http://linqjs.codeplex.com

    回覆刪除
  2. 有關Linq.js也會在之後介紹,
    目前的前端語言使用類似Linq語法操作,好像SQLike與linq.js這兩種比較完整

    回覆刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。