使用Ruby& amp;将新的子节点添加到现有的XML文件中引入nokogiri

时间:2015-07-07 15:37:26

标签: ruby xml nokogiri

我在Ruby中有这个服务器项目,我想在XML文件中记录事件和用户会话。我对此非常陌生,经过几天的研究,我已经撞墙了。

这是我当前的示例代码,假设已经有一个名为" test.xml"的文件。包含一个名为

的根节点
$ cat test.xml
<server></server>

和代码:

require 'nokogiri'
require 'securerandom'

logintime = Time.now
sessionid = SecureRandom.hex(10)
file = File.open("test.xml",'a+')
doc = Nokogiri::XML.parse file
session_node = Nokogiri::XML::Node.new("session",doc)
session_node['id'] = sessionid
logintime_node = Nokogiri::XML::Node.new("logintime",doc)
logintime_node.content = logintime
session_node << logintime_node
doc.root << session_node
file.print doc.to_xml
file.close

以及4次运行后的test.xml文件

<server></server>
<?xml version="1.0"?>
<server>
  <session id="5ef27ade2afaf5c2162f">
    <logintime>2015-07-07 17:27:20 +0200</logintime>
  </session>
</server>
<?xml version="1.0"?>
<server>
  <session id="637595bd0857c8af1cc0">
    <logintime>2015-07-07 17:27:36 +0200</logintime>
  </session>
</server>
<?xml version="1.0"?>
<?xml version="1.0"?>
<server>
  <session id="41e6082c4db7d1dc8692">
    <logintime>2015-07-07 17:27:37 +0200</logintime>
  </session>
</server>
<?xml version="1.0"?>
<?xml version="1.0"?>
<server>
  <session id="1cad6c3d38d4fb96632b">
    <logintime>2015-07-07 17:27:38 +0200</logintime>
  </session>
</server>
<?xml version="1.0"?>

所需的输出应该是这样的:

<?xml version="1.0"?>
<server>
  <session id="5ef27ade2afaf5c2162f">
    <logintime>2015-07-07 17:27:20 +0200</logintime>
  </session>
  <session id="637595bd0857c8af1cc0">
    <logintime>2015-07-07 17:27:36 +0200</logintime>
  </session>
  <session id="41e6082c4db7d1dc8692">
    <logintime>2015-07-07 17:27:37 +0200</logintime>
  </session>
  <session id="1cad6c3d38d4fb96632b">
    <logintime>2015-07-07 17:27:38 +0200</logintime>
  </session>
</server>

而且我真的不知道为什么要做到这一点。

首先,如果没有包含根节点的现有文件,该脚本只运行一次,然后在我尝试再次运行时抱怨已经有根节点:

/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/gems/2.0.0/gems/nokogiri-1.5.6/lib/nokogiri/xml/document.rb:232:in `add_child': Document already has a root node (RuntimeError)
    from /Users/xxx/nokogiri.rb:13:in `<top (required)>'
    from -e:1:in `load'
    from -e:1:in `<main>'

所以......我有点迷失在这里。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

问题是您是使用File.open('test.xml', 'a+')以追加模式打开文件,然后使用file.print doc.to_xml将整个XML文档写入其中。这就是为什么你最终将整个文档写入文件中的原因。

如果您单独读取和写入文件,XML文档将以您希望的方式替换文件。如果您还需要处理尚未存在的文件,您还可以检查它并使用<server>根标记初始化数据。

require 'nokogiri'
require 'securerandom'

logintime = Time.now
sessionid = SecureRandom.hex(10)

# Read or initialize the data
if File.exist?('test.xml')
  data = File.read("test.xml")
else
  data = '<server></server>'
end

doc = Nokogiri::XML.parse data
session_node = Nokogiri::XML::Node.new("session",doc)
session_node['id'] = sessionid
logintime_node = Nokogiri::XML::Node.new("logintime",doc)
logintime_node.content = logintime
session_node << logintime_node
doc.root << session_node

# Write the document to disk
File.open('test.xml', 'w') do |file|
  file.print doc.to_xml
end

我不建议长时间以这种方式记录会话。在任何重要的用户负载下,写入文件将变得非常昂贵。此外,如果您有多台服务器在运行,它们都会将文件从另一台服务器中删除。当你达到这一点时,你至少应该将存储转换为数据库,或者甚至更好地使用为此构建的ELK Stack之类的东西。