使用dynamic特性处理XML文档
處理XML文檔是我們經常需要進行的一項工作,尤其是在進行網絡服務相關編程時,比如更新RSS等。在.NET 3.5中引入了Linq To XML,使得XML文檔的讀寫已經大大簡化,而.NET 4.0中最新的dynamic特性,則將簡化發揮到了極致。以處理白云黃鶴的“十大”為例,數據源地址為http://www.byhh.net/posttop10.xml,其當前內容為(為使結果顯示清晰,去掉了其中的鏈接地址字段):
<?xml version="1.0" encoding="gb2312" ?><?xml-stylesheet type="text/xsl" href="/style/blue/xsl/posttop.xsl"?><toppost> <post> <board>WorldSoccer</board> <title>大家支持哪隊? </title> </post> <post> <board>HUSTStudent</board> <title>地震了??? </title> </post> <post> <board>Picture</board> <title>想當二奶的有門路了! </title> </post> <post> <board>Picture</board> <title>輕拍。。。不要太挑剔了 </title> </post> <post> <board>Humor</board> <title>【原創】幾個小humor </title> </post> <post> <board>HUSTStudent</board> <title>院士增選的一個疑問 </title> </post> <post> <board>WorldSoccer</board> <title>臥槽,1:55才開始抽?? </title> </post> <post> <board>WorldSoccer</board> <title>主持MM好靚 </title> </post> <post> <board>TrainFan</board> <title>1000 </title> </post> <post> <board>Movies</board> <title>還是推薦熊貓大俠,早上才十塊錢. </title> </post></toppost>好,我們先不管它的鏈接,僅僅獲取其中的版面名(board)和標題(title)。那么使用Linq To XML,處理方法如下:
var doc = XDocument.Load ("http://www.byhh.net/posttop10.xml");foreach (var post in doc.Element ("toppost").Elements ("post")){ Console.WriteLine ("版面:" + post.Element ("board").Value); Console.WriteLine ("標題:" + post.Element ("title").Value.Trim ());}輸出結果:版面:HUSTStudent
標題:地震了???
版面:WorldSoccer
標題:大家支持哪隊?
版面:Humor
標題:【原創】幾個小humor
版面:WorldSoccer
標題:2010年世界杯抽簽結果
版面:HUSTStudent
標題:當武大陷入教授門、貪污門時。華中科大又多了兩?
版面:Bicycle
標題:雅京行紀錄片-1-雅典
版面:Picture
標題:想當二奶的有門路了!
版面:Picture
標題:輕拍。。。不要太挑剔了
版面:Humor
標題:【原創】關于找工作
版面:TrainFan
標題:1000
ress any key to continue . . .
?
那在.NET 4.0 中,又是怎樣的呢,先看我最后的代碼:
XDocument doc = XDocument.Load ("http://www.byhh.net/posttop10.xml");dynamic posts = doc.Element ("toppost").AsDynamic ();foreach (var post in posts.post){ Console.WriteLine ("版面:" + post.board); Console.WriteLine ("標題:" + post.title.Trim ());}此時,我們已經完全去掉了啰嗦的Element和Elements方法以及Value屬性的調用,查詢post節點中的board節點、title節點,就只需要post.board和post.title即可,多么方便!而這一切的秘密,就在于dynamic關鍵字和那個AsDynamic方法。不過,不要以為你新建一個VS2010粘貼以上代碼就能運行,“簡單是以復雜為支撐的”,之所以能這么寫,是因為我實現了兩個幫助類XmlNode和XmlNodeList(不是System.Xml命名空間中的那個)來提供dynamic特性的支持,另外還實現了一個靜態類來提供XElement上的擴展方法。具體代碼如下。
class XmlNode DynamicObjectprivate XElement _element; public XmlNode (string name) : this (new XElement (name)) { } public XmlNode (XElement element) { _element = element; } public override bool TryInvokeMember (InvokeMemberBinder binder,object[] args, out object result) { string name = binder.Name; if (String.CompareOrdinal (name, "SelectAll") == 0) { IEnumerable<XElement> selectedElements = nullif (args.Length == 0) { selectedElements = _element.Descendants (); } else { selectedElements = _element.Descendants (args[0].ToString ()); } result = new XmlNodeList (selectedElements); return true; } else if (String.CompareOrdinal (name, "SelectChildren") == 0) { IEnumerable<XElement> selectedElements = nullif (args.Length == 0) { selectedElements = _element.Elements (); } else { selectedElements = _element.Elements (args[0].ToString ()); } result = new XmlNodeList (selectedElements); return true; } return base.TryInvokeMember (binder, args, out result); } public override bool TryGetMember (GetMemberBinder binder, out object result) { string name = binder.Name; if (String.CompareOrdinal (name, "Name") == 0) { result = _element.Name.LocalName; return true; } else if (String.CompareOrdinal (name, "Parent") == 0) { XElement parent = _element.Parent; if (parent != null) { result = new XmlNode (parent); return true; } result = nullreturn true; } else if (String.CompareOrdinal (name, "Value") == 0) { result = _element.Value; return true; } else if (String.CompareOrdinal (name, "Nodes") == 0) { result = new XmlNodeList (_element.Elements ()); return true; } else if (String.CompareOrdinal (name, "Xml") == 0) { StringWriter sw = new StringWriter (); _element.Save (sw, SaveOptions.None); result = sw.ToString (); return true; } else XAttribute attribute = _element.Attribute (name); if (attribute != null) { result = attribute.Value; return true; } var childNodes = _element.Elements (name).ToArray (); if (childNodes.Length == 1) { if (!childNodes[0].HasElements) { result = childNodes[0].Value; return true; } result = new XmlNode (childNodes[0]); return true; } else if (childNodes.Length > 1) { result = new XmlNodeList (childNodes); return true; } } return base.TryGetMember (binder, out result); } public override bool TrySetMember (SetMemberBinder binder, object value) { string name = binder.Name; if (String.CompareOrdinal (name, "Value") == 0) { _element.Value = (value != null) ? value.ToString () : String.Empty; } return base.TrySetMember (binder, value); }}
下面是XmlNodeList,用于處理子節點列:
class XmlNodeList DynamicObjectIEnumerableprivate List<XElement> _elements; internal XmlNodeList (IEnumerable<XElement> elements) { _elements = new List<XElement> (elements); } public override bool TryConvert (ConvertBinder binder, out object result) { Type targetType = binder.ReturnType; if (targetType == typeof (IEnumerable)) { result = thisreturn true; } return base.TryConvert (binder, out result); } public override bool TryInvokeMember (InvokeMemberBinder binder,object[] args, out object result) { if (string.CompareOrdinal (binder.Name, "Item") == 0) { if (args.Length == 1) { XElement element = _elements[Convert.ToInt32 (args[0])]; result = new XmlNode (element); return true; } } return base.TryInvokeMember (binder, args, out result); } public override bool TryGetMember (GetMemberBinder binder, out object result) { if (string.CompareOrdinal (binder.Name, "Length") == 0) { result = _elements.Count; return true; } return base.TryGetMember (binder, out result); } #region Implementation of IEnumerable IEnumerator IEnumerable.GetEnumerator () { return new NodeEnumerator (_elements.GetEnumerator ()); } #endregion private sealed class NodeEnumerator IEnumerator private IEnumerator<XElement> _elementEnumerator; public NodeEnumerator (IEnumerator<XElement> elementEnumerator) { _elementEnumerator = elementEnumerator; } public object Current { get XElement element = _elementEnumerator.Current; return new XmlNode (element); } } public bool MoveNext () { return _elementEnumerator.MoveNext (); } public void Reset () { _elementEnumerator.Reset (); } }}
?
可以看到,這兩個類都繼承自DynamicObject,并覆寫了基類的一些方法,正因為如此,它們才能對dynamic上的調用做出特殊相應。需要注意的是,雖然我這里是寫了兩個類,但它們依然是與我的應用無關的,也就是說,我處理任何XML文檔,都可以使用上述方法,千萬不要以為我為了處理白云黃鶴的十大而特別寫了這兩個類。這兩個類的代碼參考了nikhilk的博客(http://www.nikhilk.net/CSharp-Dynamic-Programming-REST-Services.aspx)的內容,不過他的實現是基于.NET 4.0 CTP的,在beta2上已經無法使用。
最后貼上那個擴展方法AsDynamic()的實現:
static class XmlExtensionpublic static XmlNode AsDynamic (this XElement source) { return new XmlNode (source); } public static XmlNodeList AsDynamic (this IEnumerable<XElement> source) { return new XmlNodeList (source); }}轉載于:https://www.cnblogs.com/wwwzzg168/p/3568977.html
總結
以上是生活随笔為你收集整理的使用dynamic特性处理XML文档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: navigationbar
- 下一篇: vim中使用sed去除网上copy的源代