[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

REXML get specific element

Pierre Pat

3/18/2009 5:16:00 AM

All,

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!

Thanks.
--
Posted via http://www.ruby-....

14 Answers

Pierre Pat

3/18/2009 5:17:00 AM

0

Obviously, in the second example, it's 'programmer' instead of
'magician' ;-)
(Copy paste failure in order to leave some magician's privacy :p)
--
Posted via http://www.ruby-....

Robert Klemme

3/18/2009 12:10:00 PM

0

2009/3/18 Pierre Pat <theyojimbo@gmail.com>:
> All,
>
> 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}]"]

You forgot the single quotes around #{}, i.e. you must only replace
"Matz" with "#{entered_name}":

doc.root.elements["programmer[@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!

Cheers

robert

--
remember.guy do |as, often| as.you_can - without end

Henrik Hodne

3/18/2009 1:45:00 PM

0

Hello,


On 18 Mar 2009, at 06:15, Pierre Pat <theyojimbo@gmail.com> wrote:

> All,
>
> 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...

You are missing the '-s.
Try
doc.root.elements["programmer[@name='#{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!
>
> Thanks.
> --
> Posted via http://www.ruby-....
>

Regards,
Henrik Hodne

Phlip

3/18/2009 1:54:00 PM

0

> You are missing the '-s.
> Try
> doc.root.elements["programmer[@name='#{entered_name}']"]

Then that croaks if the name contains an apostrophe.

Try (IIRC)...

XPath.first(doc, '//programmer[ @name = $name ]', :name => entered_name)

7stud --

3/18/2009 7:24:00 PM

0

Phlip wrote:
>> You are missing the '-s.
>> Try
>> doc.root.elements["programmer[@name='#{entered_name}']"]
>
> Then that croaks if the name contains an apostrophe.
>
> Try (IIRC)...
>
> XPath.first(doc, '//programmer[ @name = $name ]', :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.

Here is the easy case:

1)
<xml version="1.0" encoding="ISO-8859-1"?>
<programmers>
<programmer age="50">John</programmer>
<programmer age="30">Sally</programmer>
</programmers>


require 'rexml/document'
include REXML

f = File.new('xml4.xml')
doc = Document.new(f)

input_name = gets
input_name = input_name.chomp

target = XPath.match(doc, "//programmer[text() = 'John']")
puts target[0].attributes["age"]

-------

$ ruby r1test.rb
John
50


Now suppose the programmer's name is Joh'n

<xml version="1.0" encoding="ISO-8859-1"?>
<programmers>
<programmer age="50">Joh'n</programmer>
<programmer age="30">Sally</programmer>
</programmers>


This is one of my favorite attempts to escape a single quote in the
input name:

input_name = "Joh'n"
p input_name
input_name = input_name.gsub("'", "\\'")
p input_name

--output:--
"Joh'n"
"Johnn"

Can anyone explain what's going on there?
--
Posted via http://www.ruby-....

Phlip

3/18/2009 7:35:00 PM

0

7stud -- wrote:

> 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...

> f = File.new('xml4.xml')
> doc = Document.new(f)
>
> input_name = gets
> input_name = input_name.chomp
>
> target = XPath.match(doc, "//programmer[text() = 'John']")
> puts target[0].attributes["age"]

Wouldn't this work?

target = XPath.match(doc, "//programmer[text() = $name]", :name => $john)

> input_name = input_name.gsub("'", "\\'")
> p input_name
>
> --output:--
> "Joh'n"
> "Johnn"
>
> Can anyone explain what's going on there?

XPath does not escape ticks with \.

7stud --

3/18/2009 8:09:00 PM

0

Phlip wrote:
> 7stud -- wrote:
>
>> 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...
>
>> f = File.new('xml4.xml')
>> doc = Document.new(f)
>>
>> input_name = gets
>> input_name = input_name.chomp
>>
>> target = XPath.match(doc, "//programmer[text() = 'John']")
>> puts target[0].attributes["age"]
>
> Wouldn't this work?
>
> target = XPath.match(doc, "//programmer[text() = $name]", :name =>
> $john)
>

I don't know what you are trying to do there. What is $john? This
doesn't work for me:

<xml version="1.0" encoding="ISO-8859-1"?>
<programmers>
<programmer age="50">Joh'n</programmer>
<programmer age="30">Sally</programmer>
</programmers>


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() = $name]", :name =>
$input_name)
p target

puts target[0].attributes["age"]


--output:--
$ ruby r1test.rb
Joh'n
"Joh'n"
[]
r1test.rb:14: undefined method `attributes' for nil:NilClass
(NoMethodError)


I thought the question you presented was how are you going to be able to
handle all these cases in the xml:

<programmer age="50">John</programmer>
<programmer age="50">Joh'n</programmer>
<programmer age="50">Joh"n</programmer>

The user may type in: John, or Joh'n, or Joh"n.
--
Posted via http://www.ruby-....

7stud --

3/18/2009 8:17:00 PM

0

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"?>
<programmers>
<programmer age="50">Joh'n</programmer>
<programmer age="30">John</programmer>
<programmer age="20">Joh"n</programmer>
</programmers>


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 method `node_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:in
`internal_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:in `Predicate'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:346:in `Predicate'
from /usr/lib/ruby/1.8/rexml/xpath_parser.rb:204:in
`internal_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:in
`internal_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:in `parse'
from /usr/lib/ruby/1.8/rexml/xpath.rb:59:in `match'
from r1test.rb:11

--
Posted via http://www.ruby-....

Matthias Reitinger

3/18/2009 9:56:00 PM

0

7stud -- wrote:
> This doesn't work for me:
>
> <xml version="1.0" encoding="ISO-8859-1"?>
> <programmers>
> <programmer age="50">Joh'n</programmer>
> <programmer age="30">Sally</programmer>
> </programmers>
>
>
> 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() = $name]", :name =>
> $input_name)
> p target
>
> puts target[0].attributes["age"]

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

puts target[0].attributes["age"]

__END__
<xml version="1.0" encoding="ISO-8859-1"?>
<programmers>
<programmer age="50">John</programmer>
<programmer age="50">Joh'n</programmer>
<programmer age="50">Joh"n</programmer>
</programmers>


-Matthias
--
Posted via http://www.ruby-....

Pierre Pat

3/19/2009 12:28:00 AM

0

Thanks guys!
I knew it had to be something small, just couldn't figure it out.

It really helped!
Thanks again
--
Posted via http://www.ruby-....