2014-06-12 71 views
0

我無法正確編輯XML文件。我想刪除某些元素,然後添加新元素。漂亮的打印文件與REXML

<project> 
    <option> 
     <name>foo</name> 
     <state>0</state> 
    </option> 
    <option> 
     <name>bar</name> 
     <state>foo/apple</state> 
     <state>foo/orange</state> 
    </option> 
</project> 

我想刪除state的蘋果和橘子和葡萄插入,檸檬和酸橙。我曾嘗試使用此代碼:

#!/usr/bin/ruby -w 
require 'fileutils' 
require 'rexml/document' 
require 'find' 
include REXML 

path = 'C:\Users\GustavWi\Documents\Gustav\help.xml' 
xmlfile = File.new(path) 
xmldoc = Document.new(xmlfile) 
str_new_elements =["grape","lemon","lime"] 
xmldoc.elements.each("project/option") do |parent| 
    if parent.elements['name'].text == 'bar' 
     parent.elements.each do |element| 
     str = element.text.split('/') 
      if str[0] == 'foo' 
      parent.delete_element(element) 
      end 
     end 
     str_new_elements.each do |dir| 
      state = Element.new("state") 
      state.text = dir 
      parent.add_element(state) 
     end 
    end 
end 

File.open(path,"w") do |data| 
     xmldoc.write(data) 
end 

的問題是,輸出是:

<project> 
    <option> 
     <name>foo</name> 
     <state>0</state> 
    </option> 
    <option> 
     <name>bar</name> 


    <state>grape</state><state>lemon</state><state>lime</state></option> 
</project> 

的問題是空行和新元素的缺失縮進。

我使用的是Ruby 1.8.6,這可能是一個問題,但我還沒有看到任何信息,這是1.8.6中的問題。

幾乎同樣的問題,可以在著作「編程的Ruby和Pragmatic Programmers'指南」中可以看出726頁

+3

對於它的價值,我得到了一個完全不同的輸出,在Ruby 1.8.6(和2.1)上運行您的代碼。你可以用粘貼的代碼重現問題嗎? –

+0

我認爲這裏的問題是'xmldoc.write(data,0)',它從輸出中刪除縮進。如果你擺脫了0,那麼你會得到更像問題中的例子。 – Max

回答

1

上我覺得這裏的問題是XML文本節點。空白實際上並未被REXML忽略,因此在元素之間有文本節點會導致輸出出現奇怪的格式。

例如,如果你看一下你的parent.texts循環內你會看到

["\n\t\t", "\n\t\t", "\n\t\t", "\n\t"] 

這是你的元素之間的缺口。當您致電delete_element時,REXML不會觸及周圍的文本節點,這會導致空行出現在輸出中。當您撥打add_element時,REXML會在最後一個文本節點後面插入元素,即緊接在結尾</option>之前,這就是您的新元素出現在錯誤縮進級別的原因。

我看到兩個解決方案:

  1. 與文本節點猴各地輸出,以確保壓痕是不錯了。對於REXML來說,這看起來相當困難,因爲它很難保留文本節點。
  2. 如果你不關心空白,讓REXML爲你做縮進:xmldoc.write(data, 4)。然而,這也爲每個元素的文本節點增加了空格,即"bar"變爲"\n bar\n "

坦率地說,REXML並不是一個設計精良的庫。對於一個人來說,顯然不能決定如何處理空白。你嘗試過Nokogiri嗎?