13

我正在为需要命名空间的 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>

但是,我需要类似的东西<foo:root>,但这不起作用:

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? ”,但没有回复。

有没有人有办法解决吗?

4

3 回答 3

16
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']在定义命名空间之前使用 IE,然后将其作为参数传递给根节点,因此,上面的代码将命名空间事后添加到根节点。

于 2009-12-06T19:14:04.777 回答
8

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

我已将<root>元素更改为,<rootElement>以便更清楚:

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>

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

于 2012-03-28T01:02:45.383 回答
3

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

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>
于 2015-12-01T17:02:41.400 回答