我开始使用nokogiri-happymapper和roxml将Ruby对象转换为XML。没有缩进(" \ n")而没有指令,我无法生成XML。
是否可以选择为:indent=>0, :skip_instruct
方法设置to_xml
,就像我们在nokogiri-happymapper和roxml中为Active Support设置的那样?
此外,当我尝试使用roxml将XML转换为对象时,我得到一个包含@roxml_references
的字符串。如何正确地将XML转换为Ruby对象?
ROXML代码是:
require 'roxml'
class Book
include ROXML
xml_accessor :isbn
xml_accessor :title
xml_accessor :description
xml_accessor :author
end
book = Book.new
book.author = "ABC"
book.title = "Ruby"
doc = Nokogiri::XML::Document.new
doc.root = book.to_xml
puts doc.to_s
输出:
"<?xml version=\"1.0\"?>\n<book>\n <title>Ruby</title>\n <author>ABC</author>\n</book>\n"
和
obj = Book.from_xml(doc.to_s)
puts obj
输出:
#<Mod::Book:0x00000003141718 @author="ABC", @title="Ruby", @roxml_references=[#<ROXML::XMLTextRef:0x00000003141650 @opts=#<ROXML::Definition
:0x000000031b93f8 @default=nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @namespace=nil, @ac
cessor="isbn", @array=false, @blocks=[], @sought_type=:text, @attr_name="isbn", @name="isbn">, @instance=#<Mod::Book:0x00000003141718 ...>,
@default_namespace=nil>, #<ROXML::XMLTextRef:0x00000003141628 @opts=#<ROXML::Definition:0x000000031b8930 @default=nil, @to_xml=nil, @name_ex
plicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @namespace=nil, @accessor="title", @array=false, @blocks=[], @sought_typ
e=:text, @attr_name="title", @name="title">, @instance=#<Mod::Book:0x00000003141718 ...>, @default_namespace=nil>, #<ROXML::XMLTextRef:0x000
00003141600 @opts=#<ROXML::Definition:0x000000031a3fa8 @default=nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=n
il, @wrapper=nil,
nokogiri-happymapper代码是:
require 'happymapper'
class Book
include HappyMapper
attr_accessor :title,:author
tag 'book'
element :title, String, :tag => 'title'
element :author, String, :tag => 'author'
end
book = Mod::Book.new
book.author = "ABC"
book.title = "Ruby"
xml_obj = book.to_xml
p xml_obj
输出:
"<?xml version=\"1.0\"?>\n<book>\n <title>Ruby</title>\n <author>ABC</author>\n</book>\n"
和
obj = Mod::Book.parse(xml_obj)
p obj
输出:
#<Mod::Book:0x00000000661cf0 @author="ABC", @title="Ruby">
如何从对象生成XML时删除缩进,以及两种方法的XML指令?
我尝试过以下方法: 方法1:
xml = Nokogiri::XML(xml_obj).to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
p xml
输出
"<book>\n <title>Ruby</title>\n <author>ABC</author>\n</book>\n"
方法2:
xml = Nokogiri::XML::Document.parse(xml_obj, nil,nil, Nokogiri::XML::ParseOptions::NOBLANKS).root.to_s
p xml
输出
"<book>\n <title>Ruby</title>\n <author>ABC</author>\n</book>"
我使用以下方法将对象转换为roxml中的xml:
xml_obj = lib.to_xml.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::AS_XML)
p xml_obj
输出:
"<Library><author><name>Shruti</name></author><book><title>RoR</title></book></Library>"
现在,当我尝试将xml转换回对象时,它为我提供了一个额外的实例变量@roxml_references,如下所示:
obj = Library.from_xml(xml_obj)
p obj
输出:
#<Library:0x00000002a1ebc0 @author=#<Author:0x00000002a1c780 @name="Shruti", @roxml_references=[#<ROXML::XMLTextRef:0x00000002a1e1e8 @opts=#
<ROXML::Definition:0x00000002a46418 @default=nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @
namespace=nil, @accessor="name", @array=false, @blocks=[], @sought_type=:text, @attr_name="name", @name="name">, @instance=#<Author:0x000000
02a1c780 ...>, @default_namespace=nil>]>, @book=[#<Book:0x00000002a08e60 @title="RoR", @roxml_references=[#<ROXML::XMLTextRef:0x00000002a092
e8 @opts=#<ROXML::Definition:0x00000002a3e8d0 @default=nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrap
per=nil, @namespace=nil, @accessor="title", @array=false, @blocks=[], @sought_type=:text, @attr_name="title", @name="title">, @instance=#<Bo
ok:0x00000002a08e60 ...>, @default_namespace=nil>, #<ROXML::XMLTextRef:0x00000002a09400 @opts=#<ROXML::Definition:0x00000002a3d6b0 @default=
nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @namespace=nil, @accessor="description", @arra
y=false, @blocks=[], @sought_type=:text, @attr_name="description", @name="description">, @instance=#<Book:0x00000002a08e60 ...>, @default_na
mespace=nil>], @description=nil>], @roxml_references=[#<ROXML::XMLObjectRef:0x00000002a1eb20 @opts=#<ROXML::Definition:0x00000002a3c080 @def
ault=nil, @to_xml=nil, @name_explicit=false, @cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @namespace=nil, @accessor="author", @arra
y=false, @blocks=[], @sought_type=Author, @attr_name="author", @name="author">, @instance=#<Library:0x00000002a1ebc0 ...>, @default_namespac
e=nil>, #<ROXML::XMLObjectRef:0x00000002a1eaf8 @opts=#<ROXML::Definition:0x00000002a373c8 @default=nil, @to_xml=nil, @name_explicit=false, @
cdata=nil, @required=nil, @frozen=nil, @wrapper=nil, @namespace=nil, @accessor="book", @array=true, @blocks=[], @sought_type=Book, @attr_nam
e="book", @name="book">, @instance=#<Library:0x00000002a1ebc0 ...>, @default_namespace=nil>]>
有没有办法可以从创建的对象中删除@roxml_references
?
答案 0 :(得分:1)
如果在搜索文档并咨询gem的作者后仍然找不到解决方案,那么让Nokogiri解析输出,删除节点并重新输出它而不缩进。
考虑一下:
require 'nokogiri'
xml = <<EOT
<root>
</root>
EOT
Nokogiri::XML(xml)
# => #<Nokogiri::XML::Document:0x3ffd49419494 name="document" children=[#<Nokogiri::XML::Element:0x3ffd49419084 name="root" children=[#<Nokogiri::XML::Text:0x3ffd49418df0 "\n">]>]>
注意上面包含“\ n”的Nokogiri :: XML :: Text节点。那是XML中<root>
之后的行尾:
doc.to_xml # => "<?xml version=\"1.0\"?>\n<root>\n</root>\n"
以下是我们如何找到文本节点:
doc.search('//text()') # => [#<Nokogiri::XML::Text:0x3fff88c18d20 "\n">]
'//text()'
是一个XPath选择器,意思是“在整个文档中搜索文本节点。
我们可以遍历DOM并删除那些空节点:
doc.search('//text()').each do |text_node|
text_node.unlink
end
doc.to_xml # => "<?xml version=\"1.0\"?>\n<root/>\n"
我们必须要小心,因为Nokogiri :: XML :: Text节点不仅可以包含尾随行尾,因此不加选择的节点删除也会删除所需的文本。我们也可以删除节点的内容,使其成为空的:
xml = <<EOT
<root>
<foo>bar</foo>
</root>
EOT
doc = Nokogiri::XML(xml)
doc.search('//text()') # => [#<Nokogiri::XML::Text:0x3ff77201927c "\n ">, #<Nokogiri::XML::Text:0x3ff772018e80 "bar">, #<Nokogiri::XML::Text:0x3ff772018c14 "\n">]
doc.search('//text()').each do |text_node|
text_node.content = ''
end
doc.to_xml # => "<?xml version=\"1.0\"?>\n<root><foo></foo></root>\n"
但请注意删除了所需的文字“bar”。解决方案是更具选择性:
doc.search('//text()').each do |text_node|
text_node.content = '' if text_node.content.strip.empty?
end
doc.to_xml # => "<?xml version=\"1.0\"?>\n<root><foo>bar</foo></root>\n"
注意:Nokogiri包含一个NOBLANKS
解析选项,旨在帮助删除缩进节点,但根据“Unexpected behavior with XML_PARSE_NOBLANKS”,如果它认为'底层libXML2库将不会忽略空白d导致返回无效的DOM。
如果您不想使用XMLdecl,可以告诉Nokogiri将文档解析为DocumentFragment:
xml = <<EOT
<root>
</root>
EOT
doc = Nokogiri::XML(xml)
doc.to_xml # => "<?xml version=\"1.0\"?>\n<root>\n</root>\n"
doc = Nokogiri::XML::DocumentFragment.parse(xml)
doc.to_xml # => "<root>\n</root>\n"