用C#实现仿Ruby的XML Builder

Ruby中有个很好用的XML API,在页面实现XML输出很方便。比如有个联系人Contacts的XML输出,Ruby里面是这样写的。

...
xml.contacts do
  xml.contact(:type => "work") do
    xml.name("Joe Smith")
  end
end
...

借用.Net 4.0的dynamic特性,用C#实现一个XmlBuilder。测试代码如下:

 

ContractedBlock.gif ExpandedBlockStart.gif XmlBuilderTest
 
   
[TestFixture]
public class XmlBuilderTest
{
[Test]
public void CreatorTest()
{
dynamic xmlBuilder
= new XmlBuilder();
var result
= xmlBuilder.Contacts(
xmlBuilder.Contact(
" type " , " team-member " , " id " , " 1 " ,
xmlBuilder.Name(
" Joe Smith " ),
xmlBuilder.Phone(
" type " , " work " , " (123) 456-7890 " ),
xmlBuilder.爱好(
" 看电影 " ),
xmlBuilder.Address(
" type " , " home " ,
xmlBuilder.Street(
" 123 Main St. " ),
xmlBuilder.City(
" SpringField " ))));

Console.WriteLine(
" XML: \n " + result.ToString());
}

}

为实现上述功能,我们创建类XmlBuilder,继承DynamicObject,并override其TryInvokeMember方法。

 

ContractedBlock.gif ExpandedBlockStart.gif XmlBuilder
 
   
public class XmlBuilder : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object [] args, out object result)
{
var arguments
= ParseArguments(args);
var rootElement
= new XElement(binder.Name, arguments.Text, arguments.Attributes);
foreach (XDocument xDocument in arguments.Documents)
rootElement.Add(xDocument.FirstNode);

result
= new XDocument(rootElement);
return true ;
}

private static dynamic ParseArguments( object [] arguments)
{
var documents
= new List < XDocument > ();
var strings
= new List < string > ();
var attributes
= new List < XAttribute > ();
string text = null ;

// 分析参数类型,区分string和XDocument
foreach (var arg in arguments)
{
XDocument xDocArgument;
string stringArgument;
if (CastAs(arg, out xDocArgument))
documents.Add(xDocArgument);
else if (CastAs(arg, out stringArgument))
strings.Add(stringArgument);
}

// 如果strings总数为奇数,定义最末一个字符串为InnerText。
if (strings.Count % 2 == 1 )
{
text
= strings.Last();
strings.RemoveAt(strings.Count
- 1 );
}

// 将strings成对封装为XAttribute。
for (var i = 0 ; i < strings.Count; i = i + 2 )
{
attributes.Add(
new XAttribute(strings[i], strings[i + 1 ]));
}

// 返回动态类型。
return new { Documents = documents, Attributes = attributes, Text = text };
}

/// <summary>
/// 类型判断
/// </summary>
private static bool CastAs < T > ( object value, out T castedValue)
{
if (value is T)
{
castedValue
= (T)value;
return true ;
}
castedValue
= default (T);
return false ;
}
}

运行XmlBuilderTest,得到的结果如下:

 

 

 
  
XML:
< Contacts >
< Contact type ="team-member" id ="1" >
< Name > Joe Smith </ Name >
< Phone type ="work" > (123) 456-7890 </ Phone >
< 爱好 > 看电影 </ 爱好 >
< Address type ="home" >
< Street > 123 Main St. </ Street >
< City > SpringField </ City >
</ Address >
</ Contact >
</ Contacts >

 

 

-- 声明 --

1、没太动脑筋,主要的实现思路(包括部分代码),来源于In a Perfect World。(带梯子可访问)原作者给的代码有问题,我在上面做了修改。

2、运行dynamic,需要在.Net 4.0环境下,引用程序集Microsoft.CSharp.dll。

-- 下载 --

所有代码在这儿下载。XmlBuilderTest.zip

转载于:https://www.cnblogs.com/workingbird/articles/CSharp_dynamic_xmlbuilder_like_ruby.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值