代码改变世界

由XML Literal引发的思考

2010-04-24 00:21 FantasySoft 阅读(...) 评论(...) 编辑 收藏

一年多没在首页露脸了,昨天凌晨写就了一篇有关IronPython的随笔,发布的时候我确实有点诚惶诚恐。不过还好,至少引得几位朋友的围观,还能碰上老朋友木野狐,我心足矣!木野狐在评论中给我留下了一个非常棒的问题:“IronPython能否模拟或者接近vb.net的xml literal那样的语法?”尽管我对IronPython处理XML的能力自信满满,但是,面对XML Literal这样的词汇,我有点踌躇了。于是,我开始了一系列的研究。

首先,什么是XML Literal呢?原来,这是在VB.NET 9.0才引入的一个用于构建XML对象的新特性,并且只有VB.NET 9.0才支持。我们都知道,要创建XML树,可以使用Linq中的API,如下所示(代码出自VB.NET 9.0: XML Literal):

Dim _xml2 = New XElement("ProcessList", _
                
New XElement("Process", _
                    
New XAttribute("ThreadCount""2"), "Some Process"))

对于上述的代码,我们可以使用更简单的方式进行赋值,那就是直接将XML树写出来:

Dim _xml = <Processes>
               
<Process ThreadCount="2">Some Name</Process>
           
</Processes>

这就是VB.NET特有的XML Literal了。这个特性不仅仅简化了XElement构建的过程,更重要的是,我们可以在构建的过程中添加某些查询!譬如下面的代码(代码出自XML Literals Overview):

Dim contact2 = 
        
<contact>
          
<name>Patrick Hines</name>
          
<%= From p In phoneNumbers2 
            
Select <phone type=<%= p.Type %>><%= p.Number %></phone> 
          %
>
        
</contact>

看到这些例子,我着实被震撼了。VB.NET对XML的支持力度可谓空前绝后了,甚至一些忠实的C#拥趸都因此拜倒在VB.NET的石榴裙下C#社区也纷纷要求为C#增加XML Literal特性更有甚者竭力找到了Anders为大家留下的后门。对于XML Literal有兴趣的朋友,可以阅读以下几篇来自MSDN的文章:XML Literals OverviewEmbedded Expressions in XML

对于XML的处理,VB.NET有此锐器,那么IronPython是否有相似的工具呢?Michael搜肠刮肚、翻箱倒柜才找到本属于Python的minidom模块,其中的parseString方法拥有稍微接近的处理能力,但可惜的是,parseString方法返回的对象只能是Document对象,而非ELement,这也意味着parseString并不拥有XML Literal的魔力。

>>> from xml.dom.minidom import parseString
>>> xmlElement = parseString("""
...     <Processes>
...          <Process ThreadCount="2">Some Name</Process>
...     </Processes>
...   
""")

上述代码在IronPython 2.6中执行,会出现错误。这是因为IronPython对minidom的移植还没有全部完成,缺失了某些模块。具体的workaround如下:
1、下载FePy并且解压至某个目录,譬如D:\FePy;
2、将D:\FePy\Lib\pyexpat.py、 D:\FePy\Lib\xml\dom\expatbuilder.py、D:\FePy\Lib\xml\parsers\expat.py赋值到IronPython相对应的目录中。如第一个文件就复制到D:\IronPython 2.6\Lib的目录下;
3、搜索expatbuilder.py中的NewStyle变量,并且将其删除。

 

[后记:]一位在Youtube工作的牛人Fredrik Lundh早在2002年就提出了为Python添加XML Literal的功能但是直到现在还没有出现类似的功能,至少Michael现在还没有找到。有发现的朋友请告知一声,衷心感谢! 

经过limodou兄的指点,Michael找到了xml.etree.ElementTree模块,其中的xml.etree.ElementTree.XML(text)方法在一定程度实现XML Literal特性,毕竟它返回的是Element对象,那么我们就可以基于此进行操作了。xml.etree.ElementTree模块在IronPython 2.6下运行正常。