[英]Writing namespaced XML with REXML
我正在使用涉及多個名稱空間的XML(特別是ResourceSync ,它在Sitemap文檔中嵌入了名稱空間的標記)。
創建REXML元素時,可以設置全局名稱空間:
foo = REXML::Element.new('foo')
foo.add_namespace('http://foo.com/')
puts foo # outputs <foo xmlns='http://foo.com/'/>
我可以創建一個帶有前綴的名稱空間:
foo.add_namespace('bar', 'http://bar.org/')
puts foo # outputs <foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'/>
但是,如果我隨后添加了另一個與前綴具有相同名稱空間URI的元素,但未明確使用前綴-
bar = REXML::Element.new('bar')
bar.add_namespace('http://bar.org/')
foo.add_element(bar)
-REXML不夠聰明,無法注意到前綴的存在並使用它。 而不是預期的
<foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'>
<bar:bar/>
</foo>
我得到了不必要的冗長:
<foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'>
<bar xmlns='http://bar.org/'/>
</foo>
我可以通過完全忽略名稱空間URI並僅將前綴修改為元素名稱來解決此問題:
baz = REXML::Element.new('bar:baz')
foo.add_element(baz)
但是,在創建元素時,我唯一可以確定的就是名稱空間URI -我不知道它將添加到哪個父元素或那里可能存在什么名稱空間前綴。 (而且名稱空間前綴實際上並不是邏輯文檔模型的一部分,而名稱空間URI確實是。)
有沒有辦法讓REXML在輸出時解析前綴,和/或有一種直接的方法來對REXML文檔進行后處理以使用前綴?
請注意,我並不是要尋找Nokogiri解決方案,因為我使用的是庫,即內部使用REXML的xml映射 (碰巧,它似乎也沒有任何名稱空間的概念,但是我已經找到解決該問題的方法)。
試試這個代碼:
require 'rexml/document'
foo = REXML::Element.new('foo')
foo.add_namespace('http://foo.com/')
foo.add_namespace('bar', 'http://bar.org/')
bar = REXML::Element.new('bar')
bar.add_namespace('http://bar.org/')
foo.add_element(bar)
def normalize_namespace!(elem)
if elem.attributes['xmlns']
prefix = elem.namespaces.reject { |key, _| key == 'xmlns' }.key(elem.namespace)
elem.name = "#{prefix}:#{elem.name}"
elem.delete_namespace
end
end
foo.root.each_element_with_attribute('xmlns') { |e| normalize_namespace!(e) }
puts foo
# => <foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'><bar:bar/></foo>
解釋如下:
each_element_with_attribute
遍歷所有具有屬性xmlns
xml節點。 namespaces
返回一個包含該節點所有名稱空間(包括其祖先)的哈希,例如,對於bar
,它將為: {"xmlns"=>"http://foo.com/", "bar"=>"http://bar.org/"}
namespace
空間通過檢查其屬性和祖先,返回最適合該節點的名稱空間。 對於bar
它返回http://bar.org/
。 name=
訪問者同時分配一個簡短的名稱和一個擴展的名稱(如果存在,最后一個將用於渲染) delete_namespace
刪除多余xmlns='http://bar.org/'
上bar
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.