首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用REXML编写命名空间XML

用REXML编写命名空间XML
EN

Stack Overflow用户
提问于 2015-05-18 23:07:30
回答 1查看 458关注 0票数 1

我正在处理一些涉及多个名称空间的XML (特别是ResourceSync,它将名称空间标记嵌入到网站地图文档中)。

创建REXML元素时,可以设置全局命名空间:

代码语言:javascript
复制
foo = REXML::Element.new('foo')
foo.add_namespace('http://foo.com/')

puts foo # outputs <foo xmlns='http://foo.com/'/>

我可以创建一个带有前缀的命名空间:

代码语言:javascript
复制
foo.add_namespace('bar', 'http://bar.org/')

puts foo # outputs <foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'/>

但是,如果我随后添加了另一个具有与前缀相同的命名空间URI的元素,但没有显式地使用前缀--

代码语言:javascript
复制
bar = REXML::Element.new('bar')
bar.add_namespace('http://bar.org/')
foo.add_element(bar)

- REXML不够聪明,不能注意前缀的存在并使用它。而不是预期的

代码语言:javascript
复制
<foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'>
  <bar:bar/>
</foo>

我得到的是不必要的冗长:

代码语言:javascript
复制
<foo xmlns:bar='http://bar.org/' xmlns='http://foo.com/'>
  <bar xmlns='http://bar.org/'/>
</foo>

我可以完全忽略名称空间URI,只需将前缀插入元素名称,就可以解决这个问题:

代码语言:javascript
复制
baz = REXML::Element.new('bar:baz')
foo.add_element(baz)

但是,在创建元素时,我唯一确定的是名称空间URI --我不知道它将添加到哪个父元素中,也不知道那里可能存在哪些名称空间前缀。(名称空间前缀实际上并不是逻辑文档模型的一部分,而名称空间URI确实是。)

是否有一种方法可以让REXML在输出时解析前缀,以及/或一种简单的方法来对REXML文档进行后处理以使用前缀?

请注意,我不是在寻找例如Nokogiri解决方案,因为我使用的是在内部使用REXML的库xml映射 (碰巧,它似乎也没有任何名称空间的概念,但我已经找到了解决这个问题的方法)。

EN

回答 1

Stack Overflow用户

发布于 2015-09-25 22:45:57

试试下面的代码:

代码语言:javascript
复制
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_namespacebar上删除额外的xmlns='http://bar.org/'
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30314175

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档