使用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);    }}												
											使用dynamic特性处理XML文档的更多相关文章
- Java高级特性 第15节 解析XML文档(3) - JDOM和DOM4J技术
		
一.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. Jdom由6个包构成: Element类表示XML文档的元素 org.jdom: 解析xml ...
 - Java高级特性 第14节 解析XML文档(2) - SAX 技术
		
一.SAX解析XML文档 SAX的全称是Simple APIs for XML,也即XML简单应用程序接口.与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式.当使用S ...
 - Java高级特性 第13节 解析XML文档(1) - DOM和XPath技术
		
一.使用DOM解析XML文档 DOM的全称是Document Object Model,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树 ...
 - 【.net 深呼吸】使用二进制格式来压缩XML文档
		
在相当多的情况下,咱们写入XML文件默认是使用文本格式来写入的,如果XML内容是通过网络传输,或者希望节省空间,特别是对于XML文档较大的情况,是得考虑尽可能地压缩XML文件的大小. XmlDicti ...
 - 【Win10 应用开发】自适应Toast通知的XML文档结构
		
老规矩,在开始之前老周先讲个故事. 话说公元2015年7月20日,VS 2015发布.于是,肯定有人会问老周了,C#6有啥新特性,我学不来啊.学不来的话你应该检讨.老周比较保守地计算一下,学会C# 6 ...
 - XML文档操作集锦(C#篇)
		
在JSON没流行起来的时候xml一直作为程序存储配置信息的主流介质:特别是小型数据表方面还是不错的选择,所以经常涉及到的操作无非也就是增删改查,这篇博客主要是对这些对比较常用的操作做了个简单的总结 文 ...
 - Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构
		
分享两篇Win 10应用开发的XML文档结构:Win 10 开发中Adaptive磁贴模板的XML文档结构,Win10 应用开发中自适应Toast通知的XML文档结构. Win 10 开发中Adapt ...
 - java解析xml文档(dom)
		
DOM解析XML文档 读取本地的xml文件,通过DOM进行解析,DOM解析的特点就是把整个xml文件装载入内存中,形成一颗DOM树形结构,树结构是方便遍历和和操纵. DOM解析的特性就是读取xml文件 ...
 - XML 文档和数据
		
.NET Framework 4.5 其他版本 .NET Framework 提供了一组全面而集成的类,可用来方便地生成可以识别 XML 的应用程序. 通过以下命名空间中的类,可以分析和编写 XML, ...
 
随机推荐
- java中属性,set  get 以及如何学习类的一些用法
			
1,先来看一个例子 package com.tdq.java; public class Run { public static void main(String[]args){ Student st ...
 - [解读REST] 1.REST的起源
			
0. 世界上第一个网站 1990年12月20日,这一天对于现在的互联网来说意义非凡.欧洲核子研究组织(CREN)的科学家Tim Berners-Lee在一台NeXT电脑上启动了世界上的第一个网站(当然 ...
 - [转载]AI教师正来势汹汹,教师饭碗堪优
			
(原文标题:开门,机器人老师来了) 一. 开门,机器人老师到了 国庆几天,河南刚刚上演一幕新科技的大戏: 计算机和人展开了为期四天的人机大战.这一次,对垒的双方不再是李世乭和阿尔法狗,而是教师和人工智 ...
 - C语言第一次实验报告————PTA实验1.2.3内容
			
一.PTA实验作业 题目1.温度转换 本题要求编写程序,计算华氏温度100°F对应的摄氏温度.计算公式:C=5×(F−32)/9,式中:C表示摄氏温度,F表示华氏温度,输出数据要求为整型. 1.实验代 ...
 - Hyper-v 虚拟机安装win7
			
Hyper-v 是微软自带的虚拟机 一般安装win10都有 对小娜说:Hyper就会出现 进入Hyper-v 如果虚拟机不可用 启动服务 新建虚拟机 一般设置可以自己随意 虚拟机第一代才可以使用win ...
 - 解析 .Net Core 注入 (2) 创建容器
			
在上一节的学习中,我们已经知道了通过 IServiceCollection 拓展方法创建 IServiceProvider 默认的是一个类型为 ServiceProvider 对象,并且实际提供创建对 ...
 - 使用脚本监控windows服务的方法
			
以下脚本可监控某一个windows服务,发现其停止就立即重启之. @echo off rem 定义循环间隔时间和监测的服务: set secs=60 set srvname="NetWin ...
 - 【面向对象】详解之JavaScript篇
			
[重点提前说:面向对象的思想很重要!] 最近开始接触学习后台的PHP语言,在接触到PHP中的面向对象相关思想之后,突然想到之前曾接触的JS中的面向对象思想,无奈记性太差,便去翻了翻资料,花了点时间梳理 ...
 - mongo+mongoose+express
			
直接上指令: //*代表自定义名字 //使用数据库 use * //检查当前数据库 db //查询数据库列表 show dbs //查询当前数据库集合 show collections //插入文档自 ...
 - Javascript中的Trait与代码重用
			
Javascript中的Trait与代码重用 来源 http://www.ituring.com.cn/article/64103 我们知道,OOP中最普遍的代码重用方式是通过继承,但是,继承有一些缺 ...