Humanized Xml tree navigation

Does anybody know of a library that allows to go through an xml tree as
if
it were made of normal objects?

I have seen e4x on rubyforge, but it doesn’t seem to work. simplexml
returns
hashes rather than employing dynamic method calls

What I need to do is to be able to traverse an xml document as in:

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

etc…

Any suggestion?

–kia

On Jul 31, 2006, at 6:16 AM, chiaro scuro wrote:

What I need to do is to be able to traverse an xml document as in:

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

Consider

foo föö

That’s legal XML. Ruby n00b question: can you work around problems
like “vocab-item” and “first.form” in Ruby? -Tim

uhm… I admit I didn’t think of that. I guess I will have to write some
kind of name normalized/denormalizer taking care of dots and hyphens.

all hyphens and dots will become underscores, I guess, and I’ll just
assume
nobody will try to get the code to fail using both at the same time :slight_smile:
nobody will, right?

On Jul 31, 2006, at 11:16 AM, Tim B. wrote:

foo föö

That’s legal XML. Ruby n00b question: can you work around problems
like “vocab-item” and “first.form” in Ruby? -Tim

Workaround is the word

class A
define_method("@+$%!") { puts “Snoopy talk!” }
end

a = A.new
a.send("@+$%!")

On Jul 31, 2006, at 11:16 AM, Tim B. wrote:

Consider

foo föö

That’s legal XML. Ruby n00b question: can you work around problems
like “vocab-item” and “first.form” in Ruby?

class Foo
define_method(“first.form”) do
“hi from first.form”
end
end
Foo.new.send(“first.form”) # => “hi from first.form”

– Daniel

On Jul 31, 2006, at 6:16, chiaro scuro wrote:

Does anybody know of a library that allows to go through an xml tree
as if
it were made of normal objects?

Your sample code looks a lot like RubyfulSoup. Although originally
intended for traversing HTML documents, it has an option for
non-specific XML as well.

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

RubyfulSoup would (I believe) look something like:

people.find_all['person'].each
people.person.name
people.person.size

if the XML were like

<people>
	<person>
		<name>Fred</name>
		<size>150 kg</size>
	</person>
	<person>
		<name>Sally</name>
	.
	.
	.
	</person>
</people>

If instead your XML is like

<people>
	<person name="Fred" size="150 kg"/>
	<person name="Sally" size="88 kg"/>
	.
	.
	.
</people>

Then you’d be looking at

people.find_all['person'].each
people.person['name']
people.person['size']

I don’t remember what it does with XML tags with squiggles and dots.

I’m experimenting with this XML2RB [1]. The idea is to generate
a DSL for a class of XML files (from a bunch of XML files).
Each XML file in this class can be translated to a Ruby script,
which can be executed with the DSL. Running a script actually
builds the tree by default, including the classes and methods
as you mentioned. Each class can optionally be enriched with
new functionality.

All examples are real, but I’ve not yet released any code.
Untill now, it’s just an experiment.

The document will grow every now and then. It’s not static.

gegroet,
Erik V. - http://www.erikveen.dds.nl/

[1] http://www.erikveen.dds.nl/xml2rb/index.html

Tim B. [email protected] writes:

foo föö

That’s legal XML. Ruby n00b question: can you work around problems
like “vocab-item” and “first.form” in Ruby? -Tim

Just make the API more flexible:

document[“vocab-item”].bla[“second.form”]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

Tim B. wrote:

Consider

foo föö

That’s legal XML. Ruby n00b question: can you work around problems like
“vocab-item” and “first.form” in Ruby? -Tim

With xsd/mapping;

0% irb
irb(main):001:0> require ‘xsd/mapping’
=> true
irb(main):002:0> obj = XSD::Mapping.xml2obj(<<XML)
irb(main):003:1"
irb(main):004:1"
irb(main):005:1" <first.form>foo</first.form>
irb(main):006:1" <second.form>foo</second.form>
irb(main):007:1"
irb(main):008:1"
irb(main):009:1" XML
=> #<SOAP::Mapping::Object:0x3591144
{}vocab-item=#<SOAP::Mapping::Object:0x3590f64 {}first.form=“foo”
{}second.form=“foo”>>

