<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      LINQ之路21:LINQ to XML之生成X-DOM(Projecting)

      到目前為止,我們已經討論了如何使用LINQ從一個X-DOM中獲取數據。其實,我們同樣可以使用LINQ查詢來生成一個X-DOM。數據源可以是支持LINQ查詢的任何數據,比如:

      • LINQ to SQL或 Entity Framework查詢
      • 本地集合
      • 另外一個X-DOM

      不管是何種數據源,使用LINQ來產生X-DOM的策略都是一樣的:首先寫出產生目標X-DOM的函數式構造表達式,然后針對該表達式創建LINQ查詢。

      比如,假設我們想從數據庫中獲取customers并產生如下XML:

          <customers>
      <customer id="1">
      <name>Sue</name>
      <buys>3</buys>
      </customer>
      ...
      </customers>

      我們首先為X-DOM寫出函數式構造表達式(這里用簡單的字符串值):

                  var customers =
      new XElement("customers",
      new XElement("customer", new XAttribute("id", 1),
      new XElement("name", "Sue"),
      new XElement("buys", 3)
      )
      );

      然后我們我們把它放入數據轉換之中,創建出針對該表達式的LINQ查詢:

                  var customers =
      new XElement("customers",
      from c in dataContext.Customers
      select
      new XElement("customer", new XAttribute("id", c.ID),
      new XElement("name", c.Name),
      new XElement("buys", c.Purchases.Count)
      )
      );

      這里是其結果XML:

          <customers>
      <customer id="1">
      <name>Tom</name>
      <buys>3</buys>
      </customer>
      <customer id="2">
      <name>Harry</name>
      <buys>2</buys>
      </customer>
      ...
      </customers>

      通過把上面查詢的創建分成兩步,我們可以更清楚地理解它的工作方式:

      第一步:

                  // 創建一個普通的LINQ to SQL查詢,產生一個XElement sequence
      IEnumerable<XElement> sqlQuery =
      from c in dataContext.Customers
      select
      new XElement("customer", new XAttribute("id", c.ID),
      new XElement("name", c.Name),
      new XElement("buys", c.Purchases.Count)
      );

      第二步:

                  // 創建根元素customers
      var customers = new XElement("customers", sqlQuery);

      唯一不同尋常的事情是內容參數sqlQuery,它不是一個簡單的XElement,而是IQueryable<XElement>(實現了IEnumerable<XElement>)。還記得X-DOM處理XML內容的過程嗎?記住,它會自動遍歷實現了IEnumerable的集合。所以,每個XElement都被作為一個子節點被添加到customers元素下。

      排除空元素

      假如在上面的例子中,我們還想把customer最新的大額purchase包含進來,那么我們可以創建如下查詢:

                  var customers =
      new XElement("customers",
      from c in dataContext.Customers
      let lastBigBuy = (from p in c.Purchases // 子查詢獲取最新的大額訂單
      where p.Price > 1000
      orderby p.Date descending
      select p).FirstOrDefault()
      select
      new XElement("customer", new XAttribute("id", c.ID),
      new XElement("name", c.Name),
      new XElement("buys", c.Purchases.Count),
      new XElement("lastBigBuy",
      new XElement("description",
      lastBigBuy == null ? null : lastBigBuy.Description),
      new XElement("price",
      lastBigBuy == null ? 0m : lastBigBuy.Price)
      )
      )
      );

      當customer沒有大額訂單時,上面的查詢會產生空的lastBigBuy元素。其實在這種情況下,更好的解決方案是完全忽略lastBigBuy節點。我們可以通過把lastBigBuy元素的構造函數包裝在條件運算符中來實現這一目的:

                          select
      new XElement ("customer", new XAttribute ("id", c.ID),
      new XElement ("name", c.Name),
      new XElement ("buys", c.Purchases.Count),
      lastBigBuy == null ? null :
      new XElement ("lastBigBuy",
      new XElement ("description", lastBigBuy.Description),
      new XElement ("price", lastBigBuy.Price)
      )
      )

      對于沒有lastBigBuy的customers,查詢會產生null而不是空的XElement。這正是我們想要的,因為null會被X-DOM簡單的忽略掉。

      Stream類型元素

      如果我們僅是為了保存(或調用ToString)的目的來產生X-DOM,那么我們可以通過XStreamingElement來改善內存的使用效率。一個XStreamingElement相當于XElement的簡化版本,并且它對子節點應用延遲加載語義。

      使用它時,簡單的把外層XElements替換成XStreamingElements即可:

                  var customers =
      new XStreamingElement("customers",
      from c in dataContext.Customers
      select
      new XStreamingElement("customer", new XAttribute("id", c.ID),
      new XElement("name", c.Name),
      new XElement("buys", c.Purchases.Count)
      )
      );
      customers.Save("data.xml");

      直到我們調用Save、ToString或WriteTo方法時,傳入XStreamingElement構造函數的查詢才會真正被執行。這樣就避免了立即把整個X-DOM裝載到內存之中。當然另一方面,如果我們多次調用Save,查詢也會被重復執行。還有,我們不能遍歷XStreamingElement的子節點,它沒有提供諸如Elements或Attributes之類的成員。

      XStreamingElement不是從XObject(或是其它類)繼承而來,它僅有的成員除了Save、ToString和 WriteTo,就是Add方法了,Add方法用于向它添加子節點等內容。

      轉換X-DOM

      我們可以對現有的X-DOM進行轉換。比如,C#編譯器和Visual Studio為了描述一個項目,會創建相應的XML文件,該文件會類似以下格式:

          <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/dev...>"
      <PropertyGroup
      >
      <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
      <ProductVersion>9.0.11209</ProductVersion>
      ...
      </PropertyGroup>
      <ItemGroup>
      <Compile Include="ObjectGraph.cs" />
      <Compile Include="Program.cs" />
      <Compile Include="Properties\AssemblyInfo.cs" />
      <Compile Include="Tests\Aggregation.cs" />
      <Compile Include="Tests\Advanced\RecursiveXml.cs" />
      </ItemGroup>
      <ItemGroup>
      ...
      </ItemGroup>
      ...
      </Project>

      假如我們現在相對該XML文件進行簡化,創建一個只包含相關文件的Report,如下所示:

          <ProjectReport>
      <File>ObjectGraph.cs</File>
      <File>Program.cs</File>
      <File>Properties\AssemblyInfo.cs</File>
      <File>Tests\Aggregation.cs</File>
      <File>Tests\Advanced\RecursiveXml.cs</File>
      </ProjectReport>

      下面的查詢可以完成該項轉換:

                  XElement project = XElement.Load("myProjectFile.csproj");
      XNamespace ns = project.Name.Namespace; // 獲取Namespace
      var query =
      new XElement("ProjectReport",
      from compileItem in
      project.Elements(ns + "ItemGroup").Elements(ns + "Compile") // 獲取所有的Compile元素
      let include = compileItem.Attribute("Include") // 獲取Include屬性
      where include != null
      select new XElement("File", include.Value) // 轉換X-DOM,創建新的File元素
      );

      查詢首先獲取所有的ItemGroup元素,然后使用Elements擴展方法獲取所有的Compile子元素(結果位于一個平展的sequence之中)。需要注意的是,我們必須指定一個XML命名空間,因為源文件中的所有節點都繼承了定義在Project元素上的命名空間,所以單憑一個本地的元素名稱如ItemGroup是不夠的。之后,我們根據Include屬性創建新的元素。

      高級轉換

      但我們對一個本地集合如X-DOM進行查詢時,我們可以通過自定義的查詢運算符來創建更加復雜的查詢,完成更加高級的功能。

      假如在前面的例子中,我們想要的是一個按目錄分組的層次輸出,如下:

          <Project>
      <File>ObjectGraph.cs</File>
      <File>Program.cs</File>
      <Folder name="Properties">
      <File>AssemblyInfo.cs</File>
      </Folder>
      <Folder name="Tests">
      <File>Aggregation.cs</File>
      <Folder name="Advanced">
      <File>RecursiveXml.cs</File>
      </Folder>
      </Folder>
      </Project>

      產生這樣的結果,我們需要遞歸的處理路徑字符串如: Tests\Advanced\RecursiveXml.cs。下面的方法可以完成這項工作:它接收一個路徑sequence,產生我們期望的X-DOM層次結果級:

              static IEnumerable<XElement> ExpandPaths(IEnumerable<string> paths)
      {
      var brokenUp = from path in paths
      let split = path.Split(new char[] { '\\' }, 2)
      orderby split[0]
      select new
      {
      name = split[0],
      remainder = split.ElementAtOrDefault(1)
      };

      IEnumerable<XElement> files = from b in brokenUp
      where b.remainder == null
      select new XElement("file", b.name);
      IEnumerable<XElement> folders = from b in brokenUp
      where b.remainder != null
      group b.remainder by b.name into grp
      select new XElement("folder",
      new XAttribute("name", grp.Key),
      ExpandPaths(grp)
      );

      return files.Concat(folders);
      }

      上面的方法中,第一個查詢以第一個反斜線符號把路徑分為兩部分:name + remainder。比如:Tests\Advanced\RecursiveXml.cs到Tests + Advanced\RecursiveXml.cs。如果remainder為null,則name就是一個文件,files查詢會把它裝載到files sequence。如果remainder不為null,name就是一個folder,folders查詢會處理這種情況。因為其它文件可能也位于相同的目錄中,我們必須按目錄名來進行分組。對每一個分組,會遞歸調用該方法來處理子元素。

      最終的結果是包含了所有文件和目錄的sequence。Concat運算符會保持元素的順序,所以所有的文件按字母順序排在前面,然后是按字母順序排列的所有目錄。

      有了這個方法,我們可以通過兩步來完成我們的查詢。首先,獲取所有的文件路徑:

                  IEnumerable<string> paths =
      from compileItem in
      project.Elements(ns + "ItemGroup").Elements(ns + "Compile")
      let include = compileItem.Attribute("Include")
      where include != null
      select include.Value;

      然后,在查詢中使用ExpandPaths方法來獲得最終結果:

                  var query = new XElement("Project", ExpandPaths(paths));

      至此,LINQ之路系列博客已經接近完成了。從開始的LINQ介紹到C#3.0的語言特性;從LINQ方法語法到查詢表達式語法;從延遲執行到子查詢;從解釋查詢到LINQ to SQL/Entity Framework;從各個查詢運算符到LINQ to XML。共計21篇博客,前后歷時將近2個月,好漫長的過程,真心感謝各位園友的大力支持和陪伴!稍后,會為大家奉上系列博客后記和全篇博客導航。

      posted @ 2011-12-13 11:06  Life a Poem  閱讀(3561)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 久久成人国产精品免费软件| 国产精品∧v在线观看| 乱女乱妇熟女熟妇综合网| 婷婷成人丁香五月综合激情| 少妇伦子伦精品无吗| 久久道精品一区二区三区| 久久天天躁狠狠躁夜夜婷| 午夜国产小视频| 97精品尹人久久大香线蕉| 人妻精品动漫h无码| 亚洲精品天堂在线观看| 重口SM一区二区三区视频| 精品国产av一区二区果冻传媒| 国产一区二区三区十八禁| 美女一区二区三区在线观看视频| 天堂中文8资源在线8| 亚欧美闷骚院| 国产精品无码成人午夜电影| 色狠狠综合天天综合综合| 乌兰察布市| 国产欧美精品一区二区三区-老狼| 欧美高清freexxxx性| 无码人妻一区二区三区兔费| 精品人妻大屁股白浆无码| 极品美女自拍偷精品视频| 国产区精品福利在线熟女| 强奷乱码中文字幕| 欧美性受xxxx黑人猛交| 狠狠躁夜夜躁无码中文字幕| 日韩丝袜亚洲国产欧美一区| 99久久婷婷国产综合精品青草漫画| 国产精品人妻一码二码尿失禁 | 日韩 高清 无码 人妻| 亚洲AV成人片在线观看| 深夜福利国产精品中文字幕| 亚洲一区二区经典在线播放| 南和县| 人人爽人人澡人人人妻| 欧美日韩精品一区二区三区高清视频| 精品亚洲一区二区三区在线播放 | 色琪琪丁香婷婷综合久久|