::Xml

Cheri::Xml

To include:
require 'rubygems'
require 'cheri/xml'
 ...
include Cheri::Xml
Note that inclusion at the top level is not recommended.

Options:

xml[:any]           #=> Any tag name inside xml {} will be accepted 
xml[:any=>true]
  
xml[:accept=>[:aaa,:bbb,:nnn]] #=> only specified tag names accepted
(see builder-builder example below for alternative approach)
  
xml[:format]        #=> output formatted with line-feeds only
xml[:format=>true]
  
xml[:indent]        #=> output indented by 2 spaces per level
xml[:indent=>nnn]   #=> output indented by nnn spaces per level
  
xml[:margin=>nnn]   #=> output indented by margin
                    #=> (in addition to :indent)
  
xml[:esc]           #=> output will be escaped
xml[:esc=>true]     #=>(off by default for performance) 
                

# declare xxx as a namespace prefix  
xml[:ns=>:xxx]

# declare xxx,yyy,zzz as namespace prefixes
xml[:ns=>[:xxx,:yyy,:zzz...]]

# declare tag aliases  
xml[:alias=>[:alias1,:name1,:alias2,:name2...]]

# declare attribute aliases  
xml[:attr=>[:alias1,:attr1...]]
Options specified using xml[opts] apply to all threads for an instance.
Options specified using xml(opts) apply only to the current thread/scope:
# example
xml[:any=>true,:indent=>2,:esc=>false]
@out = xml {
  # nothing escaped at this level
  aaa{
    bbb {
      xml(:esc) {
        # text/attributes escaped in this scope
        ddd { ... }
        eee { ... }
}}}}
The result of an xml block will be one of several types of object, depending on the tags used and how they are invoked. The result object can be coerced to a String, directly by calling its to_s method, or indirectly by using << to append it to a String or IO stream. The to_s method also takes an optional String/stream parameter; for streams, this is the most efficient way to render the XML.
# example
xml[:any,:indent]
@result = xml{
  aaa(:an_attr='a value',:another=>'value 2') {
    bbb { ccc }
  }
}

puts @result           #=> XML
@result.to_s           #=> XML
a_string << @result    #=> appends XML
a_stream << @result    #=> appends XML
@result.to_s(a_string) #=> appends XML more efficiently
@result.to_s(a_stream) #=> appends XML more efficiently

# result:
<?xml version="1.0" encoding="UTF-8"?>
<aaa another="value 2" an_attr="a value">
  <bbb>
    <ccc />
  </bbb>
</aaa>
To omit the XML declaration, use xml as the receiver for the initial element:
xml.aaa{bbb}
# result
<aaa>
  <bbb />
</aaa>
Alias element names that are lengthy, or can't be used directly in Ruby:
xml[:alias=>[:cls,:class]]
xml.aaa{cls}
# result
<aaa>
  <class />
</aaa>
Declare namespace prefixes, and apply them directly (using myns.tag or myns::tag), or apply them to all elements in a scope:
xml[:alias=>[:env,:Envelope,:hdr,:Header,:body,:Body]]
xml[:ns=>:soap]
xml { soap {
 env(:xxx=>'yyy') {
   hdr
   body
}}}

# result
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xxx="yyy">
  <soap:Header />
  <soap:Body />
</soap:Envelope>
Use no_ns to turn off a namespace; or specify a different namespace:
xml[:alias=>[:env,:Envelope,:hdr,:Header,:body,:Body]]
xml[:ns=>[:soap,:xx]]
xml {
  aaa {
  soap { env {
  hdr
  body {
    no_ns {
      bbb
      xx::ccc
      ddd
      xx {eee; fff}
}}}}}}

# result
<?xml version="1.0" encoding="UTF-8"?>
<aaa>
  <soap:Envelope>
    <soap:Header />
    <soap:Body>
      <bbb />
      <xx:ccc />
      <ddd />
      <xx:eee />
      <xx:fff />
    </soap:Body>
  </soap:Envelope>
</aaa>
Use the Cheri builder-builder to define more explicit element relationships:
require 'cheri/xml'
  
my_content_elems = [:aaa,:bbb,:ccc]
my_empty_elems = [:xxx,:yyy]
  
MyBuilder = Cheri::Builder.new_builder do
  extend_builder Cheri::Xml
  build Cheri::Xml::Elem, my_content_elems
  build Cheri::Xml::EmptyElem, my_empty_elems
  symbol(:aaa) { connect [:bbb,:ccc] }
  symbol(:bbb) { connect :xxx }
  symbol(:ccc) { connect :yyy }
  # raise error to prevent non-connects from silently failing
  type Cheri::Xml::XmlElement do
    connect Cheri::Xml::XmlElement do |parent,child|
      raise TypeError,"can't add #{child.sym} to #{parent.sym}"
    end
  end
end
include Cheri::Xml
include MyBuilder
Note that an upcoming feature, content models, will provide a more straightforward (and more complete) method of defining elements and attributes for XML and HTML, using a sort of Rubified DTD mechanism. (This was working in an unreleased version of Cheri, but hasn't kept up with recent refactorings. Coming (back) soon!)

More Cheri::Xml documentation and examples coming soon!

Copyright © 2007-2009 Bill Dortch