如何使用 Nokogiri Builder 创建具有命名空间根元素的 XML 文档

Posted

技术标签:

【中文标题】如何使用 Nokogiri Builder 创建具有命名空间根元素的 XML 文档【英文标题】:How to create an XML document with a namespaced root element with Nokogiri Builder 【发布时间】:2010-12-22 05:07:55 【问题描述】:

我正在为需要命名空间的 XML 数据实现导出器。我正在使用 Nokogiri 的 XML Builder(版本 1.4.0)来执行此操作,但是,我无法让 Nokogiri 创建具有命名空间的根节点。

这行得通:

Nokogiri::XML::Builder.new  |xml| xml.root('xmlns:foobar' => 'my-ns-url') .to_xml

<?xml version="1.0"?>
<root xmlns:foobar="my-ns-url"/>

这样:

Nokogiri::XML::Builder.new do |xml| 
  xml.root('xmlns:foobar' => 'my-ns-url')  xml['foobar'].child 
end.to_xml

<?xml version="1.0"?>
<root xmlns:foobar="my-ns-url">
  <foobar:child/>
</root>

但是,我需要像 &lt;foo:root&gt; 这样的东西,但这不起作用:

Nokogiri::XML::Builder.new  |xml| xml['foobar'].root('xmlns:foobar' => 'my-ns-url') .to_xml

NoMethodError: undefined method `namespace_definitions' for #<Nokogiri::XML::Document:0x11bfef8 name="document">

显然,命名空间必须在使用前定义,因此无法将其添加到根节点。

我在 Nokogiri 邮件列表中找到了“Define root node with a namespace?”,但没有任何回复。

有人有解决办法吗?

【问题讨论】:

"# Namespaces" 在 Nokogiri "Cheat sheet" 里面有信息。 【参考方案1】:
require 'rubygems'
require 'nokogiri'

puts Nokogiri::XML::Builder.new do |xml| 
  xml.root("xmlns:foo"=>"url") do
    xml.parent.namespace = xml.parent.namespace_definitions.find|ns|ns.prefix=="foo"
    xml['foo'].child
  end
end.to_xml

在定义命名空间之前,您不能使用xml['foo'],即I.E。在将其作为参数传递给根节点之前,因此,上面的代码在事后将命名空间添加到根节点。

【讨论】:

您,先生,让我免于沮丧 请注意,如果只有一个命名空间,这很好,或者 也许,如果您在 Ruby 1.9 下工作,因此可以依赖哈希参数的顺序作为相同的。否则,我会推荐xml.parent.namespace = xml.parent.namespace_definitions.find |ns| ns.prefix=="foo" (如果您不确定前缀的名称,请使用ns.href)。【参考方案2】:

在卢克的回答三年后,它变得更加简单。您现在可以使用“之前”定义的命名空间。这段代码:

require 'nokogiri'

NAMESPACES =  'xmlns:foo' => 'bar', 'xmlns:baz' => 'bat' 

builder = Nokogiri::XML::Builder.new  |xml|
  xml['foo'].RootElement(NAMESPACES) 
    xml['baz'].FirstChild
  


puts builder.to_xml

输出这个 XML:

<?xml version="1.0"?>
<foo:RootElement xmlns:foo="bar" xmlns:baz="bat">
  <baz:FirstChild/>
</foo:RootElement>

【讨论】:

由于某种原因我得到&lt;baz:FirstChild xmlns:baz="bat"/&gt; 子元素 我刚刚又试了一次,它按我描述的那样工作。使用 nokogiri 1.6.7.2、Ruby 2.3.8。 如果我没记错的话,这是关于 JRuby 问题的 Nokogiri。在 MRI 上它工作正常。【参考方案3】:

两年后,我找到了一种更简洁的方法,即使用Nokogiri::XML::Builder 的文档引用来检索根节点并向其中添加命名空间。与之前的解决方案一样,它需要根节点存在才能添加命名空间。

我已将&lt;root&gt; 元素更改为&lt;rootElement&gt;,这样更清楚:

builder = Nokogiri::XML::Builder.new do |xml| 
  xml.rootElement do
    # create a namespace and save it for later
    ns = xml.doc.root.add_namespace_definition('foo', 'my-ns-url')
    # you can also create multiple name spaces
    xml.doc.root.add_namespace_definition('bar', 'http://example.com/bar')

    # assign the saved namespace to rootElement
    xml.doc.root.namespace = ns

    xml['foo'].child
    xml['bar'].child
  end
end

现在,builder.to_xml 将返回:

<?xml version="1.0"?>
<foo:rootElement xmlns:foo="my-ns-url" xmlns:bar="http://example.com/bar">
  <foo:child/>
  <bar:child/>
</foo:rootElement>

我更喜欢这个,因为您不必搜索命名空间,并且添加多个命名空间更容易。

【讨论】:

这很好用。谢谢。但是,我无法摆脱命名空间继承。我想实现以下目标。 example.com/bar">

以上是关于如何使用 Nokogiri Builder 创建具有命名空间根元素的 XML 文档的主要内容,如果未能解决你的问题,请参考以下文章

使用 Nokogiri 的 XML Builder 添加命名空间

创建“Nokogiri::XML”或“Nokogiri::HTML”对象时如何避免创建无意义的空白文本节点

建造者模式

如何使用 Nokogiri 删除节点?

如何使用 Nokogiri 获取没有任何文本内容的完整 HTML

如何使用 Nokogiri 解析 HTML 表格?