WAX for Ruby

Links

RDoc documentation RubyForge project

Installing

Simply run "gem install wax". You may need to precede this with "sudo " on non-Windows systems in order to obtain the privilege necessary to do this.

Tutorial

This page provides many examples of using WAX for Ruby. Each code snippet is followed by the output it produces.

When nothing is passed to the WAX.write method, XML is written to $stdout. There is also a WAX.write method that takes an IO object.

Here's a simple example where only a root element is written:

WAX.write { start 'car' }
<car/>

Let's write a root element with some text inside:

WAX.write do
  start 'car'
  text 'Prius'
end
<car>Prius</car>

The end! method terminates the element that is started by the start method. In this case it's not necessary to call end! because the close method terminates all unterminated elements.

Let's put the text inside a child element:

WAX.write do
  start 'car'
  start 'model'
  text 'Prius'
end
<car>
  <model>Prius</model>
</car>

Let's do the same with the child convenience method: which is equivalent to calling start, text and end.

WAX.write do
  start 'car'
  child 'model', 'Prius'
end
<car>
  <model>Prius</model>
</car>

Let's put text containing all the special XML characters in a CDATA section:

WAX.write do
  start 'car'
  start 'model'
  cdata "1<2>3&4'5\"6"
end
<car>
  <model>
    <![CDATA[1<2>3&4'5"6]]>
  </model>
</car>

Let's output the XML without indentation, on a single line:

WAX.write do
  no_indents_or_line_separators
  start 'car'
  child 'model', 'Prius'
end
<car><model>Prius</model></car>

Let's indent the XML with four spaces instead of the default of two:

WAX.write do
  set_indent '    ' # could also pass 4
  start 'car'
  child 'model', 'Prius'
end
<car>
    <model>Prius</model>
</car>

Let's add an attribute:

WAX.write do
  start 'car'
  attr 'year', 2008
  child 'model', 'Prius'
end
<car year="2008">
  <model>Prius</model>
</car>

Attributes must be specified before any content for their element is specified. For example, calling start, attr and text is valid, but calling start, text and attr is not. If this rule is violated then a RuntimeError is raised.

Let's add an XML declaration:

WAX.write($stdout, '1.0') do
  start 'car'
  attr 'year', 2008
  child 'model', 'Prius'
end
<?xml version="1.0" encoding="UTF-8"?>
<car year="2008">
  <model>Prius</model>
</car>

Let's add a comment:

WAX.write do
  comment 'This is a hybrid car.'
  start 'car'
  child 'model', 'Prius'
end
<!-- This is a hybrid car. -->
<car>
  <model>Prius</model>
</car>

Let's add a processing instruction:

WAX.write do
  processing_instruction 'target', 'data'
  start 'car'
  attr 'year', 2008
  child 'model', 'Prius'
end
<?target data?>
<car year="2008">
  <model>Prius</model>
</car>

Let's associate an XSLT stylesheet with the XML: The xslt method is a convenience method for adding this commonly used processing instruction.

WAX.write do
  xslt 'car.xslt'
  start 'car'
  attr 'year', 2008
  child 'model', 'Prius'
end
<?xml-stylesheet type="text/xsl" href="car.xslt"?>
<car year="2008">
  <model>Prius</model>
</car>

Let's associate a default namespace with the XML:

WAX.write do
  xslt 'car.xslt'
  start 'car'
  attr 'year', 2008
  namespace 'http://www.ociweb.com/cars'
  child 'model', 'Prius'
end
<car year="2008"
  xmlns="http://www.ociweb.com/cars">
  <model>Prius</model>
</car>

Let's associate a non-default namespace with the XML:

prefix = 'c'
WAX.write do
  start prefix, 'car'
  attr 'year', 2008
  namespace prefix, 'http://www.ociweb.com/cars'
  child prefix, 'model', 'Prius'
end
<c:car year="2008"
  xmlns:c="http://www.ociweb.com/cars">
  <c:model>Prius</c:model>
</c:car>

Like attributes, namespaces must be specified before any content for their element is specified. If this rule is violated then a RuntimeError is raised.

Let's associate an XML Schema with the XML:

WAX.write do
  start 'car'
  attr 'year', 2008
  namespace '', 'http://www.ociweb.com/cars', 'car.xsd'
  child 'model', 'Prius'
end
<car year="2008"
  xmlns="http://www.ociweb.com/cars"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xsi:schemaLocation="http://www.ociweb.com/cars car.xsd">
  <model>Prius</model>
</car>

Let's associate multiple XML Schemas with the XML:

WAX.write do
  start 'car'
  attr 'year', 2008
  namespace '', 'http://www.ociweb.com/cars', 'car.xsd'
  namespace 'm', 'http://www.ociweb.com/model', 'model.xsd'
  child 'm', 'model', 'Prius'
end
<car year="2008"
  xmlns="http://www.ociweb.com/cars"
  xmlns:m="http://www.ociweb.com/model"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xsi:schemaLocation="http://www.ociweb.com/cars car.xsd
    http://www.ociweb.com/model model.xsd">
  <m:model>Prius</m:model>
</car>

Let's associate a DTD with the XML:

WAX.write do
  dtd 'car.dtd'
  start 'car'
  attr 'year', 2008
  child 'model', 'Prius'
end
<!DOCTYPE car SYSTEM "car.dtd">
<car year="2008">
  <model>Prius</model>
</car>

Let's add and use entity definitions:

String url = 'http://www.ociweb.com/xml/';
WAX.write do
  entity_def 'oci', 'Object Computing, Inc.'
  external_entity_def 'moreData', url + 'moreData.xml'
  start 'root'
  text 'The author works at &oci; in St. Louis, Missouri.',
    true, false # turning escaping off for entity reference
  text '&moreData;', true, false
end
<!DOCTYPE root [
  <!ENTITY oci "Object Computing, Inc.">
  <!ENTITY moreData SYSTEM "http://www.ociweb.com/xml/moreData.xml">
]>
<root>
  The author works at &oci; in St. Louis, Missouri.
  &moreData;
</root>

A common usage pattern is to pass a WAX object to a method of model objects that use it to write their XML representation. A "chaining" style is employed here so that self refers to the object being operated upon rather than a WAX object. For example, a Car class could have the following method.

def to_xml(wax)
  wax.start('car').attr('year', @year).
    child('make', @make).
    child('model', @model).
    end!
end

An example of the XML this would produce follows:

<car year="2008">
  <make>Toyota</make>
  <model>Prius</model>
</car>

A Person class whose objects hold a reference to an Address object could have the following method.

def to_xml(wax)
  wax.start('person').attr('birthdate', @birthdate).child('name', @name)
  @address.to_xml(wax)
  wax.end!
end

The Address class could have the following method.

def to_xml(wax)
  wax.start('address').
    child('street', @street).
    child('city', @city).
    child('state', @state).
    child('zip', @zip).
    end!
end

An example of the XML this would produce follows:

<person birthdate="4/16/1961">
  <name>R. Mark Volkmann</name>
  <address>
    <street>123 Some Street</street>
    <city>Some City</city>
    <state>MO</state>
    <zip>12345</zip>
  </address>
</person>
    

Copyright © 2008 Object Computing, Inc. All rights reserved.