2008年9月1日 星期一

Linq to XML: Write NameSpace

Linq to XML 的寫作非常方便。以往要組一個 xml ,都必須從 XmlDocument 開始,現在使用 Linq to XML 就不用了。

範例1:

例如,下列程式碼

      
	//code 1
	XElement el = new XElement("r",
        new XElement("invoice",
          new XElement("invoiceNumber", "AB12345678"),
          new XElement("invoiceDate", DateTime.Now)
          )
        );
產生的 xml 結果如下
<r>
  <invoice>
    <invoiceNumber>AB12345678</invoiceNumber>
    <invoiceDate>2008-09-01T10:08:22.9666505+08:00</invoiceDate>
  </invoice>
</r>

這樣的方式極為簡便。

範例2:


如果要產生 namespace 呢? 以下的程式碼會產生 default namespace

      //code 2
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement(ns + "r",
        new XElement(ns + "invoice",
          new XElement(ns + "invoiceNumber", "AB12345678"),
          new XElement(ns + "invoiceDate", DateTime.Now)
          ));
產生如下的 xml
<r xmlns="http://www.compnay.com.tw/Invoice">
  <invoice>
    <invoiceNumber>AB12345678</invoiceNumber>
    <invoiceDate>2008-09-01T10:16:48.2077244+08:00</invoiceDate>
  </invoice>
</r>

範例3:

也可以使用如下的寫法,但效能會差一些,原因 runtime 要計算用了哪些 namespace。
      //code 3
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement("{http://www.compnay.com.tw/Invoice}r",
        new XElement("{http://www.compnay.com.tw/Invoice}invoice",
          new XElement("{http://www.compnay.com.tw/Invoice}invoiceNumber", "AB12345678"),
          new XElement("{http://www.compnay.com.tw/Invoice}invoiceDate", DateTime.Now)
          )
        );
結果是一樣的
<r xmlns="http://www.compnay.com.tw/Invoice">
  <invoice>
    <invoiceNumber>AB12345678</invoiceNumber>
    <invoiceDate>2008-09-01T10:20:56.8615067+08:00</invoiceDate>
  </invoice>
</r>

這樣的寫法雖然較容易了解,但較不容易修改,我個人不建議這樣的寫法。

範例4:


另外,注意到雖然我們沒有說要寫成 default namespace,但Linq to XML 會「自動」地視狀況修改。
我們可以使用 XAttribute 來使用 namesapce prefix。如下程式碼。

      //code 4 
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement("r",
        new XAttribute(XNamespace.Xmlns + "i", "http://www.compnay.com.tw/Invoice"),
        new XElement("invoice",
          new XElement("invoiceNumber", "AB12345678"),
          new XElement("invoiceDate", DateTime.Now)
          )
        );
結果如下。注意到這樣的方法,可以很方便地產生了一個 namespace prefix i,但卻沒有任何節點使用到這個 prefix
<r xmlns:i="http://www.compnay.com.tw/Invoice">
  <invoice>
    <invoiceNumber>AB12345678</invoiceNumber>
    <invoiceDate>2008-09-01T10:27:11.773833+08:00</invoiceDate>
  </invoice>
</r>

範例5:

使用下面的程式碼,就不難了解 xml namespace 的特殊

      //code 5
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement("r",
        new XAttribute(XNamespace.Xmlns + "i", "http://www.compnay.com.tw/Invoice"),
        new XElement("{i}invoice",
          new XElement("invoiceNumber", "AB12345678"),
          new XElement("invoiceDate", DateTime.Now)
          )
        );
產生的xml 如下。xml:i="http:....." 這個 namespace 宣告了,卻沒有任何節點使用。i 是一個 namespace 的值,是inovice節點的 default namespace。invoiceNumber 與 invoiceDate的 namespace 卻是 ""。一個簡單的xml,卻有三個 namespace,基本上是錯誤的設計。
<r xmlns:i="http://www.compnay.com.tw/Invoice">
  <invoice xmlns="i">
    <invoiceNumber xmlns="">AB12345678</invoiceNumber>
    <invoiceDate xmlns="">2008-09-01T11:02:47.1886207+08:00</invoiceDate>
  </invoice>
</r>

範例6:

如果要像 code 2,產生相同的結果,但不要每一個節點使用 ns + "xxx"這樣的方式可不可以呢?如下的程式碼會發生錯誤

    //code 6, fails
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement("r",
        new XAttribute("xmlns", "http://www.compnay.com.tw/Invoice"),
        new XElement("invoice",
          new XElement("invoiceNumber", "AB12345678"),
          new XElement("invoiceDate", DateTime.Now)
          )
          );

錯誤的訊息為 Unhandled Exception: System.Xml.XmlException: The prefix '' cannot be redefined from '' to 'http://www.compnay.com.tw/Invoice' within the same start element tag. 看來,沒有一個好的方法,將其他的節點批次地設為 default namespace了。必須每一個節點都如 code 2 一般,將每一個節點,一個個設 namespace。也沒有辦法設哪一個 namespace 為 default namespace。

範例7:


最後的範例,是 prefix namespace, 請與範例2 對照

//code 7 
      XNamespace ns = "http://www.compnay.com.tw/Invoice";
      XElement el = new XElement(ns + "r",
        new XAttribute(XNamespace.Xmlns + "i", ns),
        new XElement(ns + "invoice",
          new XElement(ns + "invoiceNumber", "AB12345678"),
          new XElement(ns + "invoiceDate", DateTime.Now)
          )
          );
產生的 xml 結果如下
<i:r xmlns:i="http://www.compnay.com.tw/Invoice">
  <i:invoice>
    <i:invoiceNumber>AB12345678</i:invoiceNumber>
    <i:invoiceDate>2008-09-02T08:52:11.4240786+08:00</i:invoiceDate>
  </i:invoice>
</i:r>

沒有留言:

Share with Facebook