Use DynamicXElement to create xml

  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>

  让我们看看用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");
}

  是不是比较麻烦呢?如果用我的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");
}

  是不是感觉很干净呢?而且读起来很清晰明了,有层次感!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;
}
}
}


如果还想有其他功能,你可以自己扩展~~~

原理太简单了,就是拦截所有的方法和属性,然后自定义如何Handle。这样其实我们可以在运行时就可以增加属性和方法等。

参考资料:.Net 4.0 DynamicObject使用(下)

posted @ 2011-06-02 17:29  primeli  阅读(451)  评论(0编辑  收藏  举报