irb(main):010:0> obj.methods - Kernel.methods
=> ["[]", “vocab_item=”, “[]=”, “__xmlattr”, “__xmlele”,
“__add_xmlele_value”, “vocab_item”]

irb(main):011:0> obj[“vocab-item”]
=> #<SOAP::Mapping::Object:0x3590f64 {}first.form=“foo”
{}second.form=“foo”>

irb(main):012:0> obj[XSD::QName.new(nil, “vocab-item”)]
=> #<SOAP::Mapping::Object:0x3590f64 {}first.form=“foo”
{}second.form=“foo”>

Last line is for your next question, XML Namespace. And see “__xmlattr”
method listed for the next.

Regards,
// NaHi
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)

iQEVAwUBRM6AWh9L2jg5EEGlAQIySQf/c201FQV5j6ySxEOQpMJhzVp0r9JZiB+T
fTlMD5UyfCrv7wXFc8cRxn0Av9mx6ryuy0e24Yj2iM4JZYwmKYI8HinElWaSPqTU
MhwZLWhvHEDEUbaTr1xjdNabHsmO6HhfAdGm8PjAMB5XeaJw3x4nm+LOVUrm3+lH
k/rZ6+yQN9Q9nHkyQPWOC6+zkdgIVVNEb/a8meqQ8vXpTMUSkkBbnf+HSbaN1gku
wp7SrXdk3oFBEhreE4LkW4nCo07ToDZm5rvj4qmCgY8hv98zLul8w9cexPxqREFe
WBWvhz8NuhYua9lac1TSDLE0DMlzOzLzdFDlpEOTCLwrgZ2ykSLIxw==
=BjvB
-----END PGP SIGNATURE-----

Hi,

On Jul 31, 2006, at 11:16 AM, Tim B. wrote:

foo föö

That’s legal XML. Ruby n00b question: can you work around problems
like “vocab-item” and “first.form” in Ruby? -Tim

I feel compelled to mention xampl (<http://rubyforge.org/projects/
xampl/>). Using the current version for ruby, the program looks like
this:

thing = open(“xml/funnystuff.xml”){ | f | XamplObject.from_xml_string
f.read }
puts thing.pp_xml
puts thing.class.name
thing.first_form.first.content = ‘hello there’
puts thing.pp_xml

The output like this:

foo föö XamplAdHoc::VocabItem hello there föö

The file xml/funnystuff.xml has Tim’s example xml in it.

The XamplAdHoc stuff is there because there is no namespace
declarations in the xml and I didn’t supply a default mapping to a
Ruby Module.

