LinqToXml簡介3:利用LINQ找到正確的XElement並插入資料

這篇文章,我們來講講怎麼找到之前建立的XML資料,並且對其新增新的XElement。

先確認程式碼與產出的XML資料長成下列這樣:

程式碼:

System.Xml.Linq.XNamespace oXmlNsAAA = "這完全是我亂打的一個字串";
System.Xml.Linq.XNamespace oXmlNsBBB = "http://www.foo.com/";
System.Xml.Linq.XNamespace oXmlNsCCC = "CompanyType";

System.Xml.Linq.XDocument oXml = new System.Xml.Linq.XDocument(
  new System.Xml.Linq.XDeclaration("1.0", "UTF-8", "yes"),
  new System.Xml.Linq.XElement(oXmlNsAAA + "Employees",
    new System.Xml.Linq.XAttribute(System.Xml.Linq.XNamespace.Xmlns + "AAA", "這完全是我亂打的一個字串"),
    new System.Xml.Linq.XAttribute(System.Xml.Linq.XNamespace.Xmlns + "BBB", "http://www.foo.com/"),
    new System.Xml.Linq.XAttribute(System.Xml.Linq.XNamespace.Xmlns + "CCC", "CompanyType"),
    new System.Xml.Linq.XElement(oXmlNsCCC + "Company",
      new System.Xml.Linq.XAttribute("Code", "Taipei"),
      new System.Xml.Linq.XElement(oXmlNsAAA + "Person",
        new System.Xml.Linq.XAttribute(oXmlNsBBB + "ID", "A1234"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Name", "王小明"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Address", "台北市OOO路")
      )
    ),
    new System.Xml.Linq.XElement(oXmlNsCCC + "Company",
      new System.Xml.Linq.XAttribute("Code", "Kaohsiung"),
      new System.Xml.Linq.XElement(oXmlNsAAA + "Person",
        new System.Xml.Linq.XAttribute(oXmlNsBBB + "ID", "A5678"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Name", "李小華"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Address", "高雄市OOO路")
      ),
      new System.Xml.Linq.XElement(oXmlNsAAA + "Person",
        new System.Xml.Linq.XAttribute(oXmlNsBBB + "ID", "B1234"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Name", "陳小英"),
        new System.Xml.Linq.XElement(oXmlNsAAA + "Address", "高雄市XXX路")
      )
    )
  )
);

產出之XML文件:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<AAA:Employees xmlns:AAA="這完全是我亂打的一個字串" xmlns:BBB="http://www.foo.com/" xmlns:CCC="CompanyType">
  <CCC:Company Code="Taipei">
    <AAA:Person BBB:ID="A1234">
      <AAA:Name>王小明</AAA:Name>
      <AAA:Address>台北市OOO路</AAA:Address>
    </AAA:Person>
  </CCC:Company>
  <CCC:Company Code="Kaohsiung">
    <AAA:Person BBB:ID="A5678">
      <AAA:Name>李小華</AAA:Name>
      <AAA:Address>高雄市OOO路</AAA:Address>
    </AAA:Person>
    <AAA:Person BBB:ID="B1234">
      <AAA:Name>陳小英</AAA:Name>
      <AAA:Address>高雄市XXX路</AAA:Address>
    </AAA:Person>
  </CCC:Company>
</AAA:Employees>

接著就是LINQ練習時間

挑出CCC:Company並使其成為一個IEnumerable集合。可以觀察到很有趣的結果,當失去了Employees根元素,XElement會在後續元素被自動賦予有用到命名空間的xmlns用來參考,這個設計很強。

var oCollections = oXml.Root.Elements(oXmlNsCCC + "Company");
[0]
<CCC:Company Code="Taipei" xmlns:CCC="CompanyType">
  <AAA:Person BBB:ID="A1234" xmlns:BBB="http://www.foo.com/" xmlns:AAA="這完全是我亂打的一個字串">
    <AAA:Name>王小明</AAA:Name>
    <AAA:Address>台北市OOO路</AAA:Address>
  </AAA:Person>
</CCC:Company>

[1]
<CCC:Company Code="Kaohsiung" xmlns:CCC="CompanyType">
  <AAA:Person BBB:ID="A5678" xmlns:BBB="http://www.foo.com/" xmlns:AAA="這完全是我亂打的一個字串">
    <AAA:Name>李小華</AAA:Name>
    <AAA:Address>高雄市OOO路</AAA:Address>
  </AAA:Person>
  <AAA:Person BBB:ID="B1234" xmlns:BBB="http://www.foo.com/" xmlns:AAA="這完全是我亂打的一個字串">
    <AAA:Name>陳小英</AAA:Name>
    <AAA:Address>高雄市XXX路</AAA:Address>
  </AAA:Person>
</CCC:Company>

找出在高雄公司的員工,並利用FirstOrDefault返回一個XElement。

var oKaohsiung = oXml.Root.Elements(oXmlNsCCC + "Company").Where(x => x.Attribute("Code").Value == "Kaohsiung").FirstOrDefault();
<CCC:Company Code="Kaohsiung" xmlns:CCC="CompanyType">
  <AAA:Person BBB:ID="A5678" xmlns:BBB="http://www.foo.com/" xmlns:AAA="這完全是我亂打的一個字串">
    <AAA:Name>李小華</AAA:Name>
    <AAA:Address>高雄市OOO路</AAA:Address>
  </AAA:Person>
  <AAA:Person BBB:ID="B1234" xmlns:BBB="http://www.foo.com/" xmlns:AAA="這完全是我亂打的一個字串">
    <AAA:Name>陳小英</AAA:Name>
    <AAA:Address>高雄市XXX路</AAA:Address>
  </AAA:Person>
</CCC:Company>

接續上題,找出在高雄公司的員工中編號為內含1234字串,將其姓名挑出。

var oPerson = oKaohsiung.Elements(oXmlNsAAA + "Person").Where(x => x.Attribute(oXmlNsBBB + "ID").Value.Contains("1234")).Select(x => x.Element(oXmlNsAAA + "Name").Value);
集合裡面只會有一筆資料,就是「陳小英」。

利用LINQ找出XElement目標,對其插入一筆XElement

有了上面的LINQ練習後,對於XDocument的SELECT應該是有一定的熟悉度了,在這邊我們用插入一筆XElement資料作為結束。找出台北公司的XElement,然後再子屬節點中插入一個全新的員工資料(XElement)。

oXml
  .Root
  .Elements(oXmlNsCCC + "Company")
  .Where(x => x.Attribute("Code").Value == "Taipei")
  .FirstOrDefault()
  .Add(
    new System.Xml.Linq.XElement(oXmlNsAAA + "Person",
      new System.Xml.Linq.XAttribute(oXmlNsBBB + "ID", "C7788"),
      new System.Xml.Linq.XElement(oXmlNsAAA + "Name", "郭大頭"),
      new System.Xml.Linq.XElement(oXmlNsAAA + "Address", "高雄市VVV路")
    )
  );

最終XML結果

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<AAA:Employees xmlns:AAA="這完全是我亂打的一個字串" xmlns:BBB="http://www.foo.com/" xmlns:CCC="CompanyType">
  <CCC:Company Code="Taipei">
    <AAA:Person BBB:ID="A1234">
      <AAA:Name>王小明</AAA:Name>
      <AAA:Address>台北市OOO路</AAA:Address>
    </AAA:Person>
    <AAA:Person BBB:ID="C7788">
      <AAA:Name>郭大頭</AAA:Name>
      <AAA:Address>高雄市VVV路</AAA:Address>
    </AAA:Person>
  </CCC:Company>
  <CCC:Company Code="Kaohsiung">
    <AAA:Person BBB:ID="A5678">
      <AAA:Name>李小華</AAA:Name>
      <AAA:Address>高雄市OOO路</AAA:Address>
    </AAA:Person>
    <AAA:Person BBB:ID="B1234">
      <AAA:Name>陳小英</AAA:Name>
      <AAA:Address>高雄市XXX路</AAA:Address>
    </AAA:Person>
  </CCC:Company>
</AAA:Employees>

相關連結

LinqToXml簡介1:建立並儲存XML
LinqToXml簡介2:加入Namespace命名空間
LinqToXml簡介3:利用LINQ找到正確的XElement並插入資料 XmlDocument System.Xml XDocument System.Xml.Linq LambdaExpressions Namespace 名稱空間 命名空間 LinqSelect LinqWhere XElementInsert XElementDelete