我想遍历XML文件中的所有<HeadA>
和<HeadB>
元素,并为每个元素添加唯一ID。我到目前为止尝试的方法是:
@xml.each_element('//HeadA | //HeadB') do |heading|
#add a new id
end
问题是,来自XPath //HeadA | //HeadB
的节点集是所有HeadA
s后跟所有HeadB
s。我需要的是按照文档中出现的顺序列出所有HeadA
和HeadB
的有序列表。
为了澄清一下,我的XML看起来像这样:
<Doc>
<HeadA>First HeadA</HeadA>
<HeadB>First HeadB</HeadB>
<HeadA>Second HeadA</HeadA>
<HeadB>Second HeadB</HeadB>
</Doc>
我从XPath获得的是:
<HeadA>First HeadA</HeadA>
<HeadA>Second HeadA</HeadA>
<HeadB>First HeadB</HeadB>
<HeadB>Second HeadB</HeadB>
当我需要得到的是节点顺序:
<HeadA>First HeadA</HeadA>
<HeadB>First HeadB</HeadB>
<HeadA>Second HeadA</HeadA>
<HeadB>Second HeadB</HeadB>
所以我可以按顺序添加ID。
答案 0 :(得分:1)
好的,第二次尝试,但我想我这次得到了它:P
@xml.each_element('//*[self::HeadA or self::HeadB]') do |heading|
puts heading.text
end
答案 1 :(得分:1)
使用Nokogiri解析XML:
xml = %q{
<Doc>
<HeadA>First HeadA</HeadA>
<HeadB>First HeadB</HeadB>
<HeadA>Second HeadA</HeadA>
<HeadB>Second HeadB</HeadB>
</Doc>
}
doc = Nokogiri::XML(xml)
doc.search('//HeadA | //HeadB').map{ |n| n.inner_text } #=> ["First HeadA", "First HeadB", "Second HeadA", "Second HeadB"]
对于您的任务,您可以将map
替换为each
或each_with_index
,并且差不多完成。只需添加代码即可插入唯一ID。
答案 2 :(得分:0)
如果你绕过所有HeadA并且在每个HeadA内循环通过每个HeadB,它会对你有用吗?
@xml.each_element("//HeadA") do |headA|
#do stuff to headA
headA.each_element("HeadB") do |headB|
#do stuff to headB
end
end
答案 3 :(得分:0)
我想出了一个快速而肮脏的解决方案:
as_string = @xml.to_s
counter = 0
as_string.gsub!(/(<HeadA>|<HeadB>)/) do |str|
result = str.sub '>', " id='#{counter}'>"
counter += 1
result
end
@xml = REXML::Document.new as_string
它可能不是最漂亮或最有效的,但它可以做我想做的事。
编辑:根据D-D-Doug的建议,我现在有了这个:
counter = 0
@xml.each_element('//[self::HeadA or self::HeadB]') do |heading|
heading.attributes['id'] = "id%03d" % counter
counter += 1
end
哪个更好。