Ruby Regexp to extract specific elements in an XML string
I have a simple XML string, that is more or less always the same. I'd rather avoid using an XML parser for such a little piece of code, and I though Regexp would help.
The XML string looks like :
<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.extendedPing</methodName>
<params>
<param>
<value>Official Google Blog</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/atom.xml</value>
</param>
</params>
</methodCal开发者_Go百科l>
I want to extract the values of each param (and maintain the order).
I came up with /<value>(.*)<\/value>/xi
but that just macthes the very first value :/
Parsing XML with Ruby is trivial, please don't try to parse XML with a regular expression - it is notoriously difficult and error-prone.
While it may be tempting to try and use a regular expression, please don't. No matter how hard you try to smash that nail with the screwdriver it won't work as a hammer - please use one of the many wonderful hammers at your disposal.
Normally you should use an XML parser, but I still think it's a bit overkill.
If you are like me, I would do it like this:
x = File.new("test.xml", "r").read
puts x.scan(/<value>(.*)<\/value>/)
Which results in:
Official Google Blog
http://googleblog.blogspot.com/
http://googleblog.blogspot.com/
http://googleblog.blogspot.com/atom.xml
If you want to loop over each value, you can do it like this:
x.scan(/<value>(.*)<\/value>/) do |x|
puts x
end
As just a side comment, for this specific application it may feel difficult but learning Nokogiri or libXML may help you make a decision about more complex XML parsing down the line. Besides, parsing XML in Ruby really is pretty trivial nowadays and doing it The Right Way will at least make it easy to expand to a non-trivial method when your client eventually requests that you do something ridiculously out of scope which involves full XML parsing. :)
For other frameworks and technology I probably wouldn't recommend such investment, but Nokogiri is painless. And if you just feel like playing you could try out Hpricot and get your dose of _why for the day (RIP).
I see no reason for using a regex instead of a real parser. Simplicity of use is a horrible excuse that doesn't prove to be true:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.extendedPing</methodName>
<params>
<param>
<value>Official Google Blog</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/</value>
</param>
<param>
<value>http://googleblog.blogspot.com/atom.xml</value>
</param>
</params>
</methodCall>
EOT
puts doc.search('value').map(&:text)
Running that outputs:
Official Google Blog
http://googleblog.blogspot.com/
http://googleblog.blogspot.com/
http://googleblog.blogspot.com/atom.xml
If there is need to be more specific, drill down with a more specific CSS path:
doc.search('param value')
Using a regex such as %r(<value>(.*)</value>)
will 'splode if the contained text contains "</value>"
and trapping those situations dives down a very deep rabbit hole.
精彩评论