XML作为一种通用数据格式,.net进行了专门的封装。从开始的XMLDoc到现在的 Linq to XML一直不断的简化XML的操作。
.net4.0的出现给偶们带来了dynamic特性,ExpandoObject和DynamicObject这2个类很拉风~~~
比如我们要生成一段简历的XML:
<?
xml version="1.0" encoding="utf-8"
?>
< Resume >
< Name > Prime </ Name >
< Date > 2011/6/2 </ Date >
< City > Nanjing </ City >
< Contact >
< QQ > 277389861 </ QQ >
< MSN > prime.li@live.cn </ MSN >
</ Contact >
< A >
< B >
< C >
< D >
< E >
< City > Nanjing </ City >
</ E >
</ D >
</ C >
</ B >
</ A >
</ Resume >
< Resume >
< Name > Prime </ Name >
< Date > 2011/6/2 </ Date >
< City > Nanjing </ City >
< Contact >
< QQ > 277389861 </ QQ >
< MSN > prime.li@live.cn </ MSN >
</ Contact >
< A >
< B >
< C >
< D >
< E >
< City > Nanjing </ City >
</ E >
</ D >
</ C >
</ B >
</ A >
</ Resume >
让我们看看用Linq to XML是如何创建Resume.xml的:
public
void
Resume()
{
XDocument doc = new XDocument();
var resume = new XElement( " Resume " );
resume.Add( new XElement( " Name " , " Prime " ));
resume.Add( new XElement( " Date " , DateTime.Today.ToShortDateString()));
resume.Add( new XElement( " City " , " Nanjing " ));
resume.Add( new XElement( " Contact " ));
resume.Element( " Contact " ).Add( new XElement( " QQ " , " 277389861 " ));
resume.Element( " Contact " ).Add( new XElement( " MSN " , " prime.li@live.cn " ));
resume.Add( new XElement( " A " , new XElement( " B " , new XElement( " C " , new XElement( " D " , new XElement( " E " , resume.Element( " City " )))))));
doc.Add(resume);
doc.Save( " Resume.xml " );
}
{
XDocument doc = new XDocument();
var resume = new XElement( " Resume " );
resume.Add( new XElement( " Name " , " Prime " ));
resume.Add( new XElement( " Date " , DateTime.Today.ToShortDateString()));
resume.Add( new XElement( " City " , " Nanjing " ));
resume.Add( new XElement( " Contact " ));
resume.Element( " Contact " ).Add( new XElement( " QQ " , " 277389861 " ));
resume.Element( " Contact " ).Add( new XElement( " MSN " , " prime.li@live.cn " ));
resume.Add( new XElement( " A " , new XElement( " B " , new XElement( " C " , new XElement( " D " , new XElement( " E " , resume.Element( " City " )))))));
doc.Add(resume);
doc.Save( " Resume.xml " );
}
是不是比较麻烦呢?如果用我的DynamicXElement类可以这样写:
public
void
DynamicResume()
{
dynamic resume = new DynamicXElement( " Resume " );
resume.Name = " Prime " ;
resume.Date = DateTime.Today.ToShortDateString();
resume.City = " Nanjing " ;
resume.Contact.QQ = " 277389861 " ;
resume.Contact.MSN = " prime.li@live.cn " ;
resume.A.B.C.D.E = resume.City;
resume.Save( " DynamicResume.xml " );
}
{
dynamic resume = new DynamicXElement( " Resume " );
resume.Name = " Prime " ;
resume.Date = DateTime.Today.ToShortDateString();
resume.City = " Nanjing " ;
resume.Contact.QQ = " 277389861 " ;
resume.Contact.MSN = " prime.li@live.cn " ;
resume.A.B.C.D.E = resume.City;
resume.Save( " DynamicResume.xml " );
}
是不是感觉很干净呢?而且读起来很清晰明了,有层次感!O(∩_∩)O
其实实现起来很简单,利用DyanmicObject,我们包装一个XElement就可以搞定,如下:
public
class
DynamicXElement : DynamicObject
{
public DynamicXElement( string name)
: this ( new XElement(name))
{ }
public DynamicXElement(XElement element)
: this (element, true )
{ }
public DynamicXElement( string name, bool dyanmicCreateElement)
: this ( new XElement(name), dyanmicCreateElement)
{ }
public DynamicXElement(XElement element, bool dyanmicCreateElement)
{
Element = element;
DynamicCreateElement = dyanmicCreateElement;
}
public XElement Element
{ get ; private set ; }
/// <summary>
/// 是否支持动态创建节点
/// 比如你写resume.A.B.C.D.E,其实A,B,C,D都是空的
/// true则会自动创建A,B,C,D,E这些节点,否则false则必须先创建好A,B,C,D这4个节点
/// </summary>
public bool DynamicCreateElement
{ get ; private set ; }
public static DynamicXElement Load( string uri)
{
var element = XElement.Load(uri);
return new DynamicXElement(element);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var element = Element.Element(binder.Name);
if (element != null )
{
result = new DynamicXElement(element);
return true ;
}
else
{
if (DynamicCreateElement)
{
var child = new XElement(binder.Name);
Element.Add(child);
result = new DynamicXElement(child);
return true ;
}
else
{
result = null ;
return false ;
}
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var element = Element.Element(binder.Name);
if (element != null )
{
element.SetValue(value);
}
else
{
if (value is DynamicXElement)
{
var child = new XElement(binder.Name);
var innerElement = ((DynamicXElement)value).Element;
child.Add(innerElement);
Element.Add(child);
}
else
{
Element.Add( new XElement(binder.Name, value));
}
}
return true ;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type.Equals( typeof (XElement)))
{
result = Element;
return true ;
}
return base .TryConvert(binder, out result);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object [] args, out object result)
{
try
{
var flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
result = typeof (XElement).InvokeMember(binder.Name, flags, null , Element, args);
return true ;
}
catch
{
result = null ;
return false ;
}
}
}
{
public DynamicXElement( string name)
: this ( new XElement(name))
{ }
public DynamicXElement(XElement element)
: this (element, true )
{ }
public DynamicXElement( string name, bool dyanmicCreateElement)
: this ( new XElement(name), dyanmicCreateElement)
{ }
public DynamicXElement(XElement element, bool dyanmicCreateElement)
{
Element = element;
DynamicCreateElement = dyanmicCreateElement;
}
public XElement Element
{ get ; private set ; }
/// <summary>
/// 是否支持动态创建节点
/// 比如你写resume.A.B.C.D.E,其实A,B,C,D都是空的
/// true则会自动创建A,B,C,D,E这些节点,否则false则必须先创建好A,B,C,D这4个节点
/// </summary>
public bool DynamicCreateElement
{ get ; private set ; }
public static DynamicXElement Load( string uri)
{
var element = XElement.Load(uri);
return new DynamicXElement(element);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var element = Element.Element(binder.Name);
if (element != null )
{
result = new DynamicXElement(element);
return true ;
}
else
{
if (DynamicCreateElement)
{
var child = new XElement(binder.Name);
Element.Add(child);
result = new DynamicXElement(child);
return true ;
}
else
{
result = null ;
return false ;
}
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var element = Element.Element(binder.Name);
if (element != null )
{
element.SetValue(value);
}
else
{
if (value is DynamicXElement)
{
var child = new XElement(binder.Name);
var innerElement = ((DynamicXElement)value).Element;
child.Add(innerElement);
Element.Add(child);
}
else
{
Element.Add( new XElement(binder.Name, value));
}
}
return true ;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (binder.Type.Equals( typeof (XElement)))
{
result = Element;
return true ;
}
return base .TryConvert(binder, out result);
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object [] args, out object result)
{
try
{
var flags = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
result = typeof (XElement).InvokeMember(binder.Name, flags, null , Element, args);
return true ;
}
catch
{
result = null ;
return false ;
}
}
}
如果还想有其他功能,你可以自己扩展~~~
原理太简单了,就是拦截所有的方法和属性,然后自定义如何Handle。这样其实我们可以在运行时就可以增加属性和方法等。