Forum: Ruby Wrapping XML document in Class

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.
Miles Monroe (Guest)
on 2006-03-13 21:21
I would like to use Ruby and REXML to wrap an XML document and allow
access to the element nodes, attributes, and text.  Essentially I need
an XML document builder loosely coupled from the document.

It seems like Ruby is powerful enough to code generate a class given an
XML document or build an object at run-time with the appropriate
accessors.

For instance:

order = XmlBuilder.new

order.add("root").add("header")
order.root.add("body")

order.body.add("component").attributes["type"] = "metric"

order.write($stdout)

I'd also like to be able to plug-in input validation when assigning
values to elements and attributes.

Has anyone done this before?

Thanks.
Miles Monroe (Guest)
on 2006-03-13 22:35
Miles Monroe wrote:
> I would like to use Ruby and REXML to wrap an XML document and allow
> access to the element nodes, attributes, and text.  Essentially I need
> an XML document builder loosely coupled from the document.
>
> It seems like Ruby is powerful enough to code generate a class given an
> XML document or build an object at run-time with the appropriate
> accessors.
>
> For instance:
>
> order = XmlBuilder.new
>
> order.add("root").add("header")
> order.root.add("body")
>
> order.body.add("component").attributes["type"] = "metric"
>
> order.write($stdout)
>
> I'd also like to be able to plug-in input validation when assigning
> values to elements and attributes.
>
> Has anyone done this before?
>
> Thanks.

I found this blog entry on a XmlStringBuffer class in Ruby.  I
understand using  method_missing to create the element, but I'm not sure
how to closures would be implemented.  Thanks.

http://www.beust.com/weblog/archives/000025.html

xml = XML.new

xml.html {
  xml.head {
  }
  xml.body {
    xml.table {
      xml.tr {
        xml.td({ "valign" => "top"}, "Content1"){
        }
        xml.td {
          xml.append("Content2")
        }
      }
    }
  }
}
Jim W. (Guest)
on 2006-03-13 22:52
Miles Monroe wrote:
> I would like to use Ruby and REXML to wrap an XML document and allow
> access to the element nodes, attributes, and text.  Essentially I need
> an XML document builder loosely coupled from the document.
>
> It seems like Ruby is powerful enough to code generate a class given an
> XML document or build an object at run-time with the appropriate
> accessors.
>
> For instance:
>
> order = XmlBuilder.new
[... example elided ...]

Are you wanting to build a DOM object, or build a string containing XML
markup?  If the later, Builder::XmlMarkup will do this.  If the former,
it would be interesting to create a Builder with a similar API to
Buidler::XmlMarkup, but generated DOM trees instead of strings.

Or perhaps you are looking for something completely different.

XML Builder Link:  http://builder.rubyforge.org/

--
-- Jim W.
Simon Kröger (Guest)
on 2006-03-13 23:16
(Received via mailing list)
Hi Miles,

interesting idea, i did a quick (proof of concept) hack:
-------------------------------------------------------------
class Xmltree
  attr_accessor :childs
  attr_accessor :content
  attr_accessor :attributes

  def initialize
    self.childs = []
    self.attributes = {};
  end

  def method_missing meth, *args, &block
    return attributes[args[0]] = args[1] if meth == :[]=
    return attributes[args[0]] if meth == :[]
    return self.content = args if meth == '='.intern

    unless child = childs.assoc(meth.to_s.chomp('='))
      childs << child = [meth.to_s.chomp('='), Xmltree.new]
    end

    return child[1] if meth.to_s[-1] != ?=
    child[1].content = args
  end

  def to_s
    childs.map do |t, c|
      """<#{t} #{c.attributes.map do |a, v|
      "#{a}=\"#{v}\""
      end.join(' ')}>\n#{c}</#{t}>\n"""
    end.join + content.to_s + (content ? "\n" : '')
  end
end
-------------------------------------------------------------

usage:
-------------------------------------------------------------
xml = Xmltree.new

xml.header.title = 'this is a demo'
xml.body.component['type'] = 'the answer'
xml.body.component = 42

puts xml
-------------------------------------------------------------

output:
-------------------------------------------------------------
<header >
<title >
this is a demo
</title>
</header>
<body >
<component type="the answer">
42
</component>
</body>
-------------------------------------------------------------

cheers

Simon

Miles Monroe:
Miles M. (Guest)
on 2006-03-13 23:44
Simon Kröger wrote:
> Hi Miles,
>
> interesting idea, i did a quick (proof of concept) hack:
> -------------------------------------------------------------
> class Xmltree
>   attr_accessor :childs
>   attr_accessor :content
>   attr_accessor :attributes
>
>   def initialize
>     self.childs = []
>     self.attributes = {};
>   end
>
>   def method_missing meth, *args, &block
>     return attributes[args[0]] = args[1] if meth == :[]=
>     return attributes[args[0]] if meth == :[]
>     return self.content = args if meth == '='.intern
>
>     unless child = childs.assoc(meth.to_s.chomp('='))
>       childs << child = [meth.to_s.chomp('='), Xmltree.new]
>     end
>
>     return child[1] if meth.to_s[-1] != ?=
>     child[1].content = args
>   end
>
>   def to_s
>     childs.map do |t, c|
>       """<#{t} #{c.attributes.map do |a, v|
>       "#{a}=\"#{v}\""
>       end.join(' ')}>\n#{c}</#{t}>\n"""
>     end.join + content.to_s + (content ? "\n" : '')
>   end
> end
> -------------------------------------------------------------
>
> usage:
> -------------------------------------------------------------
> xml = Xmltree.new
>
> xml.header.title = 'this is a demo'
> xml.body.component['type'] = 'the answer'
> xml.body.component = 42
>
> puts xml
> -------------------------------------------------------------
>
> output:
> -------------------------------------------------------------
> <header >
> <title >
> this is a demo
> </title>
> </header>
> <body >
> <component type="the answer">
> 42
> </component>
> </body>
> -------------------------------------------------------------
>
> cheers
>
> Simon
>
> Miles Monroe:


Awesome!  That is better than I ever imagined.

Back in my Perl days, I started creating a source filter to allow the
insertion of non-Perl XPath statements that worked on an implicit XML
document.

I used the source filter to first scan the code for naked XPath
statements and then built the XML document with the slightly-modified
XPath syntax.  I converted the invalid non-Perl strings into valid Perl
in the source filter.

Likewise, is it possible to insert non-Ruby text in the main namespace
and then turn it into Ruby code before the rest of the script is parsed?
I guess I'm asking if it's possible to implement a source filter in
Ruby.

Thanks.
Miles M. (Guest)
on 2006-03-14 00:03
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/...

http://www.rubyquiz.com/quiz34.html

I found a couple links on source filters for Ruby.

I guess what I was proposing was just something like this:


/html/head/title << "Implicit XML Document"

/html/body/h1 << "Ruby source filters"

/html/body/h1["class"] = "golden"

/html/body/table["id"] = "QueryResults"

puts $_implicit_XML
Benjohn B. (Guest)
on 2006-03-14 01:12
(Received via mailing list)
Last time I was doing playing with XML, I wanted to be able to,
basically, add methods on to the nodes matching xpaths. It didn't
seem to be very easy. I wondered at the time if some kind of
transform idea would work better.
This topic is locked and can not be replied to.