Adding new child nodes to an existing XML file with Ruby & Nokogiri -
i have server project in ruby, , keep tracks of events , user sessions in xml file. i'm totally new this, , after days of research, i'm hitting wall.
here's current sample code, assuming there's file named "test.xml" contains root node called
$ cat test.xml <server></server>
and code :
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
and here's test.xml file after 4 runs
<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"?>
and desired output should :
<?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>
and don't know why should obtain result.
first, if there's no existing file containing root node, script run once, complains there's root node when try run second time :
/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 has root node (runtimeerror) /users/xxx/nokogiri.rb:13:in `<top (required)>' -e:1:in `load' -e:1:in `<main>'
so... i'm kinda lost here. ideas ?
the problem you're opening file in append mode file.open('test.xml', 'a+')
, writing entire xml doc file.print doc.to_xml
. that's why end entire document written several times file.
if read , write file independently, xml doc replace file way want. if need handle file not existing yet, can check , initialize data <server>
root tag.
require 'nokogiri' require 'securerandom' logintime = time.now sessionid = securerandom.hex(10) # read or initialize 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 document disk file.open('test.xml', 'w') |file| file.print doc.to_xml end
i wouldn't recommend logging sessions way long. @ significant user load, writing file become expensive. also, if have multiple servers running, they'll clobbering file out under 1 another. when point, should @ least convert storage database, or better use elk stack that's built this.
Comments
Post a Comment