使用 Ruby & Nokogiri 将新的子节点添加到现有的 XML 文件
Adding new child nodes to an existing XML file with Ruby & 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 运行s
后的 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>'
所以...我有点迷路了。有什么想法吗?
问题是您使用 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 之类的东西。
我在 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 运行s
后的 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>'
所以...我有点迷路了。有什么想法吗?
问题是您使用 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 之类的东西。