如何使用Nokogiri的noblanks

时间:2013-08-04 06:46:26

标签: ruby nokogiri

我有一个XML文档:

<?xml version="1.0"?>
<installation id="ayfw-a">
</installation>

我正在为此文档添加一个子节点,如下所示:

data = Nokogiri::XML(IO.read('file')) { |doc| doc.noblanks }
new_record = Nokogiri::XML::Node.new('tag', data)
data.root.add_child(new_record)
File.open('file', 'w') { |dh_file| dh_file.write(data.to_xml(:indent => 4)) }

使用此代码,我可以在我的文件中找到它:

<?xml version="1.0"?>
<installation id="ayfw-a">
<tag/></installation>

此处noblanks不起作用。 但是,如果在插入新节点之前我的文件已经有一个子节点,noblanks工作正常:

在插入新节点之前:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <!---->
</installation>

插入新节点后:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <!---->
    <tag/>
</installation>

因此,看起来noblanks只有在已经看到“模式”时才有效。如果没有任何孩子,我有没有办法正确地缩进我的XML?


也许noblanks不适合使用,但出于某种原因,如果<installation>下已有一些节点,则可以使用<?xml version="1.0"?> <installation id="ayfw-a"> <tag/></installation> 。基本上我在添加子节点时的目前是:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <tag/>
</installation>

我需要的是:

{{1}}

我添加的子节点必须为空,并且为了简单起见,我会抑制一些属性。

2 个答案:

答案 0 :(得分:0)

你的两个例子令人迷惑:它们都表现出完全相同的行为,但你说其中一个做了不同的事情。

据我所知,指定noblanks永远不会删除空节点:

xml.xml:

<?xml version="1.0"?>
<root>
  <installation id="ayfw-a"></installation>
  <dog></dog>
  <cat/>
</root>

require 'nokogiri'

data = Nokogiri::XML(IO.read('xml.xml')) { |doc| doc.noblanks }
puts data

--output:--
<?xml version="1.0"?>
<root>
  <installation id="ayfw-a"/>
  <dog/>
  <cat/>
</root>

我希望输出为:

<root>
  <installation id="ayfw-a"></installation>
</root>

当然,可怕的Nokogiri文档(典型的Ruby)没有定义空白节点是什么。显然,noblanks的作用范围是转换这样的节点:

<dog></dog>

为:

<dog/>

<强>更新

啊,所以你的问题在于你的XML的漂亮打印。好的,我看到你遇到同样的问题。让我告诉你如何问你的问题:


我无法按照我想要的方式格式化XML:

xml.xml:

<?xml version="1.0"?>
<installation id="ayfw-a">
</installation>

require 'nokogiri'

data = Nokogiri::XML(IO.read('xml.xml')) {|doc| doc.noblanks}
new_record = Nokogiri::XML::Node.new('tag', data)
data.root.add_child(new_record)
puts data.to_xml(indent: 4, indent_text: ".")

--output:--
<?xml version="1.0"?>
<installation id="ayfw-a">
<tag/></installation>

to_xml()方法似乎无法正常工作。我期望输出为:

<?xml version="1.0"?>
<installation id="ayfw-a">
....<tag/>
</installation>

但是to_xml()方法在标记具有预先存在的子节点时以我想要的方式格式化输出:

xml.xml:

<?xml version="1.0"?>
<installation id="ayfw-a">
  <dog>Rover</dog>
</installation>

require 'nokogiri'

data = Nokogiri::XML(IO.read('xml.xml')) {|doc| doc.noblanks}
new_record = Nokogiri::XML::Node.new('tag', data)
data.root.add_child(new_record)
puts data.to_xml(indent: 4, indent_text: ".")

--output:--
<?xml version="1.0"?>
<installation id="ayfw-a">
....<dog>Rover</dog>
....<tag/>
</installation>

如何让Nokogiri在第一种情况下按照我想要的方式格式化输出?


看起来Nokogiri的打印机效果不错。似乎REXML拥有比Nokogiri更好的漂亮打印机:

xml.xml:

<?xml version="1.0"?>
<installation id="ayfw-a">
</installation>

require 'nokogiri'

data = Nokogiri::XML(IO.read('xml.xml')) {|doc| doc.noblanks}
new_record = Nokogiri::XML::Node.new('tag', data)
data.root.add_child(new_record)
puts data.to_xml(indent: 4, indent_text: ".")

require "rexml/document"

REXML::Document.new(data.to_xml).write(File.open("output.txt", "w"), indent_spaces = 4)


--output:--
<installation id="ayfw-a">
<tag/></installation>

$ cat output.txt
<?xml version='1.0'?>
<installation id='ayfw-a'>
    <tag/>
</installation>

答案 1 :(得分:0)

漂亮的打印XML不是正确XML的保证,它只是“漂亮”。 Nokogiri生成有效的XML,这一点非常重要。

如果你必须有一个特定的起始格式,请为Nokogiri创建一个小模板进行解析,然后构建它:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<installation id="ayfw-a">
  <tag/>
</installation>
EOT

puts doc.to_xml

生成:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <tag/>
</installation>

稍微调整一下代码可以让我设置起始root节点的ID和嵌入标记的名称:

require 'nokogiri'

ID = 'ayfw-a'
TAG = 'foo'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<installation id="#{ ID }">
    <#{ TAG }/>
</installation>
EOT

puts doc.to_xml

哪个输出:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <foo/>
</installation>

另一种写这个的方法是:

require 'nokogiri'

ID = 'ayfw-a'
TAG = 'foo'

doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<installation>
    <tag/>
</installation>
EOT

doc.root['id'] = ID
doc.at('tag').name = TAG

puts doc.to_xml

哪个输出:

<?xml version="1.0"?>
<installation id="ayfw-a">
    <foo/>
</installation>

无论您做什么,它都可以让您解决问题并提高工作效率。