Xampl does a lot more than this (in particular it does a weak-
transactional ‘transparent’ persistence kind of thing). It has been
around in Java since the late 1990s (where it does ‘real’
transactions’, CommonLisp for a couple of years, and Ruby for 18
months. I’ve written several programs well over 500 kloc using the
Java version. Currently using xampl in place of ActiveRecord in a
Rails project I’m working on (but you need the version I’m preparing
to release for use with Rails, so please be patient).

Cheers,
Bob


Bob H. – blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc. – http://www.recursive.ca/
Raconteur – http://www.raconteur.info/
xampl for Ruby – http://rubyforge.org/projects/xampl/

On 7/31/06, chiaro scuro [email protected] wrote:

  • people.person.name #takes the first person
  • people.person.size

My xmlcodec project will do this but you’ll need to write some simple
classes to do it. For this case, something like:

class PeopleFormat < XMLElement
xmlformat ‘People Format’
end

class People < PeopleFormat
elname :people
xmlsubel_mult :person
end

class Person < PeopleFormat
elname :person
xmlattr :name
xmlattr :size
end

With this you can do:

people = PeopleFormat.import_xml_text(myXMLTextOrFile)
people.person.each {|p| …}
people.person.first.name
people.person[2].type

You can find it at http://xmlcodec.rubyforge.org

Cheers,

Pedro.

chiaro scuro wrote:

  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

etc…

Any suggestion?

I like the idea, but I’m unaware that it’s been done
to that level.

Why don’t you start with REXML and put a wrapper on it?
Then publish it for everyone to enjoy.

Or do you find REXML too slow for your use?

Hal

On Jul 31, 2006, at 6:16 AM, chiaro scuro wrote:

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

etc…

Any suggestion?

Look here:
http://code.whytheluckystiff.net/hpricot/

or here:
http://cvs.m17n.org/~akr/htree/

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

chiaro scuro wrote:

Does anybody know of a library that allows to go through an xml tree as if
it were made of normal objects?

What I need to do is to be able to traverse an xml document as in:

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

0% cat people.xml


name1
1


name2
2


name3
3


0% irb
irb(main):001:0> require ‘xsd/mapping’
=> true
irb(main):002:0> people = XSD::Mapping.xml2obj(File.read(“people.xml”))
=> #<SOAP::Mapping::Object:0x3592020
{}person=[#<SOAP::Mapping::Object:0x3591ea0 {}name=“name1” {}size=“1”>,
#<SOAP::Mapping::Object:0x3591684 {}name=“name2” {}size=“2”>,
#<SOAP::Mapping::Object:0x3590f7c {}name=“name3” {}size=“3”>]>
irb(main):003:0> people.person.each { |person| p person }
#<SOAP::Mapping::Object:0x3591ea0 {}name=“name1” {}size=“1”>
#<SOAP::Mapping::Object:0x3591684 {}name=“name2” {}size=“2”>
#<SOAP::Mapping::Object:0x3590f7c {}name=“name3” {}size=“3”>
=> [#<SOAP::Mapping::Object:0x3591ea0 {}name=“name1” {}size=“1”>,
#<SOAP::Mapping::Object:0x3591684 {}name=“name2” {}size=“2”>,
#<SOAP::Mapping::Object:0x3590f7c {}name=“name3” {}size=“3”>]
irb(main):004:0> people.person[2].name
=> “name3”
irb(main):005:0> people.person.name
NoMethodError: undefined method `name’ for #Array:0x6b22108
from (irb):5
irb(main):006:0>

Almost.

Regards,
// NaHi

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)

iQEVAwUBRM4IxB9L2jg5EEGlAQLiHAf8DvhvC/LwgsAZNOZYDUhJQ9SdCMrhHWq2
WlAW/SyIJXhEvXWv+Rl/Z148xTWutghiu/GzYw6yZ/hUiEaGtXNA5DJkdcAYvmz+
g+FDDjtuCWJ07NEk+l3cQE4bztEq0q+6uHUQApl98EJhbpWXe35ZvOOjnrUwo0uF
0xHs9btBtqix9j0I6iJeqB4uXtLUSs2fc+H5uzUBGAEF0gQ7T1jR3ewQ7HsdBtWw
4eoHgyQ3WcC4qmJir0t8VHlRSox91LzX+C/cWBLAZHfYX00wKl7U9XtmUanMl2tX
IU15m74iiSLASwNdBUY575Tv4vbLykXvgEqReXXDQPGgqhnLgVd1RQ==
=SYJM
-----END PGP SIGNATURE-----

in the meantime I wrote a little REXML wrapper, but I’ll check the
solutions
you guys sent me and see if I can throw away some code :slight_smile:

cheers,
Kia

In article [email protected],
Pedro Côrte-Real [email protected] wrote:

  • people.person[2].name
    class People < PeopleFormat
    With this you can do:

people = PeopleFormat.import_xml_text(myXMLTextOrFile)
people.person.each {|p| …}
people.person.first.name
people.person[2].type

You can find it at http://xmlcodec.rubyforge.org

Nice. I’ve done this sort of thing, but much more ‘manually’ than you
show here.

Phil

Hi,

On Jul 31, 2006, at 9:43 AM, NAKAMURA, Hiroshi wrote:

{}person=[# people.person[2].name => "name3" irb(main):005:0> people.person.name NoMethodError: undefined method `name' for # from (irb):5 irb(main):006:0>

Almost.

Nice! I didn’t know about this.

Loses child ordering though, mixed content, and the root element?

Both of the following lines:

puts XSD::Mapping.obj2xml(XSD::Mapping.xml2obj("

</
p>"))
puts XSD::Mapping.obj2xml(XSD::Mapping.xml2obj("

1234<b/

5

"))

give the same output:

<?xml version="1.0" encoding="utf-8" ?>

<SOAP…Mapping…Object>








</SOAP…Mapping…Object>

Cheers,
Bob


Bob H. – blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc. – http://www.recursive.ca/
Raconteur – http://www.raconteur.info/
xampl for Ruby – http://rubyforge.org/projects/xampl/

On Monday 31 July 2006 14:43, NAKAMURA, Hiroshi wrote:

#<SOAP::Mapping::Object:0x3591684 {}name=“name2” {}size=“2”>

Almost.

Regards,
// NaHi
That’s really nice, I’d looked over that in the standard library. I’ve
used
Roxml with success to achieve the same effect, but it requires more
work.

Alex

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

Bob H. wrote:

Loses child ordering though, mixed content, and the root element?

Yes, Yes and Yes. obj2xml and xml2obj is not for round-trip conversion
although its name indicates it.

I introduced this XML <-> Ruby mapping to avoid bothersome XML DOM
programming in Web Services (soap4r). Do you think xampl can help us
instead of XSD::Mapping?

For example, flickr client is as follows;
(cf. http://dev.ctor.org/soap4r/browser/trunk/sample/soap/flickr.rb)

flickr = SOAP::RPC::Driver.new(‘http://www.flickr.com/services/soap/’)

response = flickr.request(
:api_key => api_key,
:method => ‘flickr.test.echo’,
:name => ‘hello world’)

responsexml = “#{response}” # svr returns partial XML!
require ‘xsd/mapping’
obj = XSD::Mapping.xml2obj(responsexml)
p obj.method
p obj.name

Creating XML request with a Hash and creating Ruby object with
XSD::Mapping. Both are for XML <-> Ruby mapping. It’s enough small but
when I come to create more complexed XML instance… How I can write
this with xampl?

Regards,
// NaHi
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (Cygwin)

iQEVAwUBRNbnLR9L2jg5EEGlAQJuNwf/R/Fjt2gFvI01FiAgbvHUCRQX71O710lE
hLJ5FpzC7X4gCxrQieUocAfKFpCVSh5kLx5CUUF9tR+9F3TRv+L9C6h+7D4mL/GX
zhPVLDBic9CvfhVj7loqkWZKlA5DH/B87DZcfN+dG3PtV+xvMcxVi3Qji/ttFQ5Y
kEhBrC3kGHthkDTrT97+mzpwBkbYiuITBQLrYdxNpXvV3PiX3J81e2KmdSvS6ofK
Aqq/K9OCC4Wgpcl9QTlF156fPHA6tG3LuX7zLeaOTonM8ANVvAV10eJjQ4Wwh1Pl
l0ZbUukPb18uldSzZ7IayxfoYey7kWexoCEyVxzBgzGNMCezsbD7mQ==
=BWic
-----END PGP SIGNATURE-----

  • people.each_person {…}
  • people.person[2].name
  • people.person.name #takes the first person
  • people.person.size

etc…

Any suggestion?

It’s not really the best way to traverse XML becuase there’s some
exceptions --keywords that ruby uses that wouldn’t be traverable as
tags, and legal XML tags that you would not be able to use as method
calls.

I’m suprised the the e4x implemention on Rubyforge didn’t work at all
–I’ll have to look at it, but in any case it is completely
expiremental, and incomplete. For my needs I have moved on to a
Ruby-esque interface instead (http://cherry.rubyforge.org).

T.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs