Nokogiri 1.10.3
Ruby 2.4.5
我有许多复杂的XML文本字符串可添加到具有标准标头组合的文档中,我通过使用Builder来创建带有标头的文档,然后遍历这些字符串以达到此目的。将它们添加进来。
将#to_xml
发送到Nokogiri::XML::Builder
时,回车和行首缩进将从文档中丢失,除非它们出现在已添加的xml字符串中。
似乎只有XML字符串本身包含\n
。
示例
好:没有添加XML字符串的生成器。结果XML字符串具有回车符和缩进:
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
end ; 0
xml.to_xml
=> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Message>\n <Header>\n <NumberOne>1</NumberOne>\n <NumberTwo>2</NumberTwo>\n </Header>\n</Message>\n"
例如,注意\n
和</NumberOne>
和<NumberTwo>
之间的空格。
好:添加了XML字符串且XML字符串没有回车符的Builder。结果XML字符串具有回车符和缩进:
xml_text1 = "<text>text1</text>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
xml << xml_text1
end ; 0
xml.to_xml
=> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Message>\n <Header>\n <NumberOne>1</NumberOne>\n <NumberTwo>2</NumberTwo>\n </Header>\n <text>text1</text>\n</Message>\n"
错误:添加了XML字符串且XML字符串 do 的生成器具有回车符。所得的XML字符串具有回车符和缩进,但插入的XML字符串除外:
xml_text1 = "<text1>text1</text1>\n<text2>text2</text2>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
xml << xml_text1
end ; 0
xml.to_xml
=> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Message><Header><NumberOne>1</NumberOne><NumberTwo>2</NumberTwo></Header><text1>text1</text1>\n<text2>text2</text2></Message>\n"
请注意,\n
和空格已删除。
让XML内容包含回车符是合法的,因此恐怕我无法将所有回车符从字符串中移出。
还有另一种方法来包含这些可能不会引起此类问题的文本字符串吗?
编辑
正如@igneus指出的,导致这种行为的是XML元素之间任何文本的存在。
例如:
xml_text1 = "<text1>tex<b> <b>t1</text1> <text2>text2</text2>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
xml << xml_text1.gsub(/>\n {0,}</, "><")
end ; 0
xml.to_xml
=> "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Message><Header><NumberOne>1</NumberOne><NumberTwo>2</NumberTwo></Header><text1>tex<b> <b>t1</b></b></text1> <text2>text2</text2></Message>\n"
实际上,当将文本字符串转换为片段时,我们会看到额外的Nokogiri::XML::Text
对象,其中包含一个空格(或在前面的示例中带有\n
,\n
等)
xml_text1 = "<text1>tex<b> <b>t1</text1> <text2>text2</text2>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
=> #<Nokogiri::XML::DocumentFragment:0x3fff1805bcb4 name="#document-fragment" children=[#<Nokogiri::XML::Element:0x3fff1805b700 name="text1" children=[#<Nokogiri::XML::Text:0x3fff1805a4f4 "tex">, #<Nokogiri::XML::Element:0x3fff1805a3b4 name="b" children=[#<Nokogiri::XML::Text:0x3fff19a93fc8 " ">, #<Nokogiri::XML::Element:0x3fff19a93dac name="b" children=[#<Nokogiri::XML::Text:0x3fff19a93a3c "t1">]>, #<Nokogiri::XML::Text:0x3fff19a93730 " ">, #<Nokogiri::XML::Element:0x3fff19a9358c name="text2" children=[#<Nokogiri::XML::Text:0x3fff19a93258 "text2">]>]>]>]>
#to_xml
不会忽略这些元素
xml.doc.fragment(xml_text1).to_xml(indent: 0)
=> "<text1>tex<b> <b>t1</b> <text2>text2</text2></b></text1>"
那么可以通过的解决方案是删除那些Text元素?
答案 0 :(得分:1)
XML序列化由基础libxml2处理。 "If libxml2 detects that there is already some text nodes as children of a node it will disable automatic indenting for the whole subtree."不能更改此libxml2行为。
在您的示例中,这样的文本节点是由元素之间的换行符产生的,但是对于元素间的文本也是如此。由于将文本节点添加到了根元素,因此整个文档都没有缩进。如果将它添加到文档结构的某处,只有包含它的子树缺少缩进:
xml_text1 = "<text1>text1</text1>a<text2>text2</text2>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
# wrapper element added
xml.Wrapper do
xml << xml_text1
end
end
puts xml.to_xml
只有<Wrapper>
的内容没有缩进:
<?xml version="1.0" encoding="utf-8"?>
<Message>
<Header>
<NumberOne>1</NumberOne>
<NumberTwo>2</NumberTwo>
</Header>
<Wrapper><text1>text1</text1>a<text2>text2</text2></Wrapper>
</Message>
一个可能有用的技巧是自己解析XML字符串并删除不需要的文本元素:
xml_text1 = "<text1>text1</text1>\n<text2>text2</text2>"
xml = Nokogiri::XML::Builder.new(encoding: "utf-8")
xml.Message do
xml.Header do
xml.NumberOne "1"
xml.NumberTwo "2"
end
doc.fragment(xml_text1).children.each do |node|
# drop all whitespace-only text nodes
next if node.text? && node.content =~ /\A\s+\Z/
insert node
end
end