
2007年7月23日
关键字:XML REXML 数组 堆栈
本quiz的目的是将一种给定格式的文件转换成为xml文件。
需要在ruby中操作xml,可以使用REXML标准库
回过头来,看标准答案:
1、ARGF 与$<同义
看看《Programming Ruby第二版》p335上的解释:
$< 返回object,一个可以访问作为命令行参数给出或者$stdin(当没有参数的时候)给出的所有文件的内容对象。 谁能告诉我,介句话是嘛意思??让我翻译成人话试试看,一个对象,当文件名作为命令行参数给出时,可以使用该对象访问这些文件的内容,如果没有参数,那么访问$stdin给出的文件内容。应该是这样吧?
$< 支持的方法和File对象类似。返回的对象可能会改变,因为$<会依次读取命令行上给出的文件。
2、\S 在ruby的正则表达式中匹配除空格之外的任何字符
3、下面这段代码有点trick
# pop off the stack until we get the parent
while (level+1) < stack.size
stack.pop
end
parent = stack.last
# create XML tag
if tag =~ /@.+@/
el = parent.add_element data
el.attributes[' id' ] = tag
else
el = parent.add_element tag
el.text = data
end
stack.push el
当刚刚初始化完成后,doc所代表的xml中只有一个根节点<gedcom/>,此后开始读取给定的GedCOM格式文件,读到第一个有效的行时,其level为0,while判断为false,置parent为根节点<gedcom/>,然后将当前的节点作为子节点,并分析其level、tag和data,然后添加到doc中,并将该元素添加到stack数组中,再继续向下处理文件中的行。当遇到一行,其level与上一行的level相同时,此时的level+1就小于了stack这个数组的size,上一行数据所形成的节点就是当前行数据对应节点的兄弟节点,那么就将上一行数据从数组中移除,这样可以保证stack数组中的最后一个元素,一直是要当前这一行要添加节点的父节点。这样一直处理到最后处理完成。
4、doc.write($stdout, 0)
write( output=$stdout, indent=-1, transitive=false, ie_hack=false )
输出XML树,并带有缩进可选项indent.这个方法输出完整的XML文档,包括XML声明,doctype声明,任何处理指令。一个争论的焦点是Document是否应该总是输出XML声明(<?xml version='1.0'?>),有人认为这应该由用户决定。如果没有指定的话,REXML不做输出,因为它向类似XML-RPC这样的应用添加了不必要的带宽占用。
output: 输出支持'<< string'的对象,document向其中写入
indent: 整数。如果是-1,不产生缩进;否则,缩进的该数字指定的空格个数,并且子节点将多产生一个额外的缩进。默认-1.
transive: (没看懂,照抄)If transitive is true and indent is >= 0, then the output will be pretty-printed in such a way that the added whitespace does not affect the absolute value of the document — that is, it leaves the value and number of Text nodes in the document unchanged.
ie_hack: (这段原文很有趣,而且简单,建议自己看)Internet Explorer is the worst piece of crap to have ever been written, with the possible exception of Windows itself. Since IE is unable to parse proper XML, we have to provide a hack to generate XML that IE’s limited abilities can handle. This hack inserts a space before the /> on empty tags. Defaults to false 。
源代码
posted @
2007-07-23 15:32 小熊bryan 阅读(130) |
评论 (0) |
编辑
REXML简要说明
1、解析XML文件
require "rexml/document"
file = File.new( "mydoc.xml" )
doc = REXML::Document.new file
2、解析XML字符串
require "rexml/document"
include REXML # so that we don't have to prefix everything with REXML::...
string = <<EOF
<mydoc>
<someelement attribute="nanoo">Text, text, text</someelement>
</mydoc>
EOF
doc = Document.new string
有了Document之后,可以通过多种方式来访问其中的元素
○ Element 类有each_element_with_attributes方法,通常使用它来访问元素
○ Element.elements属性是一个Elements类的实例,可以通过Elements类的each和[]来访问其中的元素。这两个方法都支持使用XPath来进行过滤等操作,因此功能非常强大。
○ Element是Parent的子类,所以要访问元素的子节点,可以通过类似数组的方法,诸如Element[]、Element.each、Element.find、Element.delete等。这是访问一个确实是数组的子节点的最快方式,不支持XPath搜索,并且所有的子节点元素都在这个数组中,不只是Element的子节点。
★ 在REXML中的Element子节点的索引从1开始,而不是0。因为XPath就是从1开始进行计数的,REXML维持了这种关系。
3、使用XPath
# The invisibility cream is the first <item>
invisibility = XPath.first( doc, "//item" )
# Prints out all of the prices
XPath.each( doc, "//price") { |element| puts element.text }
# Gets an array of all of the "name" elements in the document.
names = XPath.match( doc, "//name" )
4、使用Element.elements.to_a()方法,也可以得到匹配解决的数组。
all_elements = doc.elements.to_a
all_children = doc.to_a
all_upc_strings = doc.elements.to_a( "//item/attribute::upc" )
all_name_elements = doc.elements.to_a( "//name" )
5、手动添加元素的方式创建XML文档
require "rexml/document"
doc = REXML::Document.new "<root/>"
root_node = doc.root
el = root_node.add_element "myel"
el2 = el.add_element "another", {"id"=>"10"}
# does the same, but also sets attribute "id" of el2 to "10"
el3 = REXML::Element.new "blah"
el.elements << el3
el3.attributes["myid"] = "sean"
puts doc.to_s
输出:
<root><myel><another id='10'/><blah myid='sean'/></myel></root>
6、为Element添加文本
el1 = Element.new "myelement"
el1.text = "Hello world!"
# -> <myelement>Hello world!</myelement>
el1.add_text "Hello dolly"
# -> <myelement>Hello world!Hello dolly</element>
el1.add Text.new("Goodbye")
# -> <myelement>Hello world!Hello dollyGoodbye</element>
el1 << Text.new(" cruel world")
# -> <myelement>Hello world!Hello dollyGoodbye cruel world</element>
注意,这些Text对象仍然分开储存的;el1.text返回"Hello world!", el1[2]返回内容为"Goodbye"的Text对象。
7、REXML所有文本节点中都是以UTF-8编码的,所有调用的代码都要注意这一点,在程序中,传递给REXML的字符串必须是经过UTF-8编码的。
REXML不可能总是正确猜测出你的文本的编码方式,所以它总是假定为UTF-8编码。同时,如果你试图添加其他编码方式的文本,REXML不会发出警告。添加者必须保证自己添加的是UTF-8的文本。如果添加标准的ASCII 7位编码,是没有关系的。如果使用ISO8859-1文本,必须在添加之前转换为UTF-8编码。可以使用text.unpack("C*").pack("U*")。变更编码进行输出,只有Document.write()和Document.to_s()支持。如果需要输出特定编码的节点,必须用Output把输出对象包装起来。
e = Element.new "<a/>"
e.text = "f\xfcr" # ISO-8859-1 '??'
o = ''
e.write( Output.new( o, "ISO-8859-1" ) )
可以向Output传递任何支持的编码。
8、插入元素
两种方式:标准的Ruby数组表示法
doc = Document.new "<a><one/><three/></a>"
doc.root[1,0] = Element.new "two"
# -> <a><one/><two/><three/></a>
调用Parent.insert_before 或 Parent.insert_after
three = doc.elements["a/three"]
doc.root.insert_after three, Element.new "four"
# -> <a><one/><two/><three/><four/></a>
# A convenience method allows you to insert before/after an XPath:
doc.root.insert_after( "//one", Element.new("one-five") )
# -> <a><one/><one-five/><two/><three/><four/></a>
# Another convenience method allows you to insert after/before an element:
four = doc.elements["//four"]
four.previous_sibling = Element.new("three-five")
# -> <a><one/><one-five/><two/><three/><three-five/><four/></a>
9、元素的迭代
除使用Element.each方法迭代全部子节点之外,还有其他四种主要的遍历方式。Element.elements.each,只对子元素进行遍历;Element.next_element和Element.previous_element,用作取得下一个Element兄弟节点;Element.next_sibling和Element.previous_sibling,用作取得下一个和上一个兄弟节点,不管其类型是什么。
posted @
2007-07-23 14:00 小熊bryan 阅读(901) |
评论 (0) |
编辑