Xpath like syntax

Hi all,

curious if there is a nice ruby way to express an xpath like navigation of an
object graph..

ie:

XPATH way:
Countries/Provinces/Cities[ @name = "London" ]

versus

The only Ruby way I can think of:
countries.collect{ |c| c.provinces.collect {|p| p.cities.select { |c2| c2#name
== 'London' } } }

Thanks in advance

Something like this certainly would be nice. Can you think of a nice
way to represent it in Ruby?

~trans.

"Luke Galea" <lgalea@gmmsolutions.com> wrote in message

curious if there is a nice ruby way to express an xpath like navigation of

an

object graph..

XPATH way:
Countries/Provinces/Cities[ @name = "London" ]

The only Ruby way I can think of:
countries.collect{ |c| c.provinces.collect {|p| p.cities.select { |c2|

c2#name

== 'London' } } }

How about :
x[:countries][:provinces][:cities, {:name=>"London"}]

You could build up a query by composing query objects. To evaluate the query
you would have to treat each sub-query as evaluating to a result-set of
tree-like things, I believe (modulo optimizations). Can probably build up a
filtering proc and use #each to avoid actually constructing the result set.

class Q
attr_accessor :chain
def initialize
  self.chain =
end
def (attr=nil, hash={})
  f = Q.new
  f.chain = self.chain.dup
  if attr
   f.chain << [attr, hash]
  else
   f.chain.last << hash
  end
  f
end
end

require 'pp'
x = Q.new
pp x
y=x[:a]
pp y
z=y[:b][:c][:d, {:foo=>"bar", :baz=>"bratz"}]
pp z

#==>
#<Q:0x28a4668 @chain=>
#<Q:0x28bec90 @chain=[[:a, {}]]>
#<Q:0x28b8c90
@chain=[[:a, {}], [:b, {}], [:c, {}], [:d, {:foo=>"bar", :baz=>"bratz"}]]>

I asked a similar question a couple of weeks ago, and there was
nothing existing in the ruby world from the looks of it.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125206

Some external projects to look at mentioned:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125284

A code idea:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125291

JXpath in the Java world seems like it's for exactly this purpose.
http://jakarta.apache.org/commons/jxpath/

I haven't worked on the query aspect of my project lately, so I
haven't made up my mind how I'm going to approach it yet.

Regards,
Nick

···

On Fri, 21 Jan 2005 15:21:45 +0900, Luke Galea <lgalea@gmmsolutions.com> wrote:

Hi all,

curious if there is a nice ruby way to express an xpath like navigation of an
object graph..

ie:

XPATH way:
Countries/Provinces/Cities[ @name = "London" ]

versus

The only Ruby way I can think of:
countries.collect{ |c| c.provinces.collect {|p| p.cities.select { |c2| c2#name
== 'London' } } }

Thanks in advance

--
Nicholas Van Weerdenburg

I was planning on implementing something like this this week!

Ari

···

On Fri, 2005-01-21 at 15:21 +0900, Luke Galea wrote:

Hi all,

curious if there is a nice ruby way to express an xpath like navigation of an
object graph..

ie:

XPATH way:
Countries/Provinces/Cities[ @name = "London" ]

----
Ruby web hosting? http://theinternetco.net/offers/ruby

x[:countries][:provinces][:cities, {:name=>"London"}]

You should treat [:countries], {:name=>"London"}... as convenient sugar for
a general case of a block at any query stage e.g.
x[:cities]{|c| c.population > c.houses.capacity.sum}[:streets]

And if you prefer "." syntax, you could use Jim Wierich's BlankSlate and
catch method_missing so x.cities does the same as x[:countries].

If you really get into this, you could do not just filtering (select/project
combinations), but create new nodes i.e. full transformations.

itsme213 your Q class is promising.

Sometime ago I put out a small challenge to do R like querying and per
element processing. See ruby-talk:116415

http://groups-beta.google.com/group/comp.lang.ruby/browse_thread/thread/8f36cdeb04738c0e/788e64d6ca0dc746#788e64d6ca0dc746

You'll notice Niklas Frykholm gave a nice solution which reminds me of
this. I haven't looked at the possibility in depth, but I wonder if
these two can be integrated? If you wanted to develop further I would
linke to include in upcoming Ruby Carats release.

I was planning on implementing something like this this week!

Common wavelengths are amazing common around here :slight_smile:
Perhaps then you'd be interested in what I have suggested about buiding
a general purpose class for these use cases?

Actually when I posted the original question I had something like JXPath in
mind.. or OGNL.. (ognl.org)

It's awesome how many alternate implementations have been proposed in answer!
Open source at it's best!!

···

On Friday 21 January 2005 10:19, Nicholas Van Weerdenburg wrote:

