Forum: Ruby construct AoA with REXML XPath?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Chris McMahon (Guest)
on 2006-03-15 21:06
(Received via mailing list)
Hi...

say I have a document

<plan xsi:type="ns0:plan">
  <id>123</id>
  <status>ACTIVE</status>
  <jellyBean>RED</jellyBean>
  <foo>BAR</foo>
</plan>
<plan xsi:type="ns0:plan">
  <id>456</id>
  <status>BOGUS</status>
  <jellyBean>BLUE</jellyBean>
  <foo>BAZ</foo>
</plan>

I know I can do
ids = doc.elements.to_a( "//plan/id")
jellybeans = doc.elements.to_a( "//plan/jellyBean")

but is there some way to do something like

idsAndJellyBeans = doc.elements.to_a( "//plan/id" "//plan/jellyBean")

and get

[[123, "RED"],[456,"BLUE"]]?

Thanks...
Gordon T. (Guest)
on 2006-03-15 23:47
(Received via mailing list)
You could use Array#zip

ids = doc.elements.to_a( "//plan/id/").map{|i| i.text}
=> ["123", "456"]

jellybeans = doc.elements.to_a( "//plan/jellyBean").map {|i| i.text}
=> ["RED", "BLUE"]

idsAndJellyBeans = ids.zip(jellybeans)
=> [["123", "RED"], ["456", "BLUE"]]
Chris McMahon (Guest)
on 2006-03-16 00:24
(Received via mailing list)
Yes, but I wonder if there is a rock-solid guarantee that each array
that is an element of idsAndJellyBeans is in fact from the same "plan"
record.

Empirical research suggests that they are, but I'm nervous.  That's why
I wonder if there is some sort of pure-REXML trick that would extract
multiple elements from within a single record, so that I could always
be sure that the id and the jellyBean in each individual array had FER
SHURE come from the same "plan" record.
William J. (Guest)
on 2006-03-16 06:56
(Received via mailing list)
Chris McMahon wrote:
> <plan xsi:type="ns0:plan">
> but is there some way to do something like
>
> idsAndJellyBeans = doc.elements.to_a( "//plan/id" "//plan/jellyBean")
>
> and get
>
> [[123, "RED"],[456,"BLUE"]]?
>
> Thanks...

Using plain Ruby:

class Array; alias atr first; alias txt last  end
class String
  def xtag(str)
    result = []
    re = %r{ < #{str} (?: \s+ ( (?> [^>"/]* (?> "[^"]*" )? )*  ) )? }xi
    scan( %r{   #{re} / >   |   #{re}   >   ( .*? )  </ #{str} >
            }mix )  \
      { |unpaired, attr, data|   h = { }
        ( unpaired || attr || "" ).
        scan( %r{  ( \w+ ) \s* = \s*  (?: " ( [^"]* ) "  |  ( \S+ )  )
                }mx ) { |k,v,v2|
          h[k.downcase] = (v || v2) }
        block_given? ? ( yield [ h, data ] ) : result << [ h, data ]
      }
    result
  end
end

p DATA.read.xtag('plan').map{|attr,text|
  [ text.xtag('id').first.txt,
    text.xtag('jellyBean').first.txt
  ]
}

__END__
<plan xsi:type="ns0:plan">
  <id>123</id>
  <status>ACTIVE</status>
  <jellyBean>RED</jellyBean>
  <foo>BAR</foo>
</plan>
<plan xsi:type="ns0:plan">
  <id>456</id>
  <status>BOGUS</status>
  <jellyBean>BLUE</jellyBean>
  <foo>BAZ</foo>
</plan>
This topic is locked and can not be replied to.