在Ruby中解析和处理XML
我有一个小的XML文档,叫做foobar.xml。
<?xml version="1.0" standalone="no"?>
<!DOCTYPE foo SYSTEM "bar.dtd">
<title _FORMAT="XXX.XXX" _QUANTITY="1" _DEVICENAME="XXX" _JOBNAME="FOOBAR">
<subtitle>
<variable name="x">A-1234567</variable>
</subtitle>
</title>
还有一点Python代码,
with open('foobar.xml', 'rt') as f:
tree = ElementTree.parse(f)
# Loop over all elements in 'tree' in section order
for node in tree.getiterator():
if node.tag == "variable":
for z in range(number):
if len(str(start)) == 7:
accession = "A-" + str(start)
# This simply adds leading zeros if there are < 7 digits
elif len(str(start)) < 7:
accession = "A-" + ("0" * (7 - len(str(start))) + str(start))
start += 1
# Assign 'accession' to the node text
node.text = accession
tree.write("foobar.xml")
else:
continue
这段代码可以很漂亮地找到我感兴趣的节点标签,并通过循环来处理它,每次都替换节点的文本,然后把XML写入一个文件。不过,有一个问题:我需要用Ruby来实现这个功能。
到目前为止,我有
doc = Document.new(File.new("foobar.xml"))
doc.elements.each() do |element|
element.elements.each() do |child|
child.elements.each() do |sub| # probably wrong
for z in 0...$number
if $start.to_s.length == 7
accession = "A-" + $start.to_s
else
accession = "A-" + ("0" * (7 - $start.to_s.length)) + $start.to_s
end
$start += 1
# need to assign here and write to file or assign to variable
end
end
end
end
这是我第一次在Ruby中处理XML,我对语法真的不太理解。我的目标基本上是复制Python的做法,通过循环每次更改节点文本,然后把结果写入一个XML文件。任何建议都非常感谢。
2 个回答
2
我更喜欢用Nokogiri来解析Ruby中的XML;它使用起来又快又高效(而且如果你愿意的话,可以用类似CSS的选择器,而不是XPath):
require 'nokogiri'
$number = 3
$start = 134341
my_xml = IO.read('foobar.xml')
doc = Nokogiri::XML(my_xml)
doc.css('variable').each do |el|
$number.times do
# Pads to a 7-digit number: see `ri Kernel#sprintf`
el.content = "A-%07d" % $start
File.open( "foobar-#{$start}.xml", 'w' ) do |f|
f << doc
end
$start += 1
end
end
我对上面的代码做了一些修改,让它可以输出一个独特的文件;你肯定不会一直写同一个文件,对吧?
1
为了完整性,这里有一个基于REXML的解决方案:
require 'rexml/document'
$number = 3
$start = 1312
doc = REXML::Document.new(my_xml)
REXML::XPath.each(doc,'//variable') do |el|
$number.times do
el.text = "A-%07d" % $start
File.open( "f-#{$start}.xml", 'w' ){ |f| f << doc }
$start += 1
end
end