How to replace XML node contents using Nokogiri
nokogiri, ruby, xml, xml-parsing
Solution
def amend_parent_xml(folder, target_file, new_file)
Dir["#{@target_folder}/#{folder}/*.xml"]
.sort.select{|f| !File.directory? f }
.each do |xml_file|
doc = Nokogiri.XML( File.read(xml_file) )
if file = doc.at("//Route//To//Node//Filename[.='#{target_file}']")
file.content = new_file # set the text of the node
File.open(xml_file,'w'){ |f| f<<doc }
break
end
end
end
Improvements:
- Use `File.read` instead of `File.open` so that you don't leave a file handle open.
- Uses an XPath expression to find the SINGLE matching node by looking for a node with the correct text value.
- Alternatively you could find all the files and then `if file=files.find{ |f| f.text==target_file }`
- Shows how to serialize a `Nokogiri::XML::Document` back to disk.
- Breaks out of processing the files as soon as it finds a matching XML file.
Problem
I'm using Ruby to read an XML document and update a single node, if it exists, with a new value. http://www.nokogiri.org/tutorials/modifying_an_html_xml_document.html is not obvious to me how to change the node data, let alone how to save it back to the file. ``` def ammend_parent_xml(folder, target_file, new_file) # open parent XML file that contains file reference get_xml_files = Dir.glob("#{@target_folder}/#{folder}/*.xml").sort.select {|f| !File.directory? f} get_xml_files.each { |xml| f = File.open(xml) # Use Nokgiri to read the file into an XML object doc = Nokogiri::XML(f) filename = doc.xpath('//Route//To//Node//FileName') filename.each_with_index { |fl, i| if target_file == fl.text # we found the file, now rename it to new_file # ??????? end } } end ``` This is some example XML: ``` <?xml version="1.0" encoding="utf-8"> <my_id>123</my_id> <Route> <To> <Node> <Filename>file1.txt</Filename> <Filename>file2.mp3</Filename> <Filename>file3.doc</Filename> <Filename>file4.php</Filename> <Filename>file5.jpg</Filename> </Node> </To> </Route> </xml> ``` I want to change "file3.doc" to "file3_new.html". I would call: ``` def ammend_parent_xml("folder_location", "file3.doc", "file3_new.html") ```