On Fri, 21 Jan 2005 15:21:45 +0900, Luke Galea <lgalea@gmmsolutions.com> wrote:
> Hi all,
>
> curious if there is a nice ruby way to express an xpath like navigation
> of an object graph..
>
> ie:
>
> XPATH way:
> Countries/Provinces/Cities[ @name = "London" ]
>
> versus
>
> The only Ruby way I can think of:
> countries.collect{ |c| c.provinces.collect {|p| p.cities.select { |c2|
> c2#name == 'London' } } }
>
> Thanks in advance

I asked a similar question a couple of weeks ago, and there was
nothing existing in the ruby world from the looks of it.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125206

Some external projects to look at mentioned:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125284

A code idea:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125291

JXpath in the Java world seems like it's for exactly this purpose.
Apache Commons JXPath – JXPath Home

I haven't worked on the query aspect of my project lately, so I
haven't made up my mind how I'm going to approach it yet.

Regards,
Nick

"trans." <tsawyer@gmail.com> wrote in message

itsme213 your Q class is promising.

Sometime ago I put out a small challenge to do R like querying and per
element processing. See ruby-talk:116415

http://groups-beta.google.com/group/comp.lang.ruby/browse_thread/thread/8f36cdeb04738c0e/788e64d6ca0dc746#788e64d6ca0dc746

You'll notice Niklas Frykholm gave a nice solution

Yes, I'd do roughly what he did to evaluate the queries.
    SomeObj # evaluate (query)

What I wrote previously was to compose the queries themselves as 1st-class
things.
    Query # compose (queries)

Btw, my symbol and hash examples of queries
    [:cities] {:name=>"London"}
were just sugar for blocks. Explicit blocks should be allowed too.
    [:cities]{|c| c.size > c.population.size_need}
That would give your equivalent of list comprehensions.

Not sure if I can contribute anything complete, tho...

Does Ruby Carats do the same thing as Gabriele's extensions?

I was thinking of doing that as well, so I certainly would. I was
thinking that a traverse_path operation is pretty common, and any set of
objects implementing that protocol could be used .. be they a filesystem
tree, an XML document, or an object graph.

I still haven't figured out what the basic API should look like, but I
can imagine it being similar in complexity to Enumerable -- a sort of
Traversable object.

Ari

···

On Sat, 2005-01-22 at 03:30 +0900, trans. wrote:

> I was planning on implementing something like this this week!

Common wavelengths are amazing common around here :slight_smile:
Perhaps then you'd be interested in what I have suggested about buiding
a general purpose class for these use cases?

----
Ruby web hosting? http://theinternetco.net/offers/ruby

Does Ruby Carats do the same thing as Gabriele's extensions?

Gabriele's? Do you mean Gavins? Or is this another set of extensions I
am not aware?

Ruby Facets is the extensions library, which is unique for its
atomicity.

Ruby Carats OTOH, is an extensive collection of Classes, Modules and
Mixins (but has not yet been released.)
See http://calibre.rubyforge.org/

Traversable mixin! That would be great!

As for API, probably best just would work out what your current needs
are (I assume you have a current need ;-), and implement that first.
Most of the rest wil probbly fall out from there, and then others can
offer additional suggestion for functionaity. That's how I'd probbly go
about it, anyway.

Keep me informed and I'd be glad to help in any way I can.
HTH,
trans.

"trans." <tsawyer@gmail.com> wrote in message

Gabriele's? Do you mean Gavins?

My mistake. Yes, Gavins. Thanks for the clarification.

Traversable mixin! That would be great!

Would a single method, traverse_component be sufficient to build an
implementation on, do you think? Pass it a path component, and have the
object return whatever makes sense? (for a hash or array, map it to ;
for Objects in general, map it to send?)

Perhaps have a second method, traverse_filter, that receives an array of
filters, for XPath-style qualifications like [@attr = 'foo'], or
[/childobject]?

As for API, probably best just would work out what your current needs
are (I assume you have a current need ;-), and implement that first.
Most of the rest wil probbly fall out from there, and then others can
offer additional suggestion for functionaity. That's how I'd probbly

go

about it, anyway.

My uses are, right now, for passing an object graph as model data to an
XTemplate view (something that Amrita does, and XTemplate does not,
yet), and for mapping a rails-style URL to an object graph of handlers
-- so that /foo/bar/baz maps to (roughly) startingpoint.foo.bar.baz

Keep me informed and I'd be glad to help in any way I can.

Alright.

Ari

···

On Sat, 22 Jan 2005 04:25:57 +0900, trans. <tsawyer@gmail.com> wrote:

----
Ruby web hosting? http://theinternetco.net/offers/ruby

"Aredridel" <aredridel@nbtsc.org> wrote in message

Would a single method, traverse_component be sufficient to build an
implementation on, do you think? Pass it a path component, and have the
object return whatever makes sense? (for a hash or array, map it to ;
for Objects in general, map it to send?)

Perhaps have a second method, traverse_filter, that receives an array of
filters, for XPath-style qualifications like [@attr = 'foo'], or
[/childobject]?

My thoughts ... suppose query was based on 2 kinds of procs, traversers and
filters. Simplest traversers would just do x.send :foo (abbreviated
[:foo]?), simplest filters might just check an attribute value (abbreviated
{:foo=>bar}?).

class Q
    attr_accessor :traverser, :filter
    # traverser: obj->obj
    # filter. obj->bool

We can build paths by composing queries.
    def (traverser, filter)
        # shortcuts for symbols, hashes, etc.
        Q.new self, traverser, filter
    end
    def initialize prefix, traverser, filter
    end
end

This will let us navigate from an object, and filter an object in or out.
Then perhaps a query-oriented collection.

class QColl
    def eval (query) #-> QColl
        # transitive traverse, filter
        # return new QColl
    end
    def self.wrap(array)
        # wrap new QColl around array
    end

And if we want sugar: collection.foo{|f| f.bar<10}
instead of arr.collect{|x|x.foo}.select{|f| f.bar < 10}

    def method_missing sym, *args, &filter
        self.eval Q.new nil, proc{|x| x.send sym, *args}, filter
    end
end

Thoughts?

I'd like a simple addition to Enumerable. Also, maybe combine the
concepts of XPath and XQuery.

nodes= aobjectgraph.traverse("graph path here")
# or
nodes= aobjectgraph.query( "query spec here")

As well as the block result processing versions.

I think following the semantics of xpath and xquery, while maintaining
the semantics of Enumerable, would be ideal. In that light, filters
and such would ideally be done via normal Enumerable primitives.

To follow Ruby conventions, it may make more sense to extend
find/select or add a graph_select/graph_find method (maintaining
similarity to select/find naming).

Regards,
Nick

···

On Sat, 22 Jan 2005 04:50:05 +0900, Aredridel <aredridel@nbtsc.org> wrote:

On Sat, 22 Jan 2005 04:25:57 +0900, trans. <tsawyer@gmail.com> wrote:
> Traversable mixin! That would be great!

Would a single method, traverse_component be sufficient to build an
implementation on, do you think? Pass it a path component, and have the
object return whatever makes sense? (for a hash or array, map it to ;
for Objects in general, map it to send?)

Perhaps have a second method, traverse_filter, that receives an array of
filters, for XPath-style qualifications like [@attr = 'foo'], or
[/childobject]?

> As for API, probably best just would work out what your current needs
> are (I assume you have a current need ;-), and implement that first.
> Most of the rest wil probbly fall out from there, and then others can
> offer additional suggestion for functionaity. That's how I'd probbly
go
> about it, anyway.

My uses are, right now, for passing an object graph as model data to an
XTemplate view (something that Amrita does, and XTemplate does not,
yet), and for mapping a rails-style URL to an object graph of handlers
-- so that /foo/bar/baz maps to (roughly) startingpoint.foo.bar.baz

> Keep me informed and I'd be glad to help in any way I can.

Alright.

Ari

----
Ruby web hosting? http://theinternetco.net/offers/ruby

``>

--
Nicholas Van Weerdenburg

Aredridel wrote:

> Traversable mixin! That would be great!

Would a single method, traverse_component be sufficient to build an
implementation on, do you think? Pass it a path component, and have

the

object return whatever makes sense? (for a hash or array, map it to

;

for Objects in general, map it to send?)

I'd think so. And I think it can be kept reasonably simple -- just
#traverse or #travel or something like that should suffice.

The return value may be better as the special object (what itisme213 is
calling Q) so that it could be further queried/filtered, and also
operated on "element-wise" (i.e. all the elements could be modified in
parallel). Or maybe have two methods, one returns another "Q" and the
other "whatever makes sense" (with the Q object another method, say
#value, could return "wahtever made sence). Basically thinking out loud
here. Playing with some code will probably reveal much more.

Perhaps have a second method, traverse_filter, that receives an array

of

filters, for XPath-style qualifications like [@attr = 'foo'], or
[/childobject]?

If a path is a string (?) and filters are always in an array, the
differnce in class may allow for use of the same method, instead have
having two separate methods. But having two merthods is okay if need be
too.

My uses are, right now, for passing an object graph as model data to

an

XTemplate view (something that Amrita does, and XTemplate does not,
yet), and for mapping a rails-style URL to an object graph of

handlers

-- so that /foo/bar/baz maps to (roughly) startingpoint.foo.bar.baz

I see. Looks like some very good use cases.

···

On Sat, 22 Jan 2005 04:25:57 +0900, trans. <tsawyer@gmail.com> wrote: