I’m trying for the first time to play with XML and Ruby.
Since I have only the core library at the moment, my choice went
directly for REXML.
So, here is my problem.
I’m willing to get a specific element in my xml file.
Normally I would do something like this:
doc.root.elements[“programmer[@name=‘Matz’]”]
But let’s say I have a user interface, and I let a user enter the
programmer he wants to see. How can I look for an element using a
variable?
I hoped something like this would work:
entered_name = ‘Matz’
doc.root.elements[“magician[@name=#{entered_name}]”]
Unfortunately, it didn’t…
After trying a few things, check with uncle google and in this forum,
I’m driving out of clues, so I’d appreciate if someone could show me the
correct way!
But let’s say I have a user interface, and I let a user enter the
programmer he wants to see. How can I look for an element using a
variable?
I hoped something like this would work:
entered_name = ‘Matz’
doc.root.elements[“magician[@name=#{entered_name}]”]
You forgot the single quotes around #{}, i.e. you must only replace
“Matz” with “#{entered_name}”:
After trying a few things, check with uncle google and in this forum,
I’m driving out of clues, so I’d appreciate if someone could show me the
correct way!
But let’s say I have a user interface, and I let a user enter the
programmer he wants to see. How can I look for an element using a
variable?
I hoped something like this would work:
entered_name = ‘Matz’
doc.root.elements[“magician[@name=#{entered_name}]”]
Unfortunately, it didn’t…
You are missing the ‘-s.
Try
doc.root.elements["programmer[@name=’#{entered_name}']"]
That doesn’t work for me. And I couldn’t figure out the escaping
necessary to handle both a name entered with a single quote or a double
quote. I thought I understood ruby escaping, but not anymore.
That doesn’t work for me. And I couldn’t figure out the escaping
necessary to handle both a name entered with a single quote or a double
quote. I thought I understood ruby escaping, but not anymore.
You understand Ruby escaping - just not XPath escaping. There is none.
Ah. Ok.
If you
use ’ to delimit a string, you cannot use ’ inside it. I would love to
be proven
wrong, but I did research this for quite a while.
Why didn’t my $name substitution work? It’s in the rdocs…
That doesn’t work for me. And I couldn’t figure out the escaping
necessary to handle both a name entered with a single quote or a double
quote. I thought I understood ruby escaping, but not anymore.
You understand Ruby escaping - just not XPath escaping. There is none.
If you
use ’ to delimit a string, you cannot use ’ inside it. I would love to
be proven
wrong, but I did research this for quite a while.
Why didn’t my $name substitution work? It’s in the rdocs…
The following code works when the user types in John or Joh’n but not
Joh"n:
<xml version=“1.0” encoding=“ISO-8859-1”?>
Joh’n
John
Joh"n
require ‘rexml/document’
include REXML
f = File.new(‘xml4.xml’)
doc = Document.new(f)
input_name = gets
input_name = input_name.chomp
p input_name
target = XPath.match(doc, “//programmer[text() = “#{input_name}”]”)
p target
puts target[0].attributes[“age”]
$ruby r1test.rb
Joh"n
“Joh"n”
/usr/lib/ruby/1.8/rexml/xpath_parser.rb:124:in internal_parse': undefined methodnode_type’ for “Joh”:String (NoMethodError)
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:123:in each' from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:123:ininternal_parse’
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:49:in match' from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:402:inPredicate’
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:346:in Predicate' from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:204:ininternal_parse’
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:199:in times' from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:199:ininternal_parse’
… 9 levels…
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:49:in match' from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:34:inparse’
from /usr/lib/ruby/1.8/rexml/xpath.rb:59:in `match’
from r1test.rb:11
There are several flaws in your code: First, $input_name is not the
same variable as input_name. Second, according to the REXML
documentation the variables hash for the XPath query is in fact the
fourth argument to XPath#match, not the third. The third one is for the
namespaces hash. And lastly, you have to use strings as keys here, not
symbols (took me some time to figure that one out). So this does the
trick:
require ‘rexml/document’
include REXML
doc = Document.new(DATA)
input_name = gets.chomp
p input_name
target = XPath.match(doc, “//programmer[text()=$name]”, {}, “name” =>
input_name)
p target
Nice. I downloaded the REXML docs and took a look around. A question:
how in the hell would anyone know to use a $ variable in there, and that
a hash specified as the 4th argument would somehow match a value to that
variable, when all the docs say is:
Ha, actually, I hadn’t worked with XPath before, so I didn’t really know
what it was about.
It’s actually pretty cool, you can access any elements directly.
for instance:
the_lang = ‘ruby’
doc.elements["//language[@lang=’#{the_lang}’]"]
for an xml which would have a language tag inside the programmer one
with lang as attributes.
target = XPath.match(doc, “//programmer[text()=$name]”, {}, “name” =>
input_name)
p target
Since I’m now digging one level deeper in my xml and again trying to
locate a specific element, I thought I’d try XPath, which should be
easier.
But that example you gave is to locate an element knowing the text
value, then showing the attribute.
I’m trying to do the opposite, looking for an element depending on its
attribute’s value.
I looked in XPath and the Functions module it’s using, I can’t find any
method to do that :o