繁体   English   中英

用REXML编写命名空间的XML

[英]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>

解释如下:

  1. each_element_with_attribute遍历所有具有属性xmlns xml节点。
  2. namespaces返回一个包含该节点所有名称空间(包括其祖先)的哈希,例如,对于bar ,它将为: {"xmlns"=>"http://foo.com/", "bar"=>"http://bar.org/"}
  3. namespace空间通过检查其属性和祖先,返回最适合该节点的名称空间。 对于bar它返回http://bar.org/
  4. name=访问者同时分配一个简短的名称和一个扩展的名称(如果存在,最后一个将用于渲染)
  5. 最后, delete_namespace删除多余xmlns='http://bar.org/'bar

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM