xml in Ruby

P

paul vudmaska

The biggest problem i have with Ruby is the sleepness
nights.... ;->

Has anyone heard of e4x...emcascript(aka javascript)
for xml?

http://dev2dev.bea.com/products/wlworkshop/articles/JSchneider_XML.jsp

Basically it is an attempt to roll xml as a native
type into ecmascript. I'd suggest Ruby could benefit
and set itself apart by doing so. Following is my own
quick and dirty Ruby'd version of the above.(you might
want to check it out first)

# xml literal...
p = %x{<Peeps><P>paul</P><P>john</P><P/></Peeps>}
or
p <<<XML
<Peeps>
<P>paul</P>
<P>john</P>
<P/>
</Peeps>
XML
#access
mary = p.Peeps.P[3]#xpath starts with 1...

#edit
mary = 'mary'#convenience method appending text to P
element
#add element
p.Peeps << %x{<P>Ringo</P>}

#iter.
p.Peeps.each('P') do |person|

puts person #>paul,john,mary,ringo

end

Instead of the dot notation for swiching context
suggested in the above article, perhaps use xpath
exclusively,imo.

p.each('//P') do ...end

So, basically, rexml rolled into ruby natively.

But what about the much maligned xsl stylesheets? We
need style too - Rubystyle!

# prob a million ways to do this...
style = <<<STYLE
<div>
<h1>#{P}</h1> is a rock star
</div>
STYLE
...here's one
output = p.each('//P').transform(style)


There's plenty of room for rolling more
organic/programic/rubylike approaches to style than
xsl into Ruby(particulary considering Ruby's iters and
blocks). I'm not sure this is the wisest approach, and
think people like Michael Kay(an xsl guru) might point
out the folly of this. And keeping to a standard would
be good for a product such as Ruby but it sure is
intersting...at least to me.

So now we've
1) done what javascript might be doing but totally
trumped them with (ruby)style.
2) added a feature that python and perl can only wish
for
3) created an internal common data structure that is
similar to the array, hash and struct but is sometimes
better and certainly more portable/readable.
4) now a native type, we can import/export data to
whatever speaks xml without worrying about
implementation.
5) have an inherent mechanism for seperating duties
<important>within code</important>- ie data from style
6)a powerful native templating system. Great for web
stuff particularily. Picture putting the power of ruby
in templates that are sandboxed. No need to learn
template language X. Do it in ruby or subset of.
6+) prob much more, xml tends to feed upon itself

Whatcha think? Can i count on this by 1.8.1? ;->

:pv

PS:as for the previous comment at artima about the
limitations of Ruby - stone that guy! :) Not really-
seemed like legit points 2me. I want Ruby to scale to
1 mil hits per sec on my ipaq too - but not at the
expense of creativity, malability, fidelity,
pragmatism or effectiveness.


__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com
 
E

Erik Terpstra

Last year I made a quick hack that could do something like that.
I didn't have much experience with Ruby back then, so it is a quick and
very dirty solution. But the following works:


require 'XML'

y = XML %{
<employees>
<employee>
<name>Joe</name>
<age>28</age>
<department>
<name>Engineering</name>
</department>
</employee>
<employee>
<name>Ken</name>
<age>26</age>
<department>
<name>Engineering</name>
</department>
</employee>
</employees>
}

puts y.employees.employee[0].age
y.employees.employee[0].age = '9'
puts y.employees.employee[0].age

y.employees.employee.each do |employee|
puts "name: #{employee.name}, age: #{employee.age}"
end



doc = XML %{
<order>
<customer>
<name>I. Wannabuy</name>
<address>
<street>53 Party Lane</street>
<city>Anywhere</city>
<state>CA</state>
<zip>12345</zip>
</address>
</customer>
<item>
<description>Large Purple Dinosaur,
Generic</description>
<quantity>35</quantity>
<price>24.99</price>
</item>
<item>
<description>Catapult</description>
<quantity>1</quantity>
<price>149.95</price>
</item>
<item>
<description>300 foot measuring tape</description>
<quantity>1</quantity>
<price>9.95</price>
</item>
</order>
}

def calc_total(order)
total = 0
order.item.each do |item|
total += item.price.to_f * item.quantity.to_i
end
return total
end

puts "total: #{calc_total(doc.order)}"












======================================================

This is the file XML.rb that makes it work:

======================================================


require 'xmltreebuilder'
require 'perlvalue'

ELEMENT_NODE = 1; ATTRIBUTE_NODE = 2; TEXT_NODE = 3

module Kernel
def XML(xml)
RNX.new(xml)
end
end

class RNX
def initialize(xml)
@level = 0; @line = @source = ''; @path = []
builder = XML::DOM::Builder.new
begin
dom = builder.parse xml.gsub(/\s+/, '')
rescue
puts "#{$0}: #{$!} (in line #{builder.line}";
exit 1
end
dom.documentElement.normalize
traverse dom
eval %{
@#{dom.documentElement.nodeName} = PerlValue.new
#{@source}

def self.#{dom.documentElement.nodeName}
return @#{dom.documentElement.nodeName}
end
}
end

def traverse(node)
index = 0
node.childNodes.each do |n|
if n.nodeType == ELEMENT_NODE
@path[@level] = n.nodeName
if (n.nextSibling and
n.nextSibling.nodeName == n.nodeName) or (n.previousSibling and
n.previousSibling.nodeName == n.nodeName)
@path[@level] += "[#{index}]"
index += 1
end
@line = @path.join('.')
@level += 1; traverse n; @level -= 1
@path.delete_at(@level)
elsif n.nodeType == TEXT_NODE
@line += " = '#{n.data}'\n" if n.data
=~ /\S/ #optional!!!
@source += "@#{@line}"
end
end
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top