Construct AoA with REXML XPath?


#1

Hi…

say I have a document

123 ACTIVE RED BAR 456 BOGUS BLUE BAZ

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…


#2

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”]]


#3

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.


#4

Chris McMahon wrote:

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

123
ACTIVE
RED
BAR


456
BOGUS
BLUE
BAZ