我有一个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}}
我添加的子节点必须为空,并且为了简单起见,我会抑制一些属性。
答案 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>
无论您做什么,它都可以让您解决问题并提高工作效率。