如何更新NodeSet

时间:2017-03-22 15:23:00

标签: ruby xml nokogiri

我正在尝试在以下XML中添加一个<EventRouter>元素:

<EventRouters>
        <EventRouter id="Important Events to Log File" class="com.cyclonecommerce.events2.router.LogFileRouter" active="true">
            <Parameters file="../logs/%nodeName%_events.log"
                        rollOnStart="false" autoFlush="true"
                        maxFileSize="2M" maxBackupFiles="5"/>
            <MetadataProcessorListRef ref="Messaging"/>
            <EventFilterRef ref="Important"/>
        </EventRouter>
        <EventRouter id="Message Detail to Log File"   class="com.cyclonecommerce.events2.router.LogFileRouter" active="false">
            <Parameters file="../logs/%nodeName%_message_detail.log"
                        rollOnStart="true" autoFlush="true"
                        maxFileSize="2M" maxBackupFiles="5"/>
            <MetadataProcessorListRef ref="Messaging"/>
            <EventFilterRef ref="Message Detail"/>
        </EventRouter>

</EventRouters>

我能够将节点附加到节点集但是在保存XML之后我没有得到我想要的更新的XML:

require 'nokogiri'

if File.exist?('a.xml')
  data = File.read("a.xml")

end
doc = Nokogiri::XML.parse data
doc2=doc.xpath("//EventRouters/EventRouter")

event_router = Nokogiri::XML::Node.new("EventRouter",doc)
event_router['id'] = "some"
param_node = Nokogiri::XML::Node.new("Parameters",doc)
param_node.content = "some content"
event_router << param_node
doc2<<  event_router

File.open('test.xml', 'w') do |file|
  file.print doc.to_xml
end

2 个答案:

答案 0 :(得分:1)

更改

doc2=doc.xpath("//EventRouters/EventRouter")

doc2 = doc.at_xpath("//EventRouters")

xpath返回一个数组。您可以使用at_xpath来获取第一个元素。还要摆脱/EventRouter,因为我想你想把另一个'EventRouter'项添加到EventRouters

答案 1 :(得分:0)

添加新节点很简单。基本思想类似于解析XML或HTML:

  1. 找到要添加新内容的节点。
  2. 使用适当的方法在节点的子节点的开头附加内容,或者作为包含节点的兄弟节点或父节点附加内容。这些方法在the Node documentation
  3. 你已经完成了。
  4. Nokogiri使用字符串添加节点变得容易,它将解析并转换为节点:

    require 'nokogiri'
    doc = Nokogiri::XML('<xml><node/></xml>')
    
    node = doc.at('node')
    node.add_child('<foo>bar</foo>')
    doc.to_xml # => "<?xml version=\"1.0\"?>\n<xml>\n  <node>\n    <foo>bar</foo>\n  </node>\n</xml>\n"
    

    您可以使用更长的创建新节点的路线,但我发现更容易构建字符串。

    使用您的代码作为依据,以下是我的编写方式:

    require 'nokogiri'
    
    data = DATA.read
    
    doc = Nokogiri::XML.parse data
    doc.xpath("//EventRouters/EventRouter").each do |event_router|
      event_router.add_next_sibling("<EventRouter id='some'><Parameters>some content</Parameters></EventRouter>")
    end
    
    puts doc.to_xml
    
    __END__
    <EventRouters>
      <EventRouter>original1</EventRouter>
      <EventRouter>original2</EventRouter>
    </EventRouters>
    

    运行结果:

    <?xml version="1.0"?>
    <EventRouters>
      <EventRouter>original1</EventRouter><EventRouter id="some"><Parameters>some content</Parameters></EventRouter>
      <EventRouter>original2</EventRouter><EventRouter id="some"><Parameters>some content</Parameters></EventRouter>
    </EventRouters>
    

    您尝试使用<<附加到NodeSet,而NodeSet不会按照您的想法执行操作:

    doc = Nokogiri::XML.parse data
    ers = doc.search('EventRouter') 
    ers << Nokogiri::XML::Node.new('<foo/>', doc)
    

    附加到ers,这是一个NodeSet,不会将新节点应用于集合中的所有元素:

    doc.to_xml # => "<?xml version=\"1.0\"?>\n<EventRouters>\n  <EventRouter>original1</EventRouter>\n  <EventRouter>original2</EventRouter>\n</EventRouters>\n"
    

    相反,它将它附加到集合的末尾:

    ers.to_xml # => "<EventRouter>original1</EventRouter><EventRouter>original2</EventRouter><<foo/>/>"