2009-02-22 136 views
3

我嘗試使用REXML生成這樣的XMLREXML保留屬性訂購

<root> 
    <add key='foo' value='bar'/> 
</root> 

但我得到的是(請注意,鍵/值順序)

<root> 
    <add value='bar' key='foo'/> 
</root> 

代碼:

require 'rexml/document' 
include REXML 

doc = Document.new 
doc.add_element('root') 
el = doc.root.add_element('add') 
el.add_attribute('key', 'foo') 
el.add_attribute('value', 'bar') 
puts doc 

如果我寫的沒關係:

el.add_attribute('key', 'foo') 
el.add_attribute('value', 'bar') 

el.add_attribute('value', 'bar') 
el.add_attribute('key', 'foo') 

結果是相同的。看起來像REXML使用一些字典來保持屬性...

我可以執行所需的順序:鍵/值?

+0

您的第二個XML片段格式不正確。 – 2009-02-22 10:59:58

+0

除了可讀性,爲什麼attributs命令很重要? – 2009-02-22 11:03:54

+0

感謝您注意到xml代碼中的錯字! – alex2k8 2009-02-22 11:56:58

回答

6

在XML中,屬性的順序並不重要。如果你有一些XML處理代碼,它的重要性,那麼我會建議代碼是錯誤的。

根據XML規範here,請注意以下短語:「請注意,開始標記或空白元素標記中的屬性規範順序不重要」。

在回答你的具體問題,你是否可以強制執行某個命令,我不這麼認爲。我從來沒有真的試過這樣做(因爲它是不必要的),但是REXML的人似乎不太可能浪費時間來實現這樣的非功能:-)。由於鍵/值對以散列形式存儲,因此它們的順序可能是隨機的(就像從鍵的字母順序中可以看出的那樣)。

當然,由於Ruby附帶了REXML的源代碼,您可以(如果絕望的話)用您自己的版本(REXML2?)替換或擴充包含的副本。

既然你做一個簡單的放,那麼它可能使用非常格式化所以檢查src/rexml/formatters/pretty.rbwrite_element代碼而執行「node.attributes.each_attribute do |attr|」的開始 - 你會發現它是作爲處理前分選名單一樣簡單元素。

您可能還希望建議開發商(見bug報告和增強請求here郵件列表或here),它們使這個在未來的版本的選擇,但是,如果我是他們,我會簡單地說這是沒有必要的。

1

如果您正在修改配置文件並且格式很重要,那麼通過REXML讀取它可能更容易,但通過regexps進行修改。

另外,請記住,通過REXML生成大量XML的速度非常慢。我有一個網站不得不讀取和寫入大量的XML;我發現對於閱讀來說,REXML足夠快,但對於寫作,我不得不使用libxml。實際上,libxml的安裝非常緊迫,ruby庫對它來說太不成熟了,所以我最終使用erb來替換已經寫好的XML文檔的某些部分。

祝你好運!

6

您可以嘗試使用特設的REXML::Formatter,而不必觸摸REXML來源。A post on the ruby-talk ml表明,這種代碼:

class OrderedAttributes < REXML::Formatters::Pretty 
    def write_element(elm, out) 
     att = elm.attributes 

     class <<att 
      alias _each_attribute each_attribute 

      def each_attribute(&b) 
       to_enum(:_each_attribute).sort_by {|x| x.name}.each(&b) 
      end 
     end 

     super(elm, out) 
    end 
end 

fmt = OrderedAttributes.new 
fmt.write(doc, $stdout) 
0

有對想要保留屬性的順序了一些正當的理由。最重要的是驗證任何修改XML的程序。當維護屬性序列時,可以使用簡單的差異驗證對文檔的更改。保留將要顯示給用戶的信息序列是另一個。由於性能原因,XML標準採用了哈希映射的路徑,但我認爲規範中缺少維護序列的功能是一個主要的限制。

1

gioele的優秀解決方案的簡化版本:

如果我們做排序的屬性列表,然後輸出是確定性的,這是避免生成的XML文檔的版本之間的虛假變化的重要因素。

將這8行添加到您的腳本或應用程序中,可以在任何地方排序屬性,而不需要進一步更改(例如,修改XML寫出的方式,或查找元素隱式轉換爲字符串的每個位置,將其更改爲使用格式化程序)。

# make REXML sort attributes by name so output is deterministic 
module REXML 
    class Attributes 
    alias _each_attribute each_attribute 
    def each_attribute(&b) 
     to_enum(:_each_attribute).sort_by {|x| x.name}.each(&b) 
    end 
    end 
end