考虑一个XML文档
<string id = "id1" ><p> Text1 </p>
<p> Text 3 <\p>
</string>
<string id = "id2" > Text2 </string>
我想更新字符串标签的内容,即将“Text1”替换为“Apple”,将“Text2”替换为“boy”。正如我在第一个语句中提到的那样,“Text1”没有直接封装在字符串标签中,它直接封装在其他标签中(这里是<p>
但在输入文件中它可以是任意标签或{{1}内部1}}标签可以有一个标签,里面会有<p>
我试图这样做,但可以完成只更改“Text2”,因为它直接封装在字符串标记中
"Text1"
有人可以建议我在我的例子中修改“Text1”。
答案 0 :(得分:0)
下面有一个想法,怎么做。此程序针对所有string
个节点进行迭代,当节点具有非文本子节点时,它将替换子内容。它适用于您的示例(请注意我必须使用<xml>
标记包围您的XML),但是,再次将其视为一个想法。
require 'nokogiri'
xml = "<xml><string id = \"id1\" ><p> Text1 </p></string>\n<string id = \"id2\" > Text2 </string></xml>"
doc = Nokogiri::XML.parse(xml)
doc.xpath('//string').each do |s|
case s.child
when Nokogiri::XML::Text
s.content = "boy"
when Nokogiri::XML::Element
s.child.content = "Apple"
end
end
puts doc.to_xml
输出:
<?xml version="1.0"?>
<xml><string id="id1"><p>Apple</p></string>
<string id="id2">boy</string></xml>
答案 1 :(得分:0)
以下是使用xpath
&#39; text()
和normalize-space()
执行此操作的方法:
doc.css("text()[normalize-space()='Text1']").each { |n| n.content = "Apple" }
doc.css("text()[normalize-space()='Text2']").each { |n| n.content = "boy" }
puts doc.to_s
# <?xml version="1.0"?>
# <xml><string id="id1"><p>Apple</p></string>
# <string id="id2">boy</string></xml>
答案 2 :(得分:0)
因为其他两个答案都没有真正适用于所有操作的可能性,所以我修改了两个答案:
公共代码:
require 'nokogiri'
#Setting Nokogiri's parser options on the following line to strict(the default)
#and noblanks tells Nokogiri to ignore Text nodes that contain only whitespace:
xml_doc = Nokogiri::XML(<<END_OF_XML) { |config| config.strict.noblanks }
<root>
<not>Text1</not>
<string id = "id1" >
<p> Text1 </p>
<p> Text 3 </p>
</string>
<string id = "id2" > Text2 </string>
<string id="id3">
<p><p><p>Text1</p></p></p>
</string>
<not>Text2</not>
</root>
END_OF_XML
1)标准化空间答案与:
没有区别new_xml = xml_doc.to_s.gsub('Text1', 'Apple').gsub('Text2', 'boy')
以下是一些更改,因此仅在<string>
标记内发生替换:
xml_doc.xpath('//string').each do |string_tag|
string_tag.css(
"text()[normalize-space()='Text1']"
).each { |n| n.content = "Apple" }
string_tag.css(
"text()[normalize-space()='Text2']"
).each { |n| n.content = "boy" }
end
puts xml_doc.to_s
--output:--
<?xml version="1.0"?>
<root>
<not>Text1</not>
<string id="id1">
<p>Apple</p>
<p> Text 3 </p>
</string>
<string id="id2">boy</string>
<string id="id3">
<p><p><p>Apple</p></p></p>
</string>
<not>Text2</not>
</root>
您也可以这样写:
xml_doc.xpath("//string//text()[normalize-space()='Text1']"
).each { |n| n.content = "Apple" }
xml_doc.xpath("//string//text()[normalize-space()='Text2']"
).each { |n| n.content = "boy" }
puts xml_doc.to_s
但是你必须搜索整个xml_doc两次,我认为一次搜索两个文本的每个字符串标签可能更有效。
原始答案也使用了css()方法的无记录(据我所知)xpath。根据文档,css()的参数需要是一个css选择器,而xpath不是一个css选择器,所以使用xpath不应该工作。
2)案例陈述的答案有点不同,因为从你的帖子中不清楚你是在搜索特定的文本,还是想用&#34; boy&#34;替换一个直接的文本节点,以及嵌套文本节点替换为&#34; Apple&#34;。
def get_base_text_node(node)
child_node = node.child
case child_node
when Nokogiri::XML::Text
child_node
when Nokogiri::XML::Element
get_base_text_node(child_node)
end
end
xml_doc.xpath('//string').each do |s|
case s.child
when Nokogiri::XML::Text
s.content = "boy"
else
text_node = get_base_text_node(s)
text_node.content = "Apple"
end
end
puts xml_doc.to_xml
--output:--
<?xml version="1.0"?>
<root>
<not>Text1</not>
<string id="id1">
<p>Apple</p>
<p> Text 3 </p>
</string>
<string id="id2">boy</string>
<string id="id3">
<p>
<p>
<p>Apple</p>
</p>
</p>
</string>
<not>Text2</not>
</root>