该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-08-10
在开发RESTful应用或者实现多个应用系统交互时,经常会用到XML作为数据交换格式,系统会经常处理XML数据,采用ROXML将会是一个不错的方案,ROXML是一个实现ruby对象和XML进行映射的库,通过annotations声明,它也可以将xml数据节点映射为ruby类的属性,以及把XML的节点关系映射为ruby类之间的关系,个人觉得,它的作用类似于ActiveRecord将ruby对象映射为数据库表。 在此处可以下载该库 http://rubyforge.org/projects/roxml ,这里有一个图书馆和图书的例子,以此说明ROXML处理一对多的情况。
生成相应的ruby类
class Book include ROXML xml_attribute :isbn, "ISBN" xml_text :title xml_text :description, nil, ROXML::TAG_CDATA xml_text :author end class Library include ROXML xml_text :name, "NAME", ROXML::TAG_CDATA xml_object :books, Book, ROXML::TAG_ARRAY, "books" end
分别创建Library对象和Book对象,并将book放入library中,最后保存输出。
book = Book.new() book.isbn = "0201710897" book.title = "The PickAxe" book.description = "Best Ruby book out there!" book.author = "David Thomas, Andrew Hunt, Dave Thomas" lib = Library.new() lib.name = "Favorite Books" lib.books << book File.open("library.xml", "w") do |f| lib.to_xml.write(f, 0) end
可以看到生成的xml为:
<library> <NAME><![CDATA[Favorite Books]]></NAME> <books> <book ISBN='0201710897'> <title>The PickAxe</title> <description><![CDATA[Best Ruby book out there!]]></description> <author>David Thomas, Andrew Hunt, Dave Thomas</author> </book> </books> </library>
同理,也可以根据xml数据创建ruby对象,这里再举个一对一的例子,假设有以下的xml文档,描述了图书与作者的关系。
<book isbn="0974514055"> <title>Programming Ruby - 2nd Edition</title> <description>Second edition of the great book</description> <publisher> <name>Pragmatic Bookshelf</name> </publisher> </book>
那么生成ruby类与之对应:
class BookWithPublisher include ROXML xml_name :book xml_object :publisher, Publisher end
最后可以读取先前的xml文档并生成相应的ruby对象了,此时可以操作book对象来达到对xml文档进行处理。
book = Book.parse(File.read("book.xml"))
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-11-15
xml变成了hash后如何比较?
通过内建的==是无法比较两个有相同键值对的hash的,因为只要键值对顺序不同,==方法就认为不同。 |
|
返回顶楼 | |
发表时间:2008-11-15
CharlesCui 写道
xml变成了hash后如何比较?
通过内建的==是无法比较两个有相同键值对的hash的,因为只要键值对顺序不同,==方法就认为不同。
if (h1.keys).eql?(h2.keys) |
|
返回顶楼 | |
发表时间:2008-11-15
liuqiang 写道 CharlesCui 写道
xml变成了hash后如何比较?
通过内建的==是无法比较两个有相同键值对的hash的,因为只要键值对顺序不同,==方法就认为不同。
if (h1.keys).eql?(h2.keys) 没用,你怎么知道一个hash有多少个key呢?hash里面还会有hash的。 |
|
返回顶楼 | |
发表时间:2008-11-15
CharlesCui 写道 xml变成了hash后如何比较?
通过内建的==是无法比较两个有相同键值对的hash的,因为只要键值对顺序不同,==方法就认为不同。
|
|
返回顶楼 | |
发表时间:2008-11-15
最后修改:2008-11-15
hozaka 写道
跑下题,ruby1.9的key按插入顺序排列了: http://intertwingly.net/slides/2008/oscon/ruby19/22 这个特性是fiber之后最吸引我的了,会大大加强语言的表达能力。 |
|
返回顶楼 | |
发表时间:2008-11-16
最后修改:2008-11-16
hozaka 写道 CharlesCui 写道 xml变成了hash后如何比较?
通过内建的==是无法比较两个有相同键值对的hash的,因为只要键值对顺序不同,==方法就认为不同。
我没说hash是有序的,我是说ruby内建的==方法可能是有序的。 |
|
返回顶楼 | |
发表时间:2008-11-16
最后修改:2008-11-16
还有,
liusong1111,你上面介绍的操作xml的库和activeSupport这个库都有一个类似的方法就是Hash.frmo_xml. 我一直想问的问题是两个只有element顺序不同的xml片段如何比较? 你的意思是不是变成hash后再用eql?或者==来比较?可问题是,hash的子元素的类型不一定啊,说不定是数组或者别的呢,如果是数组,那就肯定不相同了,数组是有顺序的。 你试试下面的代码就理解我的意思了: require 'rubygems' require 'pp' require 'active_support' xml1=<<-XML <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> XML xml2=<<-XML <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-value>false</param-value> <param-name>listings</param-name> </init-param> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> XML h1=Hash.from_xml xml1 h2=Hash.from_xml xml2 pp h1 p "*"*100 pp h2 p "*"*100 p h1==h2 |
|
返回顶楼 | |
发表时间:2008-11-16
我对你的需求的理解是,有2个哈希,哈希可能还存在嵌套,只要这2个哈希的key,包括嵌套的hash的key相同,顺序可以不同,那么这2个hash则认为是相等的。
貌似ruby没有内置的api可以用,我觉得还是设计一个小算法自己做,我的思路是遍历hash中的所有key,包括嵌套hash的key,将第一层hash的key以及它的子哈希的key组成一个字符串,并以逗号隔开,再这些字符串存进数组,最后通过比较数组来确定这2个hash是否相等。
测试代码如下:
class A @@a = [] @@str = "" def A.xxx(h) h.each do |key, val| if val.class.to_s == "Hash" @@str = @@str + key.to_s + "," xxx(val) else @@str = @@str + key.to_s @@a << @@str @@str = "" end end end def A.getA() return @@a end def A.setA() @@a = [] end end h1 = {'a1'=>1,'a2'=>{'b2'=>1},'a3'=>{'b3'=>{'c3'=>1}}} h2 = {'a3'=>{'b3'=>{'c3'=>1}},'a1'=>1,'a2'=>{'b2'=>2}} A.setA A.xxx(h1) a = A.getA puts A.getA A.setA A.xxx(h2) b = A.getA puts b puts a.eql?(b)
写的很差,仅供参考 |
|
返回顶楼 | |
发表时间:2008-11-16
最后修改:2008-11-16
liuqiang11 写道 我对你的需求的理解是,有2个哈希,哈希可能还存在嵌套,只要这2个哈希的key,包括嵌套的hash的key相同,顺序可以不同,那么这2个hash则认为是相等的。
强强能够理解我的意思,但是你为什么不考虑value啊?差一半就被你搞定了。 我再给强强补充下: 如果有如下两个hash分别为h1和h2,那该如何比较呢? h1={"servlet"=> {"load_on_startup"=>"1", "servlet_name"=>"default", "init_param"=> [{"param_name"=>"debug", "param_value"=>"0"}, {"param_name"=>"listings", "param_value"=>"false"}], "servlet_class"=>"org.apache.catalina.servlets.DefaultServlet"}} "****************************************************************************************************" h2={"servlet"=> {"load_on_startup"=>"1", "servlet_name"=>"default", "init_param"=> [{"param_name"=>"listings", "param_value"=>"false"}, {"param_name"=>"debug", "param_value"=>"0"}], "servlet_class"=>"org.apache.catalina.servlets.DefaultServlet"}} 现实中的问题是,从一个xml解析而来的hash你不会知道它每个key的value类型,可能是hash,也可能是数组,或者是别的。 请给出一个通用的方法。 强强,再加油一把,期待你的完美表现! PS:请以我之前给出的那两个xml片段来比较吧,这两个hash就是从那两个hash解析来的。 |
|
返回顶楼 | |