我是一个类似XML的文档,由我无法控制的系统预处理。文件的格式如下:
<template>
Hello, there <RECALL>first_name</RECALL>. Thanks for giving me your email.
<SETPROFILE><NAME>email</NAME><VALUE><star/></VALUE></SETPROFILE>. I have just sent you something.
</template>
但是,我只能将文本字符串作为<template>
标记之间的内容。
我希望能够在解析时提取而不用提前指定标记。如果标签位于字符串的末尾且只有一个,我可以使用Crack gem但仅 。
使用Crack,我可以输入一个像
这样的字符串string = "<SETPROFILE><NAME>email</NAME><VALUE>go@go.com</VALUE></SETPROFILE>"
我的Crack输出是:
{"SETPROFILE"=>{"NAME"=>"email", "VALUE"=>"go@go.com"}}
然后我可以使用case
语句来表示我关心的可能值。
鉴于我需要在字符串中有多个<tags>
并且它们不能位于字符串的末尾,我如何轻松地解析节点名称和值,类似于我对crack的处理?
还需要删除这些标签。我想继续使用@TinMan的the excellent suggestion。
一旦我知道标签的名称,它就能很好地工作。标签的数量是有限的。我知道它后,我会将标签发送到适当的方法,但它需要首先轻松解析。
答案 0 :(得分:2)
使用Nokogiri,您可以将字符串视为DocumentFragment,然后找到嵌入的节点:
require 'nokogiri'
doc = Nokogiri::XML::DocumentFragment.parse(<<EOT)
Hello, there <RECALL>first_name</RECALL>. Thanks for giving me your email.
<SETPROFILE><NAME>email</NAME><VALUE><star/></VALUE></SETPROFILE>. I have just sent you something.
EOT
nodes = doc.search('*').each_with_object({}){ |n, h|
h[n] = n.text
}
nodes # => {#<Nokogiri::XML::Element:0x3ff96083b744 name="RECALL" children=[#<Nokogiri::XML::Text:0x3ff96083a09c "first_name">]>=>"first_name", #<Nokogiri::XML::Element:0x3ff96083b5c8 name="SETPROFILE" children=[#<Nokogiri::XML::Element:0x3ff96083a678 name="NAME" children=[#<Nokogiri::XML::Text:0x3ff960836884 "email">]>, #<Nokogiri::XML::Element:0x3ff96083a650 name="VALUE" children=[#<Nokogiri::XML::Element:0x3ff96083a5c4 name="star">]>]>=>"email", #<Nokogiri::XML::Element:0x3ff96083a678 name="NAME" children=[#<Nokogiri::XML::Text:0x3ff960836884 "email">]>=>"email", #<Nokogiri::XML::Element:0x3ff96083a650 name="VALUE" children=[#<Nokogiri::XML::Element:0x3ff96083a5c4 name="star">]>=>"", #<Nokogiri::XML::Element:0x3ff96083a5c4 name="star">=>""}
或者,更清晰:
nodes = doc.search('*').each_with_object({}){ |n, h|
h[n.name] = n.text
}
nodes # => {"RECALL"=>"first_name", "SETPROFILE"=>"email", "NAME"=>"email", "VALUE"=>"", "star"=>""}
获取特定标签的内容很简单:
nodes['RECALL'] # => "first_name"
迭代所有标签也很容易:
nodes.keys.each do |k|
...
end
您甚至可以用文字替换标签及其内容:
doc.at('RECALL').replace('Fred')
doc.to_xml # => "Hello, there Fred. Thanks for giving me your email. \n<SETPROFILE>\n <NAME>email</NAME>\n <VALUE>\n <star/>\n </VALUE>\n</SETPROFILE>. I have just sent you something.\n"
如何替换嵌套标签留给您作为